/****************************************************************************/ /* */ /* GADF.h */ /* */ /****************************************************************************/ /****************************************************************************/ /* This is a C language header file that defines the following routines for */ /* reading data from a GADF-format data file into memory and writing data */ /* from memory into a GADF-format file. The description of the GADF format */ /* is given in the file GADF.doc in the EISCAT CD. */ /* */ /* ------------------- Read data from a GADF-format file -------------- */ /* */ /* long ReadGADF(char *FileName, NetworkPtr Network, char *StartTimeStr, */ /* char *EndTimeStr, char *StationList) */ /* FileName Name of the GADF-file containing the data. */ /* If FileName is nil or zero length then standard */ /* input is used. */ /* Network Structure into which the data is read. */ /* Network_struct is defined in file MagnData.h. */ /* StartTimeStr String defining the first time to be read from the */ /* file (String delimited with '\0'). */ /* String format : YYYYMMDDHH. If HH is missing then */ /* 00 is assumed. If StartTimeStr is nil or zero */ /* length then start of file is assumed. */ /* EndTimeStr String defining the time not to be read anymore */ /* Format as before YYYYMMDDHH. If nil or zero */ /* length then data is read until end of file. */ /* StationList List of stations included in the data. The stations */ /* must be specified with three letter codes (e.g.SOR) */ /* and must be separeted with a space in the list */ /* (e.g. 'SOR MAS KEV'). If nil or zero length then */ /* all stations in the file are included. */ /* */ /* The function result indicates how successfull the file reading was: */ /* 0: OK : File read successfully */ /* 1: FileError : Failed to read the given file */ /* 2: OutOfMemory : Memory allocation failed during reading */ /* 3: FileFormatError : Data file is not a GADF file */ /* */ /* */ /* ------------------ Write data into a GADF-format file --------------- */ /* */ /* long WriteGADF(char *FileName, NetworkPtr Network, char *StartTimeStr, */ /* char *EndTimeStr, char *StationList) */ /* FileName Name of data file. If NULL or zero length then */ /* stdout is used. */ /* Network Pointer to the Network structure whose data is */ /* written into the data file. */ /* StartTimeStr Start date string YYYYMMDDHHMM. If NULL then same as*/ /* the time of the first record of the first station */ /* in the Network. */ /* EndTimeStr End date string YYYYMMDDHHMM. This record is NOT */ /* included anymore. If NULL then same as the EndTime */ /* of the first station in the Network. */ /* StationList String containing the 3-letter ID's of the stations */ /* to be included. If NULL or 0-length then all the */ /* stations will be written. The stations must be */ /* separated by a space in the list (e.g. 'SOR KEV'). */ /* */ /* The function result indicates how successfull the file writing was: */ /* 0: OK : Data written successfully */ /* 1: FileError : Failed to create the given file */ /* */ /* ----------------------------------------------------------------------- */ /* */ /* NOTE: These routines are intended to be used only in dealing with */ /* EISCAT or IMAGE magnetometer network data files in GADF-format. */ /* The routines defined here make assumptions about the data */ /* content. The routines might work also with other than EISCAT or */ /* IMAGE data files but this is not guaranteed. */ /* */ /****************************************************************************/ /****************************************************************************/ /* 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.06 13.02.2020 */ /****************************************************************************/ /****************************************************************************/ /* Version history: */ /* */ /* 1.06 13.02.2020 Date strings must be YYYYMMDD (four digits for year) */ /* Replaced StrToSecs -> StrToSecsC and */ /* SecsToStr -> SecsToStrC. */ /* 1.05 22.08.2001 */ /* - Added a command which checks the validness of the ASCII header. */ /* If there are non-ascii characters then ReadGADF routine stops and */ /* returns a file error. */ /* 1.04 28.11.2000 */ /* - Fixed a bug where no data was written if there were less than 180 */ /* data points in the station data record. */ /* 1.03 17.12.1999 */ /* - Fixed a bug in reading baseline values from a GADF-file. */ /* MissingValue was defined in MagnData.h as 9999999 while */ /* Missing baseline value in GADF is 999999. */ /* 1.02 27.07.1996 */ /* - Fixed a bug where WriteGADF crashed is there is no data in the */ /* Network-structure */ /* 1.01 15.12.1995 */ /* - Added missing GADF baseline manipulation. If baseline in GADF */ /* file is 999999 then 0 is substituted for the baseline value. */ /* - Added manipulation of the E-component. Now E is read into the */ /* D-field (= Y-field). */ /* - Fixed a bug which resulted in wrong field values if the scale */ /* factor was less than one (e.g. 1/2). This bug did not occur with */ /* the EISCAT CD-ROM. */ /* */ /* 1.0 2.2.1995 First official release */ /****************************************************************************/ #include #include #include /*--------------------------------------------------------------------------*/ /* Define the offsets of various fields from the start of the GADF block */ /* See the definition of GADF record for the explanation of various fields. */ /*--------------------------------------------------------------------------*/ #define GADF_RecLength 0 #define GADF_BinLength 2 #define GADF_ASCIILength 4 #define GADF_StationNbr 6 #define GADF_SampleStep 8 #define GADF_SampleCount 10 #define GADF_RefLevel 12 #define GADF_Uncertainty 14 #define GADF_Temperature 16 #define GADF_FilterBreak 18 #define GADF_FilterSlope 20 #define GADF_Reserved 22 #define GADF_RecFlag 24 #define GADF_Scale 25 #define GADF_Source 26 #define GADF_InstrNbr 27 #define GADF_ExtElemCode 28 #define GADF_DataType 29 #define GADF_BaseLineInfo 30 #define GADF_CodeRefLevel 31 #define GADF_StationCode 32 #define GADF_Component 35 #define GADF_PolarDist 36 #define GADF_Longitude 42 #define GADF_InvColatitude 48 #define GADF_DateTime 54 #define GADF_Baseline 66 #define GADF_Data 72 #define GADF_Missing 999999 typedef char *GADFptr; /*--------------------------------------------------------------------------*/ /* Function prototypes */ /*--------------------------------------------------------------------------*/ static long CheckASCIIHeader(GADFptr GADF); static long Get6Digits(char *p); static double Power(long base,long n); static long GetShort(char *p); Time_sec GetGADFTime(GADFptr GADF); long ReadGADFBlock(FILE *GADFfile, GADFptr GADF); static void SetStationParamsGADF(StationPtr Station,GADFptr GADF); static void GetGADFData(StationPtr Station,GADFptr GADF); long ReadGADF(char *FileName, NetworkPtr Network, char *StartTimeStr, char *EndTimeStr, char *StationList); static void SetShort(char *p,long value); static void FillConstantData(GADFptr GADF); static void FillStationInfo(GADFptr GADF,StationPtr Station); static void FillGADFBlock(GADFptr GADF,StationPtr Station, Time_sec T,char Comp); void WriteGADFblock(FILE *GADFfile,GADFptr GADF); long WriteGADF(char *FileName,NetworkPtr Network,char *StartTimeStr, char *EndTimeStr,char *StationList); /*==========================================================================*/ /* Routines for reading GADF-format files */ /*==========================================================================*/ /*--------------------------------------------------------------------------*/ /* Check that all the characters in the ASCII header are valid. */ /*--------------------------------------------------------------------------*/ static long CheckASCIIHeader(GADFptr GADF) { char *p; long i; p = GADF+GADF_StationCode; for (i=0;i<4;i++) { if ((*p < 'A') || (*p > 'Z')) return (1); p++; } p = GADF+GADF_PolarDist; for (i=0;i<18;i++) { if (((*p < '0') || (*p > '9')) && (*p != ' ')) return (1); p++; } p = GADF+GADF_DateTime; /* For some reason the leading zero in day number is converted into space ??? */ for (i=0;i<12;i++) { if (((*p < '0') || (*p > '9')) && (i != 4)) return (1); p++; } p = GADF+GADF_Baseline; for (i=0;i<6;i++) { if (((*p < '0') || (*p > '9')) && (*p != ' ') && (*p != '-')) return (1); p++; } return (0); } /*--------------------------------------------------------------------------*/ /* Convert a six digit character string into long variable. This routine */ /* works if there are leading zeros or spaces. */ /*--------------------------------------------------------------------------*/ static long Get6Digits(char *p) { long value = 0; long i; for (i=0;i<6;i++) { if (*p != ' ') value = 10*value+(*p-0x30); p++; } return value; } /*--------------------------------------------------------------------------*/ /* Compute the power function: base^n, where n is negative or positive. */ /*--------------------------------------------------------------------------*/ static double Power(long base,long n) { long i; if (n == 0) return 1.0; if (n > 0) { for (i=1;n>0;--n) i *= base; return (double) i; } for (i=1;n<0;++n) i *= base; return 1.0/i; } /*--------------------------------------------------------------------------*/ /* Get a two-byte binary number. The order of the bytes is : High-Low */ /* We cannot read the binaries with (short) p, where p is defined as */ /* (short) *p, since some processors use low-high byte ordering. In the */ /* GADF format the ordering is defined as high-low. We could check the */ /* type of the processor and then swap the bytes if necessary but that */ /* wouldn't be any simpler. */ /*--------------------------------------------------------------------------*/ static long GetShort(char *p) { register long high,low; high = (signed char) (*p++); low = *p; return((high << 8) | (0x000000FF & low)); } /*--------------------------------------------------------------------------*/ /* Get the start time in seconds of a 180-point data block. In a GADF */ /* data block the date format is YYMMDDHHMMSS. */ /*--------------------------------------------------------------------------*/ Time_sec GetGADFTime(GADFptr GADF) { return (StrToSecsYY(GADF+GADF_DateTime,12)); } /*--------------------------------------------------------------------------*/ /* Read one 432 character record from the GADF-format file into GADF block. */ /* Function result is 1 if reading was successful otherwise 0 is returned. */ /*--------------------------------------------------------------------------*/ long ReadGADFBlock(FILE *GADFfile, GADFptr GADF) { return (fread(GADF,432,1,GADFfile)); } /*--------------------------------------------------------------------------*/ /* Fill some fields in the Station_struct by copying them from the GADF */ /* block. AddNewStation procedure in the MagnData.h file will set other */ /* station parameters. */ /*--------------------------------------------------------------------------*/ static void SetStationParamsGADF(StationPtr Station,GADFptr GADF) { /* --- Set the three letter station ID --- */ strncpy(Station->StationID,GADF+GADF_StationCode,3); Station->StationID[3] = '\0'; /* --- Set the coordinates of the station, unit = 0.01 degrees --- */ Station->Longitude = Get6Digits(GADF+GADF_Longitude)/10; Station->Latitude = 9000-Get6Digits(GADF+GADF_PolarDist)/10; /* --- Set StartTime and TimeStep, GetGADFData-routine sets EndTime --- */ Station->StartTime = GetGADFTime(GADF); Station->TimeStep = GetShort(GADF+GADF_SampleStep); } /*--------------------------------------------------------------------------*/ /* Copy data from 432 character GADF block into proper OneDayBlock in the */ /* Station structure. */ /*--------------------------------------------------------------------------*/ static void GetGADFData(StationPtr Station,GADFptr GADF) { OneDayPtr p; long *DataPtr; char *q; register long i,FieldValue,Baseline; double Scale; long ScaleParam,Count,Temperature; char Component; /* --- Find the OneDayBlock which has room for new data --- */ Component = *(GADF+GADF_Component); p = Station->FirstDay; do { switch (Component) { case 'H' : case 'X' : Count = p->XCount; break; case 'D' : case 'Y' : case 'E' : Count = p->YCount; break; case 'Z' : Count = p->ZCount; break; } if (Count < 86400L/(Station->TimeStep)) break; /* still room */ p=p->NextDay; /* day full was full, check the next one */ } while (1); /* --- Set the component markers in the station record --- */ switch (Component) { case 'H' : Station->Components[0] = 'H'; break; case 'X' : Station->Components[0] = 'X'; break; case 'D' : Station->Components[1] = 'D'; break; case 'Y' : Station->Components[1] = 'Y'; break; case 'E' : Station->Components[1] = 'D'; break; case 'Z' : Station->Components[2] = 'Z'; break; } /* --- Get the temperature value --- */ if ((Component == 'X') || (Component == 'H')) { Temperature = GetShort(GADF+GADF_Temperature); DataPtr = (p->T)+(p->TCount); if ((Temperature == 0) || (Temperature == 0x7FFF)) *DataPtr++ = MissingValue; else *DataPtr++ = Temperature; p->TCount++; } /* --- Get the baseline and scalefactor for this block ---- */ /* Because we use 0.1 nT accuracy in the field values we */ /* multiply the scale factor by 10. (see GADF.DOC) */ Baseline = Get6Digits(GADF+GADF_Baseline); if (Baseline == GADF_Missing) Baseline = 0; else Baseline = 10*Baseline; /* Unit = 0.1 nT */ ScaleParam = (long) (*(GADF+GADF_Scale)); if (ScaleParam == 0) Scale = 10.0; else { if (ScaleParam <= 8) Scale = 10*Power(2,3-ScaleParam); else Scale = Power(10,11-ScaleParam); } /* --- Get the 180 datapoints for the particular component --- */ switch (Component) { case 'H' : case 'X' : DataPtr = (p->X)+(p->XCount); break; case 'D' : case 'E' : case 'Y' : DataPtr = (p->Y)+(p->YCount); break; case 'Z' : DataPtr = (p->Z)+(p->ZCount); break; } q = GADF+GADF_Data; for (i=0;i<180;i++) { FieldValue = GetShort(q); if (FieldValue == 0x7FFF) *DataPtr++ = MissingValue; else *DataPtr++ = (long) (Scale*FieldValue)+Baseline; q += 2; } /* --- Update counters --- */ switch (Component) { case 'H' : case 'X' : p->XCount += 180; break; case 'D' : case 'E' : case 'Y' : p->YCount += 180; break; case 'Z' : p->ZCount += 180; break; } /* --- Set the end time --- */ Station->EndTime = GetGADFTime(GADF)+180*Station->TimeStep; } /*--------------------------------------------------------------------------*/ /* Here is the routine for reading GADF-format data file into memory. */ /* The data is read into a Network structure (see MagnData.h for details). */ /* See the comments at the beginning of this file for more details about */ /* the parameters for this routine. */ /* */ /* The rounite works by reading the data file one block (432 bytes) at a */ /* time and adds that data in the particular stations data block. First */ /* for each new station that is encountered space for one day is allocated.*/ /* If the day becomes full a new one day block is allocated. At the end of */ /* the routine all one day blocks are combined into a single data block. */ /*--------------------------------------------------------------------------*/ long ReadGADF(char *FileName, NetworkPtr Network, char *StartTimeStr, char *EndTimeStr, char *StationList) { FILE *GADFfile; /* The data file to be processed */ char GADF[432]; /* This is one GADF block */ Time_sec CurrTime; /* Time of the current data block */ Time_sec StartTime; /* Time of first record to be read */ Time_sec EndTime; /* Time of record not read anymore */ StationPtr Station; /* Pointer to the current station */ long SampleStep; /* Sampling rate */ InitNetwork(Network); /* Initialize the fields of Network */ /* --- Set the start and end times --- */ if ((StartTimeStr == NULL) || (StartTimeStr[0] == '\0')) StartTime = MIN_TIME; else StartTime = StrToSecsC(StartTimeStr,0); if ((EndTimeStr == NULL) || (EndTimeStr[0] == '\0')) EndTime = MAX_TIME-(Time_sec)86400; else EndTime = StrToSecsC(EndTimeStr,0); /* --- Try to open the file --- */ if ((FileName == NULL) || (FileName[0] == '\0')) GADFfile = stdin; else if ((GADFfile = fopen(FileName, "rb")) == NULL) return(FileError); /* --- Read data into one day blocks ---*/ while (ReadGADFBlock(GADFfile,GADF)) { /* Check that some fields at the beginning of the block are valid */ if (GetShort(GADF+GADF_RecLength) != 432) return(FileFormatError); if (CheckASCIIHeader(GADF) != 0) { fprintf(stderr,"### Corrupt block ! Station = %.3s Component = %c Date = %.12s\n", GADF+GADF_StationCode, GADF+GADF_Component, GADF+GADF_DateTime); return(FileError); } if ((CurrTime=GetGADFTime(GADF)) >= EndTime+(Time_sec)86400) break; if ((CurrTime >= StartTime) && (CurrTime < EndTime) && StationInList(GADF+GADF_StationCode,StationList)) { Station = FindStation(Network,GADF+GADF_StationCode); if (Station == NULL) { /* First occurrence of this station */ SampleStep = GetShort(GADF+GADF_SampleStep); Station = AddNewStation(Network,SampleStep,180*SampleStep); if (Station != NULL) SetStationParamsGADF(Station,GADF); else /* Unable to allocate memory for station data */ return(OutOfMemory); } if (OneDayFull(Station,GADF[GADF_Component])) { if (AddOneDay(Station)) return(OutOfMemory); /* Unable to allocate memory */ } GetGADFData(Station,GADF); } } fclose(GADFfile); /* --- Combine one day blocks into one large block ---*/ Station = Network->StationList; while (Station != NULL) { if (CombineData(Station) == OutOfMemory) return(OutOfMemory); Station = Station->Next; } return OK; } /*==========================================================================*/ /* Routines for writing GADF-format files */ /*==========================================================================*/ /*--------------------------------------------------------------------------*/ /* Set a two-byte binary number. The order of the bytes is : High-Low. */ /*--------------------------------------------------------------------------*/ static void SetShort(char *p,long value) { *p++ = (char)(value >> 8); *p = (char)(value); } /*--------------------------------------------------------------------------*/ /* Fill those fields in the GADF block that are always constant. */ /* This applies to EISCAT and IMAGE networks. In other cases these fields */ /* may change. */ /*--------------------------------------------------------------------------*/ static void FillConstantData(GADFptr GADF) { SetShort(GADF+GADF_RecLength,432); SetShort(GADF+GADF_BinLength,32); SetShort(GADF+GADF_ASCIILength,40); SetShort(GADF+GADF_SampleCount,180); SetShort(GADF+GADF_RefLevel,0x7FFF); SetShort(GADF+GADF_Uncertainty,0x7FFF); SetShort(GADF+GADF_FilterSlope,0x7FFF); SetShort(GADF+GADF_Reserved,0x7FFF); GADF[GADF_Source] = (char) 1; GADF[GADF_InstrNbr] = (char) 0; GADF[GADF_CodeRefLevel] = (char) 0; } /*--------------------------------------------------------------------------*/ /* Fill those fields in the GADF block that describe the station */ /*--------------------------------------------------------------------------*/ static void FillStationInfo(GADFptr GADF, StationPtr Station) { StationInfoPtr p; char DummyStr[10]; /* --- Write the internal station number --- */ p = FindStationInfo(Station->StationID); SetShort(GADF+GADF_StationNbr,p->GADF_ID); /* --- Write the three letter Station code --- */ memcpy(GADF+GADF_StationCode,Station->StationID,3); /* --- Write the coordinates of the station --- */ sprintf(DummyStr,"%6d",10*(9000-Station->Latitude)); /* Northpole dist. */ memcpy(GADF+GADF_PolarDist,DummyStr,6); sprintf(DummyStr,"%6d",10*Station->Longitude); /* Longitude */ memcpy(GADF+GADF_Longitude,DummyStr,6); memcpy(GADF+GADF_InvColatitude," 0",6); /* Invariant colatitude */ } /*--------------------------------------------------------------------------*/ /* Fill the data fields and those fields which have not yet been filled in */ /* in the GADF block. */ /*--------------------------------------------------------------------------*/ static void FillGADFBlock(GADFptr GADF,StationPtr Station, Time_sec T,char Comp) { long i,Max,Min,Baseline,Temperature,DataValue; char DummyStr[20]; char *q; Time_sec Time; /* --- Write the component character --- */ GADF[GADF_Component] = Comp; /* --- Write the sample interval --- */ SetShort(GADF+GADF_SampleStep,Station->TimeStep); /* --- Write date and time --- */ SecsToStrC(T,DummyStr); // YYYYMMDD if (DummyStr[6] == '0') DummyStr[6] = ' '; /* Change leading zero in day field into space ??? */ memcpy(GADF+GADF_DateTime,DummyStr+2,12); // Write YYMMDDHHMMSS /* ---------------- Write the scale factor -----------------*/ /* Here we always write scale factor 0.1 (ScaleParam = 11) */ /* This corresponds to 0.1 nT accuracy in field values */ /* which is the same as in IAGA-format data files. */ GADF[GADF_Scale] = (char) 11; /* --- Compute and write the baseline value for this block --- */ /* Try to use first the baselines that DMI has used for EISCAT */ /* stations. If they are not good compute new ones. */ switch (Comp) { case 'X' : Baseline = 10000; break; case 'Y' : Baseline = 0; break; case 'Z' : Baseline = 50000; break; default : Baseline = 0; /* for H and D */ } if ((Comp == 'Z') && (strncmp(Station->StationID,"KAU",3) == 0)) Baseline = 52000; /* Compute the maximum and minimum value of the field */ FindMaxMin(Station,Comp,T,180*Station->TimeStep,&Max,&Min); /* Compute new baseline value if there is overflow. */ /* and round it to the nearest 1000 nT. */ Baseline *= 10; /* Use 0.1 nT as a unit */ if ((abs(Max-Baseline) > 0x7FFF) || (abs(Min-Baseline) > 0x7FFF)) Baseline = (((Max+Min)/2+5000)/10000)*10000; /* If there is still overflow give a notification. This should */ /* never happen. (Max - Min > 5000 nT). */ if ((abs(Max-Baseline) > 0x7FFF) || (abs(Min-Baseline) > 0x7FFF)) { fprintf(stderr,"### Overflow : variations too large: %s %c %s\n", Station->StationID,Comp,DummyStr); fprintf(stderr," Max value: %d\n",Max/10); fprintf(stderr," Min value: %d\n",Min/10); } if (Max == MissingValue) Baseline = 0; /* All values missing data */ sprintf(DummyStr,"%6d",Baseline/10); memcpy(GADF+GADF_Baseline,DummyStr,6); /* --- Write all 180 data values --- */ q = GADF+GADF_Data; Time = T; for (i=0;i<180;i++) { DataValue = GetDataValue(Station,Time,Comp); if (DataValue == MissingValue) SetShort(q,0x7FFF); else SetShort(q,DataValue-Baseline); q += 2; Time += Station->TimeStep; } /* --- Fill temperature and rest of the fields in GADF block --- */ /* If Max = Min then all field values are missing */ if (Max == Min) { SetShort(GADF+GADF_Temperature,0); SetShort(GADF+GADF_FilterBreak,0x7FFF); GADF[GADF_RecFlag] = (char) 1; GADF[GADF_ExtElemCode] = (char) 0; GADF[GADF_DataType] = (char) 0; GADF[GADF_BaseLineInfo] = (char) 0; } else { Temperature = GetDataValue(Station,T,'T'); if (Temperature == MissingValue) Temperature = 0x7FFF; SetShort(GADF+GADF_Temperature,Temperature); SetShort(GADF+GADF_FilterBreak,0); GADF[GADF_RecFlag] = (char) 0; GADF[GADF_ExtElemCode] = (char) 0; GADF[GADF_DataType] = (char) 1; GADF[GADF_BaseLineInfo] = (char) 0; switch (Comp) { case 'D' : i = 1; break; case 'H' : i = 3; break; case 'X' : i = 5; break; case 'Y' : i = 6; break; case 'Z' : i = 7; break; } GADF[GADF_ExtElemCode] = (char) i; } } /*--------------------------------------------------------------------------*/ /* Write a single 432 character GADF block into given file. */ /*--------------------------------------------------------------------------*/ void WriteGADFblock(FILE *GADFfile,GADFptr GADF) { fwrite(GADF,432,1,GADFfile); } /*--------------------------------------------------------------------------*/ /* Here is the routine for writing data into a GADF-format file. See the */ /* comments at the beginning of this file for more details about the */ /* parameters for this routine. */ /*--------------------------------------------------------------------------*/ long WriteGADF(char *FileName,NetworkPtr Network,char *StartTimeStr, char *EndTimeStr,char *StationList) { FILE *GADFfile; /* The data file to be processed */ char GADF[432]; /* This is one GADF block */ Time_sec CurrTime; /* Time of the current data block */ Time_sec StartTime; /* Time of first record to be read */ Time_sec EndTime; /* Time of record not read anymore */ StationPtr Station; /* Pointer to the current station */ long TimeStep; /* Time between successive data points */ long HourCount; /* Number of hours to be written */ long BlockCount; /* Number of blocks to be written */ long i,Comp; /* Dummy indices */ Time_sec Time2; /* Dummy time variable */ Time_struct TimeStruct; /* Dummy time variable */ char Component; /* Magnetic field component */ /* --- Check there is some data in the Network --- */ if (Network->StationList == NULL) return FAIL; /* --- Set the start and end times --- */ if ((StartTimeStr == NULL) || (*StartTimeStr == '\0')) StartTime = Network->StationList[0].StartTime; else StartTime = StrToSecsC(StartTimeStr,0); if ((EndTimeStr == NULL) || (*EndTimeStr == '\0')) EndTime = Network->StationList[0].EndTime; else EndTime = StrToSecsC(EndTimeStr,0); /* --- Try to create the file --- */ if ((FileName == NULL) || (*FileName == '\0')) GADFfile = stdout; else if ((GADFfile = fopen(FileName, "wb")) == NULL) return FileError; FillConstantData(GADF); /* Fill the fields independent of stations */ /* ------------------------- Write the data ----------------------------*/ /* Records in GADF file are in the order: Day,Station,Component,Hour. */ /* So first comes 24 hours for Day #1, Station #1, Component #1. */ /* Then 24 hours for Day #1, Station #1, Component #2 etc. */ /* If start hour is not midnight (00UT) then data for all components */ /* and for all stations till 24UT on the first day will be written. */ /* After that full days. */ /* ---------------------------------------------------------------------*/ TimeStep = Network->StationList[0].TimeStep; CurrTime = StartTime; while (CurrTime < EndTime) { /* --- Check first the number of hours in current day --- */ if ((EndTime-CurrTime) < (Time_sec) 86400) HourCount = (EndTime-CurrTime)/3600; /* Last day ?*/ else { SecsToTm(CurrTime,&TimeStruct); HourCount = 24-TimeStruct.tm_hour; } BlockCount = (((3600*HourCount)/TimeStep)+179)/180; /* 180 points per block */ /* --- Go through all stations, components and hours --- */ Station = Network->StationList; while (Station != NULL) { if (StationInList(Station->StationID,StationList)) { FillStationInfo(GADF,Station); for (Comp=0;Comp<3;Comp++) { Component = Station->Components[Comp]; Time2 = CurrTime; for (i=0;iNext; } CurrTime += 3600*HourCount; } fclose(GADFfile); return OK; }