/*************************************************************************************************** * * This is the C++ decoder for NQS ATMS data. 4 subrotines to handle different input data types. * * History: * Junye Chen Date: 11/22/2016 for N20 ATMS * Yong-Keun Lee Date: 03/31/2025 for NQS ATMS * ***************************************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "hdf5.h" using namespace std; //////////////////////////////////////////////////////////////////////////////////////////// // // some global variables // //////////////////////////////////////////////////////////////////////////////////////////// const int nchan_atms = 22; const int nchan_n18 = 20; const int min_sec = 10; float freq_nqs[nchan_atms] = { 23.800, 31.400, 50.300, 51.760, 52.800, 53.596, 54.400, 54.940, 55.500, 57.290, 57.290, 57.290, 57.290, 57.290, 57.290, 88.200, 165.500, 183.310, 183.310, 183.310,183.310, 183.310 } ; int polar_nqs[nchan_atms] = { 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3 }; float freq_n18[nchan_n18] = { 23.800, 31.400, 50.300, 52.799, 53.595, 54.400, 54.941, 55.499, 57.290, 57.290, 57.290, 57.290, 57.290, 57.290, 89.000, 89.000, 157.000, 183.311, 183.311, 190.311 } ; int polar_n18[nchan_n18] = { 2, 2, 2, 2, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 3, 3, 2 } ; const int NQC = 4; const int FILESIZE = 256; const int FILENUM = 8192; /** struct tm time1900; // 1900 time1900.tm_sec = 0; time1900.tm_min = 0; time1900.tm_hour = 0; time1900.tm_mday = 1; time1900.tm_mon = 0; time1900.tm_year = 0; time1900.tm_wday = 1; time1900.tm_yday = 0; time1900.tm_isdst = 0; time_t t1900 = mktime(&time1900); struct tm time1958; // 1958 time1958.tm_sec = 0; time1958.tm_min = 0; time1958.tm_hour = 0; time1958.tm_mday = 1; time1958.tm_mon = 0; time1958.tm_year = 58; time1958.tm_yday = 0; time1958.tm_isdst = 0; time_t t1958 = mktime(&time1958); // seconds of 1958 since 1900 unsigned long secsBefore1958 = (unsigned long)(difftime( t1958, t1900 )); */ unsigned long secsBefore1958 = 1830297600; // before 2012-06-30 23:59:60, LEAP_SECONDS=34 // after 2012-06-30 23:59:60, LEAP_SECONDS=35 // after 2015-06-30 23:59:60, LEAP_SECONDS=36 // after 2016-12-31 23:59:60, LEAP_SECONDS=37 const int LEAP_SECONDS = 36; class MeasurementTypeHeader { public: int nscan; int nchan; int nfov; int nqc; int nPosScan; float* freq; int* polar; // constructor MeasurementTypeHeader(int nscan_arg, int nchan_arg, int nfov_arg, int nqc_arg ) { nscan = nscan_arg; nchan = nchan_arg; nfov = nfov_arg; nqc = nqc_arg; freq = new float[nchan]; polar = new int[nchan]; }; // copy constructor MeasurementTypeHeader(const MeasurementTypeHeader& mh) { nscan = mh.nscan; nchan = mh.nchan; nfov = mh.nfov; nqc = mh.nqc; freq = new float[nchan]; polar = new int[nchan]; } // destructor ~MeasurementTypeHeader() { delete [] freq; delete [] polar; freq = NULL; polar = NULL; }; }; class MeasurementType { public: int nchan ; int nfov ; int nqc ; int node ; int jday ; int year ; int secs ; float* lat ; float* lon ; float* angle ; float* relAziAngle ; float* solZenAngle ; float** tb ; int* qc ; // constructor MeasurementType(int nch, int nfv, int nc) { nchan = nch; nfov = nfv; nqc = nc; lat = new float[nfov]; lon = new float[nfov]; angle = new float[nfov]; relAziAngle = new float[nfov]; solZenAngle = new float[nfov]; qc = new int[nqc]; tb = new float *[nfov]; for(int i = 0; i 0 ) { for(int iqc=0; iqc> 24) | (((x) & 0x00ff0000) >> 8) | ( ((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) ; return y; } int cal2jday(int year, int month, int day ) { if ( day > 31 || day < 1 || month > 12 || month < 1 ) return -1; int JulianDate1[12] = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 } ; int JulianDate2[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 } ; int leap = 0; if ( ( year % 4 == 0 && year % 100 != 0 ) || year % 400 == 0 ) leap = 1; int jday; if ( leap == 1 ) jday = JulianDate1[month-1] + day ; else jday = JulianDate2[month-1] + day ; return jday; } /*--------------------------------------------------------------------------*/ /* This routine converts a date given in seconds into years, months, days, */ /* hours, minutes and seconds which are fields in tm struct. The zero */ /* point of the date is set to 1900 Jan 1, at 00:00. This routine will work */ /* only between the years 1900 to 2040. The algorithm is from the book: */ /* Jean Meeus, Astronomical Algorithms, p 59-66. */ /*--------------------------------------------------------------------------*/ void seconds2tm(unsigned long Secs, struct tm *tp) { long Seconds; long alfa,B,C,D,E; long DayNbr; Seconds = ((unsigned long) Secs) % ((unsigned long) 86400); DayNbr = ((unsigned long) Secs) / ((unsigned long) 86400); tp->tm_hour = (int)(Seconds/3600); tp->tm_min = (int)((Seconds % 3600)/60); tp->tm_sec = (int)(Seconds % 60); DayNbr += 2415021; /* 1900, Jan 1, 00:00 is Julian day 2415020.5 */ alfa = (long)((DayNbr-1867216.25)/36524.25); B = DayNbr+alfa-alfa/4+1525; C = (long)((B-122.1)/365.25); D = (long)(365.25*C); E = (long)((B-D)/30.6001); tp->tm_mday = B-D-(long)(30.6001*E); tp->tm_mon = (E<14) ? E-2 : E-14; tp->tm_year = (tp->tm_mon > 1) ? C-6616 : C-6615; tp->tm_yday = cal2jday(tp->tm_year, tp->tm_mon+1, tp->tm_mday) - 1 ; tp->tm_isdst = 0; } //////////////////////////////////////////////////////////////////////////////////////////// // // 4 subroutines to read raw data // //////////////////////////////////////////////////////////////////////////////////////////// /*************************************************************************************************** * * The subroutine to read TDR data * ***************************************************************************************************/ int rdr2tdr_nqs_atms_TDR(char *file_RDR,char* file_GEO,char *file_OUT) { hid_t dsetr_id; hid_t space_id; hid_t type_id; H5T_class_t class_id; int storage_size; hssize_t points; int size_bytes; int status; int index; //////////////////////////////////////////////////////////////////////////////////////////// // // GATMO file ( contains meta data, lat/lon/zenith angle/time, etc ) // //////////////////////////////////////////////////////////////////////////////////////////// hid_t file_id = H5Fopen(file_GEO, H5F_ACC_RDONLY, H5P_DEFAULT); hid_t root_id = H5Gopen1(file_id, "/"); hid_t all_data_id = H5Gopen1(root_id, "All_Data"); hid_t gran_id = H5Gopen1(all_data_id, "ATMS-SDR-GEO_All"); //////////////////////////////////////////////////////////////////////////////////////////// // Latitude 32-bit floating-point, 12 row-scan x 96 column-nfov //////////////////////////////////////////////////////////////////////////////////////////// dsetr_id = H5Dopen1(gran_id, "Latitude"); // get space id for antenna temperature space_id = H5Dget_space( dsetr_id ); // data type id type_id = H5Dget_type( dsetr_id ); // number of dimensions int ndims = H5Sget_simple_extent_ndims(space_id); // each dimension size hsize_t *dims = new hsize_t[ndims]; hsize_t *maxdims = new hsize_t[ndims]; status = H5Sget_simple_extent_dims(space_id, dims, maxdims ); int NSCAN = dims[0]; int NFOV = dims[1]; points = H5Sget_simple_extent_npoints(space_id); size_bytes = H5Tget_size(type_id); storage_size = points*size_bytes; float *out_Latitude = new float[storage_size/4]; status = H5Dread(dsetr_id, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, out_Latitude); // row major array, // offset = row*NUMCOLS + column float lats[NSCAN][NFOV]; for( int iscan=0; iscan0) { cout << "contms: " << contms/NCHAN/NFOV << file_RDR <<"\n"; } delete [] out_AntennaTemperature; out_AntennaTemperature = NULL; H5Dclose(dsetr_id); //////////////////////////////////////////////////////////////////////////////////////////////////// // BeamTime 64-bit integer, 12 scan x 96 fov //////////////////////////////////////////////////////////////////////////////////////////////////// dsetr_id = H5Dopen1(gran_id, "BeamTime"); points = H5Sget_simple_extent_npoints(space_id); size_bytes = H5Tget_size(type_id); storage_size = points*size_bytes; long long* out_BeamTime = new long long[storage_size/8]; status = H5Dread(dsetr_id, H5T_NATIVE_LLONG, H5S_ALL, H5S_ALL, H5P_DEFAULT, out_BeamTime); long long beamTime[NSCAN][NFOV]; //int sec_diff = 378691200 ; // time difference in seconds between 1970 and 1958 UTC for(int iscan=0; iscan= lats[0][0] ) node = 0; else node = 1; MeasurementType ms(NCHAN,NFOV,NQC); for(int iscan=0; iscan= 1 ) { if ( lats[iscan][0] > lats[iscan-1][0] ) node = 0; else node = 1; } ms.node = node; // date/time information unsigned long secsAfter1958 = (unsigned long)( scanStartTime[iscan] * 0.000001 ); // micro seconds into seconds //unsigned long seconds = secsBefore1958 + secsAfter1958 - LEAP_SECONDS; unsigned long seconds = 0L; if( secsAfter1958 < 10 ) { // missing value seconds = 9; } else if( secsAfter1958 < 1719792035 ) { // 1719792035 ---> 2012/07/01 00:00:00 seconds = secsBefore1958 + secsAfter1958 - 34; } else if ( secsAfter1958 < 1814400036 ) { // 1814400036 ---> 2015/07/01 00:00:00 seconds = secsBefore1958 + secsAfter1958 - 35; } else if ( secsAfter1958 < 1861920037 ) { // 1861920037 ---> 2017/01/01 00:00:00 seconds = secsBefore1958 + secsAfter1958 - 36; } else { seconds = secsBefore1958 + secsAfter1958 - 37; } // more branches are needed in the future when leap second gets adjusted again. struct tm time_str; struct tm *tp = &time_str; if (seconds < min_sec ) { ms.year = -999; ms.jday = -999; ms.secs = -999; } else { seconds2tm( seconds, tp ); ms.year = tp->tm_year + 1900; ms.jday = tp->tm_yday + 1; ms.secs = ( tp->tm_hour * 3600 + tp->tm_min * 60 + tp->tm_sec ) * 1000 ; // time in milli-seconds since the start of day } // lat/lon/angle/relAziAngle/solZenAngle for(int ifov=0; ifov 0 ) ms.angle[ifov] = -1.0 * ms.angle[ifov]; // 1-48 to negative values ms.relAziAngle[ifov] = sensorAzimuthAngle[iscan][ifov]; ms.solZenAngle[ifov] = solarZenithAngle[iscan][ifov]; } // tb for(int ifov=0;ifov 0 ) { // ms.qc[0] = 1; // // cout << "QF19 L1070" << iscan << file_RDR << "\n"; // } //liusy. //comments out QF1 in GEO temporarilly liusy // if( QF1_ATMSSDRGEO[iscan] != 0 ) { // ms.qc[0] = 1; // // cout << QF1_ATMSSDRGEO[iscan] << "QF1_ATMSSDRGEO L1074" << iscan << file_RDR << "\n"; // } //liusy. // write measurement content of this scan writeMeasurement( myFile, ms ); } myFile.close(); return 0; } /*************************************************************************************************** * * The subroutine to read MIT SDR proxy data * ***************************************************************************************************/ int rdr2tdr_nqs_atms_SDR_proxy(char *file_RDR, char *file_OUT) { hid_t dsetr_id; hid_t space_id; hid_t type_id; H5T_class_t class_id; int storage_size; hssize_t points; int size_bytes; int status; int index; int index2; //////////////////////////////////////////////////////////////////////////////////////////////// // // TATMS file ( contains antenna temperature ) // //////////////////////////////////////////////////////////////////////////////////////////////// hid_t file_id = H5Fopen(file_RDR, H5F_ACC_RDONLY, H5P_DEFAULT); hid_t root_id = H5Gopen1(file_id, "/"); hid_t all_data_id = H5Gopen1(root_id, "ATMSproxy"); //////////////////////////////////////////////////////////////////////////////////////////// // Latitude 32-bit floating-point, 2307 x 96 //////////////////////////////////////////////////////////////////////////////////////////// dsetr_id = H5Dopen1(all_data_id, "BeamLatitude_MIT"); // get space id for latitude space_id = H5Dget_space( dsetr_id ); // data type id type_id = H5Dget_type( dsetr_id ); // number of dimensions int ndims = H5Sget_simple_extent_ndims(space_id); // each dimension size hsize_t *dims = new hsize_t[ndims]; hsize_t *maxdims = new hsize_t[ndims]; status = H5Sget_simple_extent_dims(space_id, dims, maxdims ); int NSCAN = dims[0]; int NFOV = dims[1]; points = H5Sget_simple_extent_npoints(space_id); size_bytes = H5Tget_size(type_id); storage_size = points*size_bytes; float *out_Latitude = new float[storage_size/4]; status = H5Dread(dsetr_id, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, out_Latitude); float lats[NSCAN][NFOV]; for( int iscan=0; iscan= lats[0][46] ) node = 0; else node = 1; MeasurementType ms(NCHAN,NFOV,NQC); for(int iscan=0; iscan= 1 ) { if ( lats[iscan][46] > lats[iscan-1][46] ) node = 0; else node = 1; } ms.node = node; ms.year = int(scan_year[iscan]); ms.jday = int(scan_day_of_year[iscan]); ms.secs = int(scan_UTC[iscan]); // lat/lon/angle/relAziAngle/solZenAngle for(int ifov=0;ifov= lats[0][0] ) node = 0; else node = 1; MeasurementType ms(NCHAN,NFOV,NQC); for(int iscan=0; iscan= 1 ) { if ( lats[iscan][0] > lats[iscan-1][0] ) node = 0; else node = 1; } ms.node = node; // date/time information unsigned long secsAfter1958 = (unsigned long)( scanStartTime[iscan] * 0.000001 ); // micro seconds into seconds //unsigned long seconds = secsBefore1958 + secsAfter1958 - LEAP_SECONDS; unsigned long seconds = 0L; if( secsAfter1958 < 10 ) { // missing value seconds = 9; } else if( secsAfter1958 < 1719792035 ) { // 1719792035 ---> 2012/07/01 00:00:00 seconds = secsBefore1958 + secsAfter1958 - 34; } else if ( secsAfter1958 < 1814400036 ) { // 1814400036 ---> 2015/07/01 00:00:00 seconds = secsBefore1958 + secsAfter1958 - 35; } else if ( secsAfter1958 < 1861920037 ) { // 1861920037 ---> 2017/01/01 00:00:00 seconds = secsBefore1958 + secsAfter1958 - 36; } else { seconds = secsBefore1958 + secsAfter1958 - 37; } // more branches are needed in the future when leap second gets adjusted again. struct tm time_str; struct tm *tp = &time_str; if (seconds < min_sec ) { ms.year = -999; ms.jday = -999; ms.secs = -999; } else { seconds2tm( seconds, tp ); ms.year = tp->tm_year + 1900; ms.jday = tp->tm_yday + 1; ms.secs = ( tp->tm_hour * 3600 + tp->tm_min * 60 + tp->tm_sec ) * 1000 ; // time in milli-seconds since the start of day } // lat/lon/angle/relAziAngle/solZenAngle for(int ifov=0;ifov 0 ) ms.angle[ifov] = -1.0 * ms.angle[ifov]; // 1-48 to negative values ms.relAziAngle[ifov] = sensorAzimuthAngle[iscan][ifov]; ms.solZenAngle[ifov] = solarZenithAngle[iscan][ifov]; } // tb for(int ifov=0;ifov 0 ) ms.qc[0] = 1; if( QF1_ATMSSDRGEO[iscan] != 0 ) ms.qc[0] = 1; // write measurement content writeMeasurement( myFile, ms ); } myFile.close(); //////////////////////////////////////////////////////////////////////////////////////////////// // // Output NEDT file // //////////////////////////////////////////////////////////////////////////////////////////////// //float NEdTWarm[NSCAN][NCHAN]; float nedts[NCHAN]; for(int ichan=0; ichan 0 ) nedts[ichan] += NEdTWarm[iscan][ichan] ; } } for(int ichan=0; ichan= lats[0][0] ) node = 0; else node = 1; MeasurementType ms(NCHAN,NFOV,NQC); for(int iscan=0; iscan= 1 ) { if ( lats[iscan][0] > lats[iscan-1][0] ) node = 0; else node = 1; } ms.node = node; // date/time information unsigned long secsAfter1958 = (unsigned long)( scanStartTime[iscan] * 0.000001 ); // micro seconds into seconds //unsigned long seconds = secsBefore1958 + secsAfter1958 - LEAP_SECONDS ; unsigned long seconds = 0L; if( secsAfter1958 < 10 ) { // missing value seconds = 9; } else if( secsAfter1958 < 1719792035 ) { // 1719792035 ---> 2012/07/01 00:00:00 seconds = secsBefore1958 + secsAfter1958 - 34; } else if ( secsAfter1958 < 1814400036 ) { // 1814400036 ---> 2015/07/01 00:00:00 seconds = secsBefore1958 + secsAfter1958 - 35; } else if ( secsAfter1958 < 1861920037 ) { // 1861920037 ---> 2017/01/01 00:00:00 seconds = secsBefore1958 + secsAfter1958 - 36; } else { seconds = secsBefore1958 + secsAfter1958 - 37; } // more branches are needed in the future when leap second gets adjusted again. struct tm time_str; struct tm *tp = &time_str; if (seconds < min_sec ) { ms.year = -999; ms.jday = -999; ms.secs = -999; } else { seconds2tm( seconds, tp ); ms.year = tp->tm_year + 1900; ms.jday = tp->tm_yday + 1; ms.secs = ( tp->tm_hour * 3600 + tp->tm_min * 60 + tp->tm_sec ) * 1000 ; // time in milli-seconds since the start of day } // lat/lon/angle/relAziAngle/solZenAngle for(int ifov=0;ifov