/****************************************************************************/ /* */ /* Find_missing.c */ /* */ /****************************************************************************/ /****************************************************************************/ /* This program reads IAGA, GADF, Dump or WDC format data files containing */ /* magnetometer data, searches for missing data values and writes the */ /* missing periods into standard output */ /* */ /* Usage: */ /* Find_missing [-f] [-v] File1 ... FileN */ /* [-v ] Verbose. Write information about file content. */ /* [-f Dataformat] Format of the data file. Possible values for */ /* Dataformat are IAGA (default),GADF,Dump or WDC. */ /* File* Names of data files. */ /* */ /****************************************************************************/ /****************************************************************************/ /* Lasse Hakkinen */ /* Finnish Meteorological Institute */ /* Department of Geophysics */ /* P.O.Box 503 */ /* FIN-00101, Helsinki, Finland */ /* e-mail: Lasse.Hakkinen@fmi.fi */ /* phone : (+358)-9-19294634 */ /* fax : (+358)-9-19294603 */ /* */ /* version 1.02 02.07.1999 */ /****************************************************************************/ /****************************************************************************/ /* Version history: */ /* */ /* 1.03 06.06.2016 Changed output so that times of first and last missing */ /* data points are displayed. Previously first missing and */ /* first existing data points were displayed. */ /* 1.02 02.07.1999 Fixed a Y2K bug in NewTime.h file which resulted in */ /* incorrect year in date strings if year >= 2000. */ /* 1.01 21.10.1998 Accommodated to the changes in Dump.h (0.1 nT to */ /* 0.01 nT resolution). */ /* 1.0 20.01.1997 First official release */ /****************************************************************************/ #include #include #include #include "Usage.h" #include "MagnData.h" #include "IAGA.h" #include "GADF.h" #include "WDC.h" #include "Dump.h" char *version = "1.02"; char *date = "02.07.1999"; #define HeaderLineCount 4 #define UsageLineCount 6 char *HeaderText[HeaderLineCount] = { "**************************************************************************", "This program finds missing data records in magnetometer data files and ", "writes times of data gaps into standard output. ", "**************************************************************************", }; char *UsageText[UsageLineCount] = { " [-v] [-f] File1 ... FileN ", " [-v ] Verbose. Write information about data content. ", " If missing then only gaps are written. ", " [-f Dataformat] Format of the data file. Possible values for ", " Dataformat are IAGA (default),GADF,Dump or WDC. ", " File* Names of data files.", }; /*--------------------------------------------------------------------------*/ /* Define a data structure for storing information about each data gap. */ /*--------------------------------------------------------------------------*/ #define MaxGapCount 1000 struct Data_Gap { char Comp[4]; /* Components missing for this interval */ Time_sec StartTime; /* First missing data point */ Time_sec EndTime; /* Last missing data point */ }; typedef struct Data_Gap Data_Gap_struct; long GapCount; Data_Gap_struct GapTable[MaxGapCount]; /*--------------------------------------------------------------------------*/ /* Add the gap for given component and given times into the GapTable. */ /* First check if this gap already exists for some other component. If so */ /* then update the particular element in the GapTable otherwise add a new */ /* element to the GapTable. */ /*--------------------------------------------------------------------------*/ void AddGapToTable(char Component,Time_sec GapStart, Time_sec GapEnd) { long i = 0; /*** First check if this gap already exists in some other component ***/ while (i < GapCount) { if ((GapTable[i].StartTime == GapStart) && (GapTable[i].EndTime == GapEnd)) { /* Yes, we have it already */ GapTable[i].Comp[Component-'X'] = Component; return; } i++; } /*** We haven't recorded this gap, so add it to the GapTable ***/ GapTable[GapCount].StartTime = GapStart; GapTable[GapCount].EndTime = GapEnd; GapTable[GapCount].Comp[Component-'X'] = Component; GapCount++; } /*--------------------------------------------------------------------------*/ /* Exchange the i'th and j'th element of the GapTable. */ /*--------------------------------------------------------------------------*/ void Exchange(long i, long j) { char dummyStr[4]; Time_sec t1,t2; strcpy(dummyStr,GapTable[i].Comp); t1 = GapTable[i].StartTime; t2 = GapTable[i].EndTime; strcpy(GapTable[i].Comp,GapTable[j].Comp); GapTable[i].StartTime = GapTable[j].StartTime; GapTable[i].EndTime = GapTable[j].EndTime; strcpy(GapTable[j].Comp,dummyStr); GapTable[j].StartTime = t1; GapTable[j].EndTime = t2; } /*--------------------------------------------------------------------------*/ /* Put the elements of GapTable into temporal order according to StartTime.*/ /* Here we use a very simple algorithm for sorting the table. */ /*--------------------------------------------------------------------------*/ void TimeOrderGapTable() { long i,j; for (i=0;i GapTable[j].StartTime) Exchange(i,j); } /*--------------------------------------------------------------------------*/ /* Write the elements of GapTable into standard output. */ /*--------------------------------------------------------------------------*/ void WriteGapTable(StationPtr Station) { long i; char StartStr[20]; char EndStr[20]; Time_sec GapLength; long GapDays,GapHours,GapMins,GapSecs; for (i=0;iTimeStep, EndStr); GapLength = GapTable[i].EndTime - GapTable[i].StartTime; GapDays = GapLength/86400; GapHours = (GapLength % 86400)/3600; GapMins = (GapLength % 3600)/60; GapSecs = GapLength % 60; printf(" %s %s %.8s %s - %.8s %s ",Station->StationID, GapTable[i].Comp,StartStr,StartStr+8,EndStr,EndStr+8); if (GapDays > 0) printf("%02dd ",GapDays); else printf(" "); if (GapHours > 0) printf("%02dh ",GapHours); else printf(" "); if (GapMins > 0) printf("%02dm ",GapMins); else printf(" "); printf("%02ds\n",GapSecs); } } /*--------------------------------------------------------------------------*/ /* The main procedure */ /*--------------------------------------------------------------------------*/ int main(int argc, char *argv[]) { long params,i; long status = 0; long FileCount = 0; long FileNbr; char FileName[100]; Network_struct NETWORK; /* Structure containing the data */ /* for all stations. */ StationPtr Station; /* Pointer to the current station */ char FormatStr[10] = "IAGA"; /* Format of magnetometer data file */ char StartTimeStr[20]; char EndTimeStr[20]; Time_sec GapStart; Time_sec GapEnd; Time_sec T; char Comp; long Verbose = 0; /*==========================*/ /* Analyse the command line */ /*==========================*/ if (argc == 1) { /* No arguments, show the usage text */ PrintUsage(argv[0],0,HeaderLineCount,UsageLineCount); return OK; } for (params = 1; params < argc; params++) { if (*argv[params] != '-') { argv[FileCount++] = argv[params]; } else { switch (*(argv[params]+1)) { case 'f' : strcpy(FormatStr,argv[++params]); break; case 'v' : Verbose = 1; break; default : fprintf(stderr,"\n### %s: \"%s\" is not an option.\n\n", argv[0], argv[params]); PrintUsage(argv[0],1,HeaderLineCount,UsageLineCount); return FAIL; break; } } } /*=================================================*/ /* Check that all necessary parameters are defined */ /*=================================================*/ if (FileCount == 0) { PrintUsage(argv[0],1,HeaderLineCount,UsageLineCount); return FAIL; } /*=================================================*/ /* Go through all files listed in the command line */ /*=================================================*/ for (FileNbr = 0; FileNbr < FileCount; FileNbr++) { strcpy(FileName,argv[FileNbr]); /*======================================*/ /* Read data from data file into memory */ /*======================================*/ if (!strcmp(FormatStr,"IAGA")) { status = ReadIAGA(FileName,&NETWORK,NULL,NULL,NULL); } else if (!strcmp(FormatStr,"GADF")) { status = ReadGADF(FileName,&NETWORK,NULL,NULL,NULL); } else if (!strcmp(FormatStr,"Dump")) { status = ReadDump(FileName,&NETWORK,NULL,NULL,NULL); } else if (!strcmp(FormatStr,"WDC")) { status = ReadWDC(FileName,&NETWORK,NULL,NULL,NULL); } else { fprintf(stderr,"Illegal format type: %s\n",FormatStr); return FAIL; } if (status != 0) { if (status == FileError) fprintf(stderr,"### Error in opening data file "); if (status == OutOfMemory) fprintf(stderr,"### Out of memory while reading data file"); if (status == FileFormatError) fprintf(stderr,"### Wrong file format in input file "); fprintf(stderr,"%s\n",FileName); } if (!strcmp(FormatStr,"Dump")) /* This is not necessary but */ ChangeUnitsDOWN(&NETWORK); /* do it anyway */ /*======================================*/ /* Go through all stations in NETWORK */ /*======================================*/ Station = NETWORK.StationList; while(Station != NULL) { /*** Write station ID and data start and end times ***/ if (Verbose) { SecsToStrC(Station->StartTime,StartTimeStr); SecsToStrC(Station->EndTime,EndTimeStr); printf("%s %.8s %s - %.8s %s\n",Station->StationID, StartTimeStr,StartTimeStr+8,EndTimeStr,EndTimeStr+8); } /*** Find gaps in each component and store them into GapTable ***/ GapCount = 0; for (i = 0;i < MaxGapCount; i++) strcpy(GapTable[i].Comp," "); for (Comp='X';Comp <= 'Z';Comp++) { T = Station->StartTime; while (T < Station->EndTime) { if (FindGap(Station,Comp,T,&GapStart,&GapEnd)) { AddGapToTable(Comp,GapStart,GapEnd); if (GapCount == MaxGapCount) { fprintf(stderr,"### Too many gaps !!!!\n"); return 1; } } T = GapEnd; } } /*** Write GapTable into standard output ***/ TimeOrderGapTable(); WriteGapTable(Station); Station = Station->Next; } /* End of Station Loop */ FreeNetwork(&NETWORK); } /* End of File loop */ return OK; }