/****************************************************************************/ /* */ /* IAGA_time_shift.c */ /* */ /****************************************************************************/ /****************************************************************************/ /* This program fixes time errors in IAGA-format files by shifting blocks */ /* of data within the given file. The corrected data is then written into */ /* standard output. */ /* */ /* Usage: */ /* IAGA_time_shift -s YYYYMMDDHHMMSS -e YYYYMMDDHHMMSS -t TimeShift */ /* -d d_TimeShift -o StationID [-i] IAGAFile > NewIAGAFile */ /* */ /* -s YYYYMMDDHHMMSS Time of the first block to be shifted */ /* -e YYYYMMDDHHMMSS Time of the last block to be shifted. */ /* -t TimeShift Time shift in seconds. Positive if clock in the */ /* particular station shows smaller reading for */ /* some reference event. */ /* -d d_TimeShift Change of Time shift at the endpoint (-e) in */ /* seconds. Time shift is linearly interpolated */ /* from 'TimeShift' at startpoint to 'TimeShift' + */ /* 'd_TimeShift' at endpoint. */ /* -o StationID Three letter ID of the station. */ /* -i The gap which is created when data is shifted */ /* is filled with interpolated data values. If */ /* missing then the gap is filled with missing */ /* data markers. */ /* IAGAFile Name of IAGA-format file. */ /* NewIAGAFile Name of corrected IAGA-format file. */ /* */ /* Note: The size of the data file is not changed, the data is only shifted */ /* within the file. */ /* */ /****************************************************************************/ /****************************************************************************/ /* Lasse Hakkinen */ /* Finnish Meteorological Institute */ /* Geophysical Research Division */ /* P.O.Box 503 */ /* FIN-00101, Helsinki, Finland */ /* e-mail: Lasse.Hakkinen@fmi.fi */ /* phone : (+358)-9-19294634 */ /* fax : (+358)-9-19294603 */ /* */ /* version 1.04 13.02.2020 */ /****************************************************************************/ /****************************************************************************/ /* Version history: */ /* */ /* 1.04 13.02.2020 Date strings must be YYYYMMDD (four digits for year) */ /* Replaced StrToSecs -> StrToSecsC and */ /* SecsToStr -> SecsToStrC. */ /* 1.03 06.11.2015 Added -d option. */ /* 1.02 09.09.1999 Fixed a Y2K bug in NewTime.h file which resulted in */ /* incorrect year in date strings if year >= 2000. */ /* 1.01 15.01.1999 Added interpolation (-i) option. */ /* 1.0 26.02.1996 First official release */ /****************************************************************************/ #include #include #include #include "Usage.h" #include "MagnData.h" #include "IAGA.h" char *version = "1.04"; char *date = "13.02.2020"; #define HeaderLineCount 5 #define UsageLineCount 19 char *HeaderText[HeaderLineCount] = { "**************************************************************************", "This program fixes time errors in an IAGA format file by shifting selected", "blocks within the IAGA file by specified time shift. The size of the data ", "file is not changed, the data is only shifted within the file. ", "**************************************************************************", }; char *UsageText[UsageLineCount] = { " [-s] [-e] -t -d -o [-i] [<] IAGAFile > NewIAGAFile", " [-s YYYYMMDDHH] Time of the first record to be shifted. ", " If missing then start of file is assumed. ", " [-e YYYYMMDDHH] Time of the last record to be shifted. ", " If missing then end of file is assumed. ", " -t TimeShift Time shift in seconds. Positive if clock in the", " particular station shows smaller reading for ", " some reference event. ", " -d d_TimeShift Change of Time shift at the endpoint (-e) in ", " seconds. Time shift is linearly interpolated ", " from 'TimeShift' at startpoint to 'TimeShift' +", " 'd_TimeShift' at endpoint. ", " -o StationID Three letter ID of the station. ", " [-i] Shifting the data values creates a gap ", " Fill this gap by interpolating data values. ", " If missing then gap is filled with missing ", " data markers. ", " IAGAFile Name of IAGA-format file. ", " NewIAGAFile Name of extracted IAGA-format file. ", }; /*--------------------------------------------------------------------------*/ /* Replace field value at time T1 with that at time T0. */ /*--------------------------------------------------------------------------*/ void ReplaceValue(StationPtr s, Time_sec T0, Time_sec T1, char Comp) { long Value; /* GetDataValue and SetDataValue routines will take care that */ /* the times are within the limits of existing data points in */ /* the station data structure. */ Value = GetDataValue(s,T0,Comp); SetDataValue(s,T1,Comp,Value); } /*--------------------------------------------------------------------------*/ /* Fill block of memory with missing data */ /*--------------------------------------------------------------------------*/ void FillMissingData(StationPtr s, Time_sec T0, Time_sec T1, char Comp) { Time_sec T; for (T=T0; T<=T1; T += s->TimeStep) SetDataValue(s,T,Comp,MissingValue); } /*--------------------------------------------------------------------------*/ /* Move data for all components in memory to adjust for the time shift and */ /* fill the remaining blocks with missing data values or interpolate them. */ /* Here StartTime is the first data point to be shifted and EndTime is the */ /* last data point to be shifted. */ /*--------------------------------------------------------------------------*/ void MoveDataForward(StationPtr s,Time_sec StartTime,Time_sec EndTime, long TimeShift,long InterpolateFlag) { Time_sec T; /* Move data in memory. ReplaceValue-routine will check that */ /* times are within limits. */ for (T = EndTime - TimeShift; T >= StartTime; T -= s->TimeStep) { ReplaceValue(s,T,T+TimeShift,'X'); ReplaceValue(s,T,T+TimeShift,'Y'); ReplaceValue(s,T,T+TimeShift,'Z'); } for (T = EndTime - TimeShift; T >= StartTime; T -= s->TempStep) { ReplaceValue(s,T,T+TimeShift,'T'); ReplaceValue(s,T,T+TimeShift,'A'); } if (InterpolateFlag == 0) { FillMissingData(s,StartTime,StartTime+TimeShift - s->TimeStep,'X'); FillMissingData(s,StartTime,StartTime+TimeShift - s->TimeStep,'Y'); FillMissingData(s,StartTime,StartTime+TimeShift - s->TimeStep,'Z'); FillMissingData(s,StartTime,StartTime+TimeShift - s->TempStep,'T'); FillMissingData(s,StartTime,StartTime+TimeShift - s->TempStep,'A'); } else { InterpolateData(s,StartTime,StartTime+TimeShift - s->TimeStep,'X'); InterpolateData(s,StartTime,StartTime+TimeShift - s->TimeStep,'Y'); InterpolateData(s,StartTime,StartTime+TimeShift - s->TimeStep,'Z'); InterpolateData(s,StartTime,StartTime+TimeShift - s->TempStep,'T'); } } /*--------------------------------------------------------------------------*/ /* Move data backward in memory to adjust for the time shift and fill the */ /* remaining blocks with missing data values. Note that TimeShift here is */ /* positive, since the routine is called with '-TimeShift'. */ /*--------------------------------------------------------------------------*/ void MoveDataBackward(StationPtr s,Time_sec StartTime,Time_sec EndTime, long TimeShift,long InterpolateFlag) { Time_sec T; /* Move data in memory. ReplaceValue-routine will check that */ /* times are within limits. */ for (T = StartTime + TimeShift; T <= EndTime; T += s->TimeStep) { ReplaceValue(s,T,T-TimeShift,'X'); ReplaceValue(s,T,T-TimeShift,'Y'); ReplaceValue(s,T,T-TimeShift,'Z'); } for (T = StartTime + TimeShift; T <= EndTime; T += s->TempStep) { ReplaceValue(s,T,T-TimeShift,'T'); ReplaceValue(s,T,T-TimeShift,'A'); } if (InterpolateFlag == 0) { FillMissingData(s,EndTime-TimeShift+ s->TimeStep,EndTime,'X'); FillMissingData(s,EndTime-TimeShift+ s->TimeStep,EndTime,'Y'); FillMissingData(s,EndTime-TimeShift+ s->TimeStep,EndTime,'Z'); FillMissingData(s,EndTime-TimeShift+ s->TempStep,EndTime,'T'); FillMissingData(s,EndTime-TimeShift+ s->TempStep,EndTime,'A'); } else { InterpolateData(s,EndTime-TimeShift+ s->TimeStep,EndTime,'X'); InterpolateData(s,EndTime-TimeShift+ s->TimeStep,EndTime,'Y'); InterpolateData(s,EndTime-TimeShift+ s->TimeStep,EndTime,'Z'); InterpolateData(s,EndTime-TimeShift+ s->TempStep,EndTime,'T'); } } /*--------------------------------------------------------------------------*/ /* The main procedure */ /*--------------------------------------------------------------------------*/ int main(int argc, char *argv[]) { long params; long status = 0; long FileCount = 0; char FileName[100] = ""; /* Name of the original data file */ Time_sec StartTime = MIN_TIME; /* Time of first data block (secs) */ Time_sec EndTime = MAX_TIME; /* Time of last block to be moved */ char StationID[20] = "???"; /* List of stations in command line */ long TimeShift = 99999; /* Time shift in seconds */ long d_TimeShift = 0; /* Change of Time shift in seconds */ Network_struct IMAGE; /* Structure containing the data */ /* for all stations. */ StationPtr Station; /* Pointer to the corrected station */ long InterpolateFlag = 0; /* Interpolate data values or fill */ /* with missing data values (def) */ long count, Shift; Time_sec T0,T1,dT; long i; /*==========================*/ /* 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] != '-') { strcpy(FileName,argv[params]); FileCount++; } else { switch (*(argv[params]+1)) { case 's' : StartTime = StrToSecsC(argv[++params],0); break; case 'e' : EndTime = StrToSecsC(argv[++params],0); break; case 't' : TimeShift = atol(argv[++params]); break; case 'd' : d_TimeShift = atol(argv[++params]); break; case 'o' : strcpy(StationID,argv[++params]); break; case 'i' : InterpolateFlag = 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>1) || (TimeShift==99999) || (strcmp(StationID,"???")==0)) { PrintUsage(argv[0],1,HeaderLineCount,UsageLineCount); return FAIL; } /*====================================================*/ /* Read the data from an IAGA format file into memory */ /*====================================================*/ status = ReadIAGA(FileName,&IMAGE,NULL,NULL,NULL); if (status != 0) { if (status == FileError) fprintf(stderr,"Error in reading file %s\n",FileName); if (status == OutOfMemory) fprintf(stderr,"Out of memory while reading file %s\n",FileName); if (status == FileFormatError) fprintf(stderr,"%s is not an IAGA format file\n",FileName); return FAIL; } /*=======================================================*/ /* Check that the values of the parameters are resonable */ /*=======================================================*/ Station = FindStation(&IMAGE,StationID); if (Station == NULL) { fprintf(stderr,"Couldn't find station %s in %s\n",StationID,FileName); return FAIL; } if (StartTime > EndTime) { fprintf(stderr,"StartTime > EndTime !?\n"); return FAIL; } if ((StartTime != MIN_TIME) && (((StartTime-Station->StartTime) % Station->TimeStep) != 0)) { fprintf(stderr, "Illegal StartTime. There is such data point in the datafile\n"); return FAIL; } if ((EndTime != MAX_TIME) && (((EndTime-Station->StartTime) % Station->TimeStep) != 0)) { fprintf(stderr, "Illegal EndTime. There is no such data point in the datafile\n"); return FAIL; } if ((TimeShift % Station->TimeStep) != 0) { fprintf(stderr, "Illegal TimeShift. Must be multiple of datafile time step\n"); return FAIL; } if ((d_TimeShift % Station->TimeStep) != 0) { fprintf(stderr, "Illegal d_TimeShift. Must be multiple of datafile time step\n"); return FAIL; } /*======================================================*/ /* Move the data blocks in memory to fix the time error */ /*======================================================*/ if (StartTime == MIN_TIME) StartTime = Station->StartTime; if (EndTime == MAX_TIME) EndTime = Station->EndTime; // if (TimeShift > 0) // MoveDataForward(Station,StartTime,EndTime,TimeShift,InterpolateFlag); // else // MoveDataBackward(Station,StartTime,EndTime,-TimeShift,InterpolateFlag); count = abs(d_TimeShift)/Station->TimeStep + 1; dT = (EndTime - StartTime)/count; if ((TimeShift > 0) && (d_TimeShift >= 0)) { for (i=0; i < count; i++) { T0 = StartTime + i*dT + i*Station->TimeStep; Shift = (i == 0) ? TimeShift : Station->TimeStep; MoveDataForward(Station, T0, EndTime, Shift, InterpolateFlag); } } else if ((TimeShift < 0) && (d_TimeShift <= 0)) { for (i=0; i < count; i++) { T0 = StartTime + i*dT; Shift = (i == 0) ? -TimeShift : Station->TimeStep; MoveDataBackward(Station, T0, EndTime, Shift, InterpolateFlag); } } else fprintf(stderr, "TimeShift (-t) and d_TimeShift (-d) must both be either positive or negative.\n"); /*==========================================*/ /* Write the corrected file into stdout */ /*==========================================*/ WriteIAGA(NULL,&IMAGE,NULL,NULL,NULL); FreeNetwork(&IMAGE); return OK; }