TC_Error_Code TCDS_Ascii_Harmonic::LoadHarmonicData(IDX_entry *pIDX) { Station_Data *psd = NULL; // Look in the index first if(pIDX->pref_sta_data) return TC_NO_ERROR; //easy // Try the member array of "already-looked-at" master stations for(unsigned int i=0 ; i < m_msd_array.GetCount() ; i++) { psd = &m_msd_array.Item(i); // In the following comparison, it is allowed that the sub-station reference_name may be // a pre-subset of the master station name. // e.g IDX_refence_name: The Narrows midchannel New York // as found in HARMONIC.IDX // psd_station_name: The Narrows, Midchannel, New York Harbor, New York Current // as found in HARMONIC if( (!slackcmp(psd->station_name, pIDX->IDX_reference_name)) && (toupper(pIDX->IDX_type) == psd->station_type) ) { pIDX->pref_sta_data = psd; // save for later return TC_NO_ERROR; } } // OK, have to read and create from the raw file psd = NULL; // If reference station was recently sought, and not found, don't bother // if(!strcmp(pIDX->IDX_reference_name, plast_reference_not_found->mb_str())) if(m_last_reference_not_found.IsSameAs(wxString(pIDX->IDX_reference_name, wxConvUTF8))) return TC_MASTER_HARMONICS_NOT_FOUND; // Clear for this looking m_last_reference_not_found.Clear(); // Find and load appropriate constituents FILE *fp; char linrec[linelen]; fp = fopen (m_harmfile_name.mb_str(), "r"); while (read_next_line (fp, linrec, 1)) { nojunk (linrec); int curonly = 0; if (curonly) if (!strstr (linrec, "Current")) continue; // See the note above about station names // if(!strncmp(linrec, "Rivi", 4)) // int ggl = 4; if (slackcmp (linrec, pIDX->IDX_reference_name)) continue; // Got the right location, so load the data psd = new Station_Data; psd->amplitude = (double *)malloc(num_csts * sizeof(double)); psd->epoch = (double *)malloc(num_csts * sizeof(double)); psd->station_name = (char *)malloc(strlen(linrec) +1); char junk[80]; int a; strcpy (psd->station_name, linrec); // Establish Station Type wxString caplin(linrec, wxConvUTF8); caplin.MakeUpper(); if(caplin.Contains(_T("CURRENT"))) psd->station_type = 'C'; else psd->station_type = 'T'; /* Get meridian */ read_next_line (fp, linrec, 0); psd->meridian = hhmm2seconds (linrec); psd->zone_offset = 0; /* Get tzfile, if present */ if (sscanf (nojunk(linrec), "%s %s", junk, psd->tzfile) < 2) strcpy (psd->tzfile, "UTC0"); /* Get DATUM and units */ read_next_line (fp, linrec, 0); if (sscanf (nojunk(linrec), "%lf %s", &(psd->DATUM), psd->unit) < 2) strcpy (psd->unit, "unknown"); if ((a = findunit (psd->unit)) == -1) { // Nonsense.... // strcpy (psd->units_abbrv, psd->unit); // strcpy (psd->units_conv, known_units[a].name); } psd->have_BOGUS = (findunit(psd->unit) != -1) && (known_units[findunit(psd->unit)].type == BOGUS); int unit_c; if (psd->have_BOGUS) unit_c = findunit("knots"); else unit_c = findunit(psd->unit); if (unit_c != -1) { strcpy (psd->units_conv, known_units[unit_c].name); strcpy (psd->units_abbrv, known_units[unit_c].abbrv); } /* Get constituents */ double loca, loce; for (a=0; a<num_csts; a++) { read_next_line (fp, linrec, 0); sscanf (linrec, "%s %lf %lf", junk, &loca, &loce); // loc_epoch[a] *= M_PI / 180.0; psd->amplitude[a] = loca; psd->epoch[a] = loce * M_PI / 180.; } fclose (fp); break; } if(!psd) { m_last_reference_not_found = wxString(pIDX->IDX_reference_name, wxConvUTF8); return TC_MASTER_HARMONICS_NOT_FOUND; } else { m_msd_array.Add(psd); // add it to the member array pIDX->pref_sta_data = psd; return TC_NO_ERROR; } }
TC_Error_Code TCDS_Binary_Harmonic::LoadData(const wxString &data_file_path) { if(!open_tide_db (data_file_path.mb_str())) return TC_TCD_FILE_CORRUPT; //Build the tables of constituent data DB_HEADER_PUBLIC hdr = get_tide_db_header (); source_ident = wxString( hdr.version, wxConvUTF8 ); num_csts = hdr.constituents; if(0 == num_csts) return TC_GENERIC_ERROR; num_nodes = hdr.number_of_years; if(0 == num_nodes) return TC_GENERIC_ERROR; // Allocate a working buffer m_work_buffer = (double *) malloc (num_csts * sizeof (double)); // Constituent speeds m_cst_speeds = (double *) malloc (num_csts * sizeof (double)); for (int a=0; a<num_csts; a++) { m_cst_speeds[a] = get_speed (a); m_cst_speeds[a] *= M_PI / 648000; /* Convert to radians per second */ } // Equilibrium tables by year m_first_year = hdr.start_year; num_epochs = hdr.number_of_years; m_cst_epochs = (double **) malloc (num_csts * sizeof (double *)); for (int i=0; i<num_csts; i++) m_cst_epochs[i] = (double *) malloc (num_epochs * sizeof (double)); for (int i=0; i<num_csts; i++) { for (int year=0; year<num_epochs; year++) { m_cst_epochs[i][year] = get_equilibrium (i, year); m_cst_epochs[i][year] *= M_PI / 180.0; } } // Node factors m_cst_nodes = (double **) malloc (num_csts * sizeof (double *)); for (int a=0; a<num_csts; a++) m_cst_nodes[a] = (double *) malloc (num_nodes * sizeof (double)); for (int a=0; a<num_csts; a++) { for (int year=0; year<num_nodes; year++) m_cst_nodes[a][year] = get_node_factor (a, year); } // now load and create the index TIDE_RECORD *ptiderec = (TIDE_RECORD *)calloc(sizeof(TIDE_RECORD), 1); for(unsigned int i=0 ; i < hdr.number_of_records ; i++) { read_tide_record (i, ptiderec); num_IDX++; // Keep counting entries for harmonic file stuff IDX_entry *pIDX = new IDX_entry; pIDX->source_data_type = SOURCE_TYPE_BINARY_HARMONIC; pIDX->pDataSource = NULL; pIDX->Valid15 = 0; pIDX->pref_sta_data = NULL; // no reference data yet pIDX->IDX_Useable = 1; // but assume data is OK pIDX->IDX_tzname = NULL; pIDX->IDX_lon = ptiderec->header.longitude; pIDX->IDX_lat = ptiderec->header.latitude; const char *tz = get_tzfile (ptiderec->header.tzfile); change_time_zone ((char *)tz); if(tz_info) pIDX->IDX_time_zone = -tz_info->tzi.Bias; strncpy(pIDX->IDX_station_name, ptiderec->header.name, MAXNAMELEN); // if(strstr(ptiderec->header.name, "Beaufort") != NULL) // int yyp = 4; pIDX->IDX_flood_dir = ptiderec->max_direction; pIDX->IDX_ebb_dir = ptiderec->min_direction; if(REFERENCE_STATION == ptiderec->header.record_type) { // Establish Station Type wxString caplin(pIDX->IDX_station_name, wxConvUTF8); caplin.MakeUpper(); if(caplin.Contains(_T("CURRENT"))) pIDX->IDX_type = 'C'; else pIDX->IDX_type = 'T'; int t1 = ptiderec->zone_offset; double zone_offset = (double)(t1 / 100) + ((double)(t1 % 100))/60.; // pIDX->IDX_time_zone = t1a; pIDX->IDX_ht_time_off = pIDX->IDX_lt_time_off = 0; pIDX->IDX_ht_mpy = pIDX->IDX_lt_mpy = 1.0; pIDX->IDX_ht_off = pIDX->IDX_lt_off = 0.0; pIDX->IDX_ref_dbIndex = ptiderec->header.reference_station; // will be -1 // build a Station_Data class, and add to member array Station_Data *psd = new Station_Data; psd->amplitude = (double *)malloc(num_csts * sizeof(double)); psd->epoch = (double *)malloc(num_csts * sizeof(double)); psd->station_name = (char *)malloc(ONELINER_LENGTH); strncpy(psd->station_name, ptiderec->header.name, MAXNAMELEN); psd->station_type = pIDX->IDX_type; // Get meridian, which is seconds difference from UTC, not figuring DST, so that New York is always (-300 * 60) psd->meridian = -(tz_info->tzi.Bias * 60); psd->zone_offset = zone_offset; // Get units strncpy (psd->unit, get_level_units (ptiderec->level_units), 40 - 1); psd->unit[40 -1] = '\0'; psd->have_BOGUS = (findunit(psd->unit) != -1) && (known_units[findunit(psd->unit)].type == BOGUS); int unit_c; if (psd->have_BOGUS) unit_c = findunit("knots"); else unit_c = findunit(psd->unit); if(unit_c != -1) { strncpy (psd->units_conv, known_units[unit_c].name, sizeof(psd->units_conv)-1); strncpy (psd->units_abbrv, known_units[unit_c].abbrv, sizeof(psd->units_abbrv)-1); } else { strncpy (psd->units_conv, psd->unit, 40 - 1); psd->units_conv[40 - 1] = '\0'; strncpy (psd->units_abbrv, psd->unit, 20 - 1); psd->units_abbrv[20 - 1] = '\0'; } // Get constituents for (int a=0; a<num_csts; a++) { psd->amplitude[a] = ptiderec->amplitude[a]; psd->epoch[a] = ptiderec->epoch[a] * M_PI / 180.; } psd->DATUM = ptiderec->datum_offset; m_msd_array.Add(psd); // add it to the member array pIDX->pref_sta_data = psd; pIDX->IDX_ref_dbIndex = i; pIDX->have_offsets = 0; } else if(SUBORDINATE_STATION == ptiderec->header.record_type) { // Establish Station Type wxString caplin(pIDX->IDX_station_name, wxConvUTF8); caplin.MakeUpper(); if(caplin.Contains(_T("CURRENT"))) pIDX->IDX_type = 'c'; else pIDX->IDX_type = 't'; int t1 = ptiderec->max_time_add; double t1a = (double)(t1 / 100) + ((double)(t1 % 100))/60.; t1a *= 60; // Minutes pIDX->IDX_ht_time_off = t1a; pIDX->IDX_ht_mpy = ptiderec->max_level_multiply; if(0. == pIDX->IDX_ht_mpy) pIDX->IDX_ht_mpy = 1.0; pIDX->IDX_ht_off = ptiderec->max_level_add; t1 = ptiderec->min_time_add; t1a = (double)(t1 / 100) + ((double)(t1 % 100))/60.; t1a *= 60; // Minutes pIDX->IDX_lt_time_off = t1a; pIDX->IDX_lt_mpy = ptiderec->min_level_multiply; if(0. == pIDX->IDX_lt_mpy) pIDX->IDX_lt_mpy = 1.0; pIDX->IDX_lt_off = ptiderec->min_level_add; pIDX->IDX_ref_dbIndex = ptiderec->header.reference_station; // strncpy(pIDX->IDX_reference_name, ptiderec->header.name, MAXNAMELEN); if( pIDX->IDX_ht_time_off || pIDX->IDX_ht_off != 0.0 || pIDX->IDX_lt_off != 0.0 || pIDX->IDX_ht_mpy != 1.0 || pIDX->IDX_lt_mpy != 1.0) pIDX->have_offsets = 1; } m_IDX_array.Add(pIDX); } // Mark the index entries individually with invariant harmonic constants unsigned int max_index = GetMaxIndex(); for(unsigned int i=0 ; i < max_index ; i++) { IDX_entry *pIDX = GetIndexEntry( i ); if(pIDX) { pIDX->num_nodes = num_nodes; pIDX->num_csts = num_csts; pIDX->num_epochs = num_epochs; pIDX->m_cst_speeds = m_cst_speeds; pIDX->m_cst_nodes = m_cst_nodes; pIDX->m_cst_epochs = m_cst_epochs; pIDX->first_year = m_first_year; pIDX->m_work_buffer = m_work_buffer; } } free( ptiderec ); return TC_NO_ERROR; }