/************************************************************************************** * May ALTER the value of dimval if warranted!! */ void fi_dim_value_convert( double *dimval, FDBlist *file, NCVar *var, NCDim *d ) { #ifdef HAVE_UDUNITS2 double converted_dimval; int year0, month0, hour0, min0, day0, err; double sec0; if( (file->recdim_units == NULL) || (var->first_file->recdim_units == NULL) || (var->first_file->ut_unit_ptr == NULL) || (file->ut_unit_ptr == NULL) || (! d->timelike ) || (strcmp(file->recdim_units,var->first_file->recdim_units) == 0) ) return; /* Convert the dim value to a date using the units given * in the file that this dim value came from */ err = utCalendar2_cal( *dimval, file->ut_unit_ptr, &year0, &month0, &day0, &hour0, &min0, &sec0, d->calendar ); if( err == 0 ) { err = utInvCalendar2_cal( year0, month0, day0, hour0, min0, sec0, var->first_file->ut_unit_ptr, &converted_dimval, d->calendar ); if( err == 0 ) *dimval = converted_dimval; } #endif }
NhlErrorTypes ut_calendar_W( void ) { /* * Input array variables */ void *x; double *tmp_x; NrmQuark *sspec = NULL; char *cspec, *cspec_orig; int *option; int ndims_x; ng_size_t dsizes_x[NCL_MAX_DIMENSIONS]; int has_missing_x; NclScalar missing_x, missing_dx; NclBasicDataTypes type_x; /* * Variables for calculating fraction of year, if the option is 4. */ int doy, nsid, total_seconds_in_year, seconds_in_doy, seconds_in_hour; int seconds_in_minute; double current_seconds_in_year, fraction_of_year; /* * Variables for retrieving attributes from the first argument. */ NclAttList *attr_list; NclAtt attr_obj; NclStackEntry stack_entry; NrmQuark *scal; char *ccal = NULL; /* * Variables for Udunits package. */ ut_system *utopen_ncl(), *unit_system; ut_unit *utunit; /* * Output variables. */ int year, month, day, hour, minute; double second; void *date = NULL; int ndims_date = 0; ng_size_t *dsizes_date; NclScalar missing_date; NclBasicDataTypes type_date = NCL_none; NclObjClass type_date_t = NCL_none; /* * Variables for returning "calendar" attribute. */ int att_id; NclQuark *calendar; NclMultiDValData att_md, return_md; NclVar tmp_var; NclStackEntry return_data; /* * various */ int ret, return_missing; ng_size_t dsizes[1]; ng_size_t i, total_size_x; ng_size_t total_size_date = 0; ng_size_t index_date; int months_to_days_fix=0, years_to_days_fix=0; extern float truncf(float); /* * Before we do anything, initialize the Udunits package. */ unit_system = utopen_ncl(); /* * Retrieve parameters * * Note any of the pointer parameters can be set to NULL, which * implies you don't care about its value. */ x = (void*)NclGetArgValue( 0, 2, &ndims_x, dsizes_x, &missing_x, &has_missing_x, &type_x, DONT_CARE); /* * Get option. */ option = (int*)NclGetArgValue( 1, 2, NULL, NULL, NULL, NULL, NULL, 1); /* * The "units" attribute of "time" must be set, otherwise missing * values will be returned. * * The "calendar" option may optionally be set, but it must be equal to * one of the recognized calendars. */ return_missing = 0; stack_entry = _NclGetArg(0, 2, DONT_CARE); switch (stack_entry.kind) { case NclStk_VAR: if (stack_entry.u.data_var->var.att_id != -1) { attr_obj = (NclAtt) _NclGetObj(stack_entry.u.data_var->var.att_id); if (attr_obj == NULL) { return_missing = 1; break; } } else { /* * att_id == -1 ==> no attributes specified; return all missing. */ return_missing = 1; break; } /* * Check for attributes. If none are specified, then return missing values. */ if (attr_obj->att.n_atts == 0) { return_missing = 1; break; } else { /* * Get list of attributes. */ attr_list = attr_obj->att.att_list; /* * Loop through attributes and check them. */ while (attr_list != NULL) { if ((strcmp(attr_list->attname, "calendar")) == 0) { scal = (NrmQuark *) attr_list->attvalue->multidval.val; ccal = NrmQuarkToString(*scal); if(strcasecmp(ccal,"standard") && strcasecmp(ccal,"gregorian") && strcasecmp(ccal,"noleap") && strcasecmp(ccal,"365_day") && strcasecmp(ccal,"365") && strcasecmp(ccal,"360_day") && strcasecmp(ccal,"360") ) { NhlPError(NhlWARNING,NhlEUNKNOWN,"ut_calendar: the 'calendar' attribute is not equal to a recognized calendar. Returning all missing values."); return_missing = 1; } } if ((strcmp(attr_list->attname, "units")) == 0) { sspec = (NrmQuark *) attr_list->attvalue->multidval.val; } attr_list = attr_list->next; } } default: break; } /* * Convert sspec to character string. */ if(sspec == NULL) { NhlPError(NhlFATAL,NhlEUNKNOWN,"ut_calendar: no 'units' attribute provided"); return(NhlFATAL); } cspec = NrmQuarkToString(*sspec); /* * There's a bug in utInvCalendar2_cal that doesn't handle the * 360-day calendar correctly if units are "years since" or * "months since". * * To fix this bug, we convert these units to "days since", do the * calculation as "days since", and then convert back to the original * "years since" or "months since" requested units. */ cspec_orig = (char*)calloc(strlen(cspec)+1,sizeof(char)); strcpy(cspec_orig,cspec); cspec = fix_units_for_360_bug(ccal,cspec,&months_to_days_fix, &years_to_days_fix); /* * Make sure cspec is a valid udunits string. */ utunit = ut_parse(unit_system, cspec, UT_ASCII); if(utunit == NULL) { NhlPError(NhlWARNING,NhlEUNKNOWN,"ut_calendar: Invalid specification string. Missing values will be returned."); return_missing = 1; } /* * Calculate size of input array. */ total_size_x = 1; for( i = 0; i < ndims_x; i++ ) total_size_x *= dsizes_x[i]; /* * Calculate size and dimensions for output array, and allocate * memory for output array. The output size will vary depending * on what option the user has specified. Only options -5 to 4 * are currently recognized. (option = -4 doesn't exist.) */ if(*option < -5 || *option > 4 || *option == -4) { NhlPError(NhlWARNING,NhlEUNKNOWN,"ut_calendar: Unknown option, defaulting to 0."); *option = 0; } if(*option == 0) { type_date = NCL_float; type_date_t = nclTypefloatClass; total_size_date = 6 * total_size_x; missing_date = ((NclTypeClass)nclTypefloatClass)->type_class.default_mis; ndims_date = ndims_x + 1; date = (float *)calloc(total_size_date,sizeof(float)); } else if(*option == -5) { /* identical to option=0, except returns ints */ type_date = NCL_int; type_date_t = nclTypeintClass; total_size_date = 6 * total_size_x; missing_date = ((NclTypeClass)nclTypeintClass)->type_class.default_mis; ndims_date = ndims_x + 1; date = (int *)calloc(total_size_date,sizeof(int)); } else if(*option >= 1 && *option <= 4) { type_date = NCL_double; type_date_t = nclTypedoubleClass; total_size_date = total_size_x; missing_date = ((NclTypeClass)nclTypedoubleClass)->type_class.default_mis; ndims_date = ndims_x; date = (double *)calloc(total_size_date,sizeof(double)); } else if(*option >= -3 && *option <= -1) { type_date = NCL_int; type_date_t = nclTypeintClass; total_size_date = total_size_x; missing_date = ((NclTypeClass)nclTypeintClass)->type_class.default_mis; ndims_date = ndims_x; date = (int *)calloc(total_size_date,sizeof(int)); } dsizes_date = (ng_size_t *)calloc(ndims_date,sizeof(ng_size_t)); /* * Make sure we have enough memory for output. */ if( date == NULL || dsizes_date == NULL) { NhlPError(NhlFATAL,NhlEUNKNOWN,"ut_calendar: Unable to allocate memory for output arrays"); return(NhlFATAL); } /* * Calculate output dimension sizes. */ for( i = 0; i < ndims_x; i++ ) dsizes_date[i] = dsizes_x[i]; if(*option == 0 || *option == -5) { dsizes_date[ndims_x] = 6; } /* * Coerce missing values to double. */ coerce_missing(type_x,has_missing_x,&missing_x,&missing_dx,NULL); /* * If we reach this point and return_missing is not 0, then either * "units" was invalid or wasn't set, or "calendar" was not a * recoginized calendar. We return all missing values in this case. */ if(return_missing) { if(*option == 0) { for(i = 0; i < total_size_date; i++ ) { ((float*)date)[i] = missing_date.floatval; } } else if(*option == -5) { /* identical to option=0, except returns ints */ for(i = 0; i < total_size_date; i++ ) { ((int*)date)[i] = missing_date.intval; } } else if(*option >= 1 && *option <= 4) { for(i = 0; i < total_size_date; i++ ) { ((double*)date)[i] = missing_date.doubleval; } } else if(*option >= -3 && *option <= -1) { for(i = 0; i < total_size_date; i++ ) { ((int*)date)[i] = missing_date.intval; } } /* * Return all missing values. */ ret = NclReturnValue(date,ndims_date,dsizes_date, &missing_date,type_date,0); NclFree(dsizes_date); return(ret); } /* * Convert input to double if necessary. */ tmp_x = coerce_input_double(x,type_x,total_size_x,has_missing_x,&missing_x, &missing_dx); /* * This is the bug fix for 360 day calendars and a units * of "years since" or "months since". We have to convert * from "years since" or "months since" to "days since". * * See above for more information about the bug. */ if(years_to_days_fix == 1) { for(i = 0; i < total_size_x; i++ ) tmp_x[i] *= 360.; } if(months_to_days_fix == 1) { for(i = 0; i < total_size_x; i++ ) tmp_x[i] *= 30.; } /* * Loop through each element and get the 6 values. */ index_date = 0; for( i = 0; i < total_size_x; i++ ) { if(!has_missing_x || (has_missing_x && tmp_x[i] != missing_dx.doubleval)) { (void) utCalendar2_cal(tmp_x[i],utunit,&year,&month,&day, &hour,&minute,&second,ccal); /* * Calculate the return values, based on the input option. */ switch(*option) { case 0: ((float*)date)[index_date] = (float)year; ((float*)date)[index_date+1] = (float)month; ((float*)date)[index_date+2] = (float)day; ((float*)date)[index_date+3] = (float)hour; ((float*)date)[index_date+4] = (float)minute; ((float*)date)[index_date+5] = second; break; /* identical to option=0, except returns ints */ case -5: ((int*)date)[index_date] = year; ((int*)date)[index_date+1] = month; ((int*)date)[index_date+2] = day; ((int*)date)[index_date+3] = hour; ((int*)date)[index_date+4] = minute; ((int*)date)[index_date+5] = (int)truncf(second); break; /* * YYYYMM */ case -1: ((int*)date)[index_date] = (100*year) + month; break; case 1: ((double*)date)[index_date] = (double)(100*year) + (double)month; break; /* * YYYYMMDD */ case -2: ((int*)date)[index_date] = (10000*year) + (100*month) + day; break; case 2: ((double*)date)[index_date] = (double)(10000*year) + (double)(100*month) + (double)day; break; /* * YYYYMMDDHH */ case -3: ((int*)date)[index_date] = (1000000*year) + (10000*month) + (100*day) + hour; break; case 3: ((double*)date)[index_date] = (double)(1000000*year) + (double)(10000*month) + (double)(100*day) + (double)hour; break; /* * YYYY.fraction_of_year */ case 4: nsid = 86400; /* num seconds in a day */ if(ccal == NULL) { total_seconds_in_year = seconds_in_year(year,"standard"); doy = day_of_year(year,month,day,"standard"); } else { total_seconds_in_year = seconds_in_year(year,ccal); doy = day_of_year(year,month,day,ccal); } if(doy > 1) { seconds_in_doy = (doy-1) * nsid; } else { seconds_in_doy = 0; } if(hour > 1) { seconds_in_hour = (hour-1) * 3600; } else { seconds_in_hour = 0; } if(minute > 1) { seconds_in_minute = (minute-1) * 60; } else { seconds_in_minute = 0; } current_seconds_in_year = seconds_in_doy + seconds_in_hour + seconds_in_minute + second; fraction_of_year = current_seconds_in_year/(double)total_seconds_in_year; ((double*)date)[index_date] = (double)year + fraction_of_year; break; } } else { switch(*option) { case 0: ((float*)date)[index_date] = missing_date.floatval; ((float*)date)[index_date+1] = missing_date.floatval; ((float*)date)[index_date+2] = missing_date.floatval; ((float*)date)[index_date+3] = missing_date.floatval; ((float*)date)[index_date+4] = missing_date.floatval; ((float*)date)[index_date+5] = missing_date.floatval; break; /* identical to option=0, except returns ints */ case -5: ((int*)date)[index_date] = missing_date.intval; ((int*)date)[index_date+1] = missing_date.intval; ((int*)date)[index_date+2] = missing_date.intval; ((int*)date)[index_date+3] = missing_date.intval; ((int*)date)[index_date+4] = missing_date.intval; ((int*)date)[index_date+5] = missing_date.intval; break; case 1: case 2: case 3: case 4: ((double*)date)[index_date] = missing_date.doubleval; break; case -1: case -2: case -3: ((int*)date)[index_date] = missing_date.intval; break; } } if(*option == 0 || *option == -5) { index_date += 6; } else { index_date++; } } /* * Free the work arrays. */ if(type_x != NCL_double) NclFree(tmp_x); /* * Close up Udunits. */ utclose_ncl(unit_system); /* * Free extra units */ NclFree(cspec_orig); ut_free(utunit); /* * Set up variable to return. */ if(has_missing_x) { return_md = _NclCreateVal( NULL, NULL, Ncl_MultiDValData, 0, date, &missing_date, ndims_date, dsizes_date, TEMPORARY, NULL, type_date_t ); } else { return_md = _NclCreateVal( NULL, NULL, Ncl_MultiDValData, 0, date, NULL, ndims_date, dsizes_date, TEMPORARY, NULL, type_date_t ); } /* * Set up attributes to return. */ att_id = _NclAttCreate(NULL,NULL,Ncl_Att,0,NULL); dsizes[0] = 1; /* * Return "calendar" attribute. * * We can't just return "scal" here, because it's an NCL input * parameter and this seems to screw things up if we try to * return it as an attribute. */ calendar = (NclQuark*)NclMalloc(sizeof(NclQuark)); if(ccal != NULL) { *calendar = NrmStringToQuark(ccal); } else { *calendar = NrmStringToQuark("standard"); } att_md = _NclCreateVal( NULL, NULL, Ncl_MultiDValData, 0, (void*)calendar, NULL, 1, dsizes, TEMPORARY, NULL, (NclObjClass)nclTypestringClass ); _NclAddAtt( att_id, "calendar", att_md, NULL ); tmp_var = _NclVarCreate( NULL, NULL, Ncl_Var, 0, NULL, return_md, NULL, att_id, NULL, RETURNVAR, NULL, TEMPORARY ); NclFree(dsizes_date); /* * Return output grid and attributes to NCL. */ return_data.kind = NclStk_VAR; return_data.u.data_var = tmp_var; _NclPlaceReturn(return_data); return(NhlNOERROR); }
void udu_fmt_time( char *temp_string, size_t temp_string_len, double new_dimval, NCDim *dim, int include_granularity ) { static ut_unit *dataunits=NULL; int year, month, day, hour, minute, debug; double second; static char last_units[1024]; static char months[12][4] = { "Jan\0", "Feb\0", "Mar\0", "Apr\0", "May\0", "Jun\0", "Jul\0", "Aug\0", "Sep\0", "Oct\0", "Nov\0", "Dec\0"}; debug = 0; if( debug ) fprintf( stderr, "udu_fmt_time: entering with dim=%s, units=%s, value=%f\n", dim->name, dim->units, new_dimval ); if( ! valid_udunits_pkg ) { snprintf( temp_string, temp_string_len-1, "%lg", new_dimval ); return; } if( (strlen(dim->units) > 1023) || strcmp(dim->units,last_units) != 0 ) { if( dataunits != NULL ) /* see if left over from previous invocation */ ut_free( dataunits ); if( (dataunits = ut_parse( unitsys, dim->units, UT_ASCII )) == NULL ) { fprintf( stderr, "internal error: udu_fmt_time can't parse data unit string!\n" ); fprintf( stderr, "problematic units: \"%s\"\n", dim->units ); fprintf( stderr, "dim->name: %s dim->timelike: %d\n", dim->name, dim->timelike ); exit( -1 ); } strncpy( last_units, dim->units, 1023 ); } if( utCalendar2_cal( new_dimval, dataunits, &year, &month, &day, &hour, &minute, &second, dim->calendar ) != 0 ) { fprintf( stderr, "internal error: udu_fmt_time can't convert to calendar value!\n"); fprintf( stderr, "units: >%s<\n", dim->units ); exit( -1 ); } if( include_granularity ) { switch( dim->tgran ) { case TGRAN_YEAR: case TGRAN_MONTH: case TGRAN_DAY: snprintf( temp_string, temp_string_len-1, "%1d-%s-%04d", day, months[month-1], year ); break; case TGRAN_HOUR: case TGRAN_MIN: snprintf( temp_string, temp_string_len-1, "%1d-%s-%04d %02d:%02d", day, months[month-1], year, hour, minute ); break; default: snprintf( temp_string, temp_string_len-1, "%1d-%s-%04d %02d:%02d:%02.0f", day, months[month-1], year, hour, minute, second ); } } else { snprintf( temp_string, temp_string_len-1, "%1d-%s-%04d %02d:%02d:%02.0f", day, months[month-1], year, hour, minute, second ); } }
void process_auswave(e *E){ // netcdf vars int ncid; int varid; int retval; size_t attlen = 0; size_t from[3]; size_t to[3]; // for time conversion static char *calendar = "Standard"; ut_system *u_system; double sec; int ierr, yr, mo, day, hr, min; int i,j,t; int count; // read in the auswave data so we can estimate wave setup //time = UNLIMITED ; // (192 currently) //lat = 411 ; //lon = 441 ; // open the file if((retval = nc_open(E->wave_input, NC_NOWRITE, &ncid))) fail("failed to open wave setup input file: error is %d\n",retval); // get the time data if((retval = nc_inq_dimid(ncid, "time", &varid))) fail("failed to get auswave dimid: error is %d\n",retval); if((retval = nc_inq_dimlen(ncid,varid,&E->nTimeWaves))) fail("failed to get auswave lat dimlen: error is %d\n",retval); //printf("aus waves_times = %zu\n", E->nTimeWaves); // get the auswave lat data if((retval = nc_inq_dimid(ncid, "lat", &varid))) fail("failed to get auswave lat dimid: error is %d\n",retval); if((retval = nc_inq_dimlen(ncid,varid,&E->nLatWaves))) fail("failed to get auswave lat dimlen: error is %d\n",retval); //printf("auswave lat = %zu\n", E->nLatWaves); // get the auswave lon data if((retval = nc_inq_dimid(ncid, "lon", &varid))) fail("failed to get auswave lon dimid: error is %d\n",retval); if((retval = nc_inq_dimlen(ncid,varid,&E->nLonWaves))) fail("failed to get auswave lon dimlen: error is %d\n",retval); //printf("auswave lat = %zu\n", E->nLonWaves); // process spatial dimensions // malloc room for the dim variable arrays E->wavesLat = malloc(E->nLatWaves*sizeof(double)); E->wavesLon = malloc(E->nLonWaves*sizeof(double)); nc_inq_varid(ncid, "lat", &varid); if((retval = nc_get_var_double(ncid, varid, &E->wavesLat[0]))) fail("failed to read waves lat data: error is %d\n", retval); //printf("waves lat[0] = %f\n", E->wavesLat[0]); nc_inq_varid(ncid, "lon", &varid); if((retval = nc_get_var_double(ncid, varid, &E->wavesLon[0]))) fail("failed to read waves lon data: error is %d\n", retval); //printf("waves lon[0] = %f\n", E->wavesLon[0]); // find the dimension indexes that cover the spatial region we need int lat_end; double dLatWaves, dLonWaves; // grid spacings for lat, lon for auswave dLatWaves = fabs(E->wavesLat[1] - E->wavesLat[0])*2.0; dLonWaves = fabs(E->wavesLon[1] - E->wavesLon[0])*2.0; for(i=0; i<E->nLatWaves; i++) { if(E->wavesLat[i] > (E->roms_min_lat-dLatWaves)) // greater than because auswave lat is monotonically decreasing lat_end = i; } int lat_start; for(i=E->nLatWaves-1; i>=0; i--) { if(E->wavesLat[i] < (E->roms_max_lat+dLatWaves)) // less than because auswave lat is monotonically decreasing lat_start = i; } //printf("wave data start lat = %f (%d), end lat = %f (%d)\n", E->wavesLat[lat_start],lat_start, E->wavesLat[lat_end],lat_end); int lon_start; for(i=0; i<E->nLonWaves; i++) { if(E->wavesLon[i] < (E->roms_min_lon-dLonWaves)) lon_start = i; } int lon_end; for(i=E->nLonWaves-1; i>=0; i--) { if(E->wavesLon[i] > (E->roms_max_lon+dLonWaves)) lon_end = i; } //printf("wave data start lon = %f, end lon = %f\n", E->wavesLon[lon_start], E->wavesLon[lon_end]); // TODO: add some error checking to the bounds code. // for example, if the spatial extent does not overlap then throw an exception // now just read in what we want from the files // reading in the whole dataset to avoid gaps in the interpolation lat_start = 0; lat_end = E->nLatWaves-1; lon_start = 0; lon_end = E->nLonWaves-1; free(E->wavesLat); free(E->wavesLon); E->nLatWaves = (lat_end - lat_start); E->nLonWaves = (lon_end - lon_start); E->wavesLat = malloc(E->nLatWaves*sizeof(double)); E->wavesLon = malloc(E->nLonWaves*sizeof(double)); // now re-read the lat and lon data size_t spatial_from[1], spatial_to[1]; spatial_from[0] = lat_start; spatial_to[0] = lat_end-lat_start; nc_inq_varid(ncid, "lat", &varid); if((retval = nc_get_vara_double(ncid, varid, spatial_from, spatial_to, &E->wavesLat[0]))) fail("failed to read waves lat data: error is %d\n", retval); spatial_from[0] = lon_start; spatial_to[0] = lon_end-lon_start; nc_inq_varid(ncid, "lon", &varid); if((retval = nc_get_vara_double(ncid, varid, spatial_from, spatial_to, &E->wavesLon[0]))) fail("failed to read waves lon data: error is %d\n", retval); // process time E->wavesTime = malloc(E->nTimeWaves*sizeof(double)); // read the data from the waves output file nc_inq_varid(ncid, "time", &varid); if((retval = nc_get_var_double(ncid, varid, &E->wavesTime[0]))) fail("failed to read auswave time data: error is %d\n", retval); // normalize the time information between the roms_his file // and the tide data file // get everything in ROMS ocean_time // get the time metadata units nc_inq_attlen (ncid, varid, "units", &attlen); E->waves_time_units = (char *) malloc(attlen + 1); /* + 1 for trailing null */ E->waves_time_units[attlen] = '\x0'; nc_get_att_text(ncid, varid, "units", E->waves_time_units); //printf("waves time units = %s\n", E->waves_time_units); //printf("wavesTime[0] = %f\n", E->wavesTime[0]); // Make the Calendar calls //tval = 86460.0; /* in seconds, this is 1 day and 1 minute */ //tval = 8580; // Parse the units strings if( (E->waves_ref_time = ut_parse( E->u_system, E->waves_time_units, UT_ASCII )) == NULL ) { fprintf( stderr, "Error parsing units string \"%s\"\n", E->waves_time_units ); exit(-1); } /* if( (ierr = utCalendar2_cal( E->wavesTime[0], E->waves_ref_time, &yr, &mo, &day, &hr, &min, &sec, calendar )) != 0 ) { fprintf( stderr, "Error on utCalendar2_cal call: %d\n", ierr ); exit(-1); } printf( "this date is %04d-%02d-%02d %02d:%02d:%06.3lf\n",yr, mo, day, hr, min, sec ); */ // put the waves time on the same time units as the roms time for(t=0; t<E->nTimeWaves; t++) { //printf("PRE: waveTimes[t] = %f ", E->wavesTime[t]); // convert tide time into year, month, day, hour, minute and seconds if( (ierr = utCalendar2_cal( E->wavesTime[t], E->waves_ref_time, &yr, &mo, &day, &hr, &min, &sec, E->calendar )) != 0 ) { fprintf( stderr, "Error on utCalendar2_cal call: %d\n", ierr ); exit(-1); } //printf( "this date is %04d-%02d-%02d %02d:%02d:%06.3lf\n",yr, mo, day, hr, min, sec ); // convert this date to be on the same units as the roms time if( (ierr = utInvCalendar2_cal( yr, mo, day, hr, min, sec, E->roms_ref_time, &E->wavesTime[t], E->calendar )) != 0 ) { fprintf( stderr, "Error on utCalendar2_cal call: %d\n", ierr ); exit(-1); } //printf( "POST: %04d-%02d-%02d %02d:%02d:%06.3lf is %lf %s in the %s calendar\n", // yr, mo, day, hr, min, sec, E->wavesTime[t], E->roms_time_units, E->calendar ); } // find the index bounds where the waves time overlaps the roms time // the waves times should fully cover the roms times E->waves_start_time_index = -1; E->start_time_roms = E->romsTime[0]; // get the time start index for the tide file for(t=0; t<E->nTimeWaves; t++) { if(E->wavesTime[t]<=E->start_time_roms) E->waves_start_time_index = t; } if(E->waves_start_time_index == -1) { fprintf(stderr,"couldn't find a matching start time in the waves file.\n"); fprintf(stderr,"check to make sure the waves file times sufficiently overlap\n"); fprintf(stderr,"the ROMS times.\n\n"); exit(1); } // get the end index for the tide file E->waves_end_time_index = -1; E->end_time_roms = E->romsTime[E->nTimeRoms-1]; for(t=E->nTimeWaves-1; t>=0; t--) { //printf("t = %d, wave_time = %f\n",t,E->wavesTime[t]); if(E->wavesTime[t] >= E->end_time_roms) E->waves_end_time_index = t; } if(E->waves_end_time_index == -1) { fprintf(stderr,"couldn't find a matching end time in the waves file.\n"); fprintf(stderr,"check to make sure the wave file times sufficiently overlap\n"); fprintf(stderr,"the ROMS times.\n\n"); fprintf(stderr,"end time ROMS = %f\n", E->end_time_roms); fprintf(stderr,"end time waves = %f\n", E->wavesTime[E->nTimeWaves-1]); exit(1); } //printf("start index = %d\n", E->waves_start_time_index); //printf("end index = %d\n", E->waves_end_time_index); E->nTimeWavesSubset = (E->waves_end_time_index - E->waves_start_time_index)+1; // malloc enough room for the variable arrays //sig_wav_ht(time, lat, lon) E->Hs = malloc3d_double(E->nTimeWavesSubset, E->nLatWaves, E->nLonWaves); E->Tp = malloc3d_double(E->nTimeWavesSubset, E->nLatWaves, E->nLonWaves); // make the time vector for the output file E->waves_interp_time = malloc(E->nTimeWavesSubset*sizeof(double)); count=0; for(t=E->waves_start_time_index; t<=E->waves_end_time_index; t++) { E->waves_interp_time[count] = E->wavesTime[t]; count++; } // get the sig wave height nc_inq_varid(ncid, "sig_wav_ht", &varid); //if((retval = nc_get_var_double(ncid, varid, &E->Hs[0][0][0]))) // fail("failed to read waves setup data: error is %d\n", retval); from[0] = E->waves_start_time_index; to[0] = E->nTimeWavesSubset; from[1] = lat_start; to[1] = lat_end - lat_start; from[2] = lon_start; to[2] = lon_end - lon_start; if((retval = nc_get_vara_double(ncid, varid, from, to, &E->Hs[0][0][0]))) fail("failed to read waves Hs data: error is %d\n", retval); //printf("sig_wave_ht[0][0][0] = %f\n", E->Hs[0][0][0]); // get the peak period nc_inq_varid(ncid, "pk_wav_per", &varid); if((retval = nc_get_vara_double(ncid, varid, from, to, &E->Tp[0][0][0]))) fail("failed to read waves Hs data: error is %d\n", retval); //printf("pk_wav_per[0][0][0] = %f\n", E->Tp[0][0][0]); // close the file nc_close(ncid); // flip the auswave data so the lat vector is monotonically increasing double ***flipData = malloc3d_double(E->nTimeWavesSubset, E->nLatWaves, E->nLonWaves); double *flipLat = malloc(E->nLatWaves*sizeof(double)); // flip the lat vector for(i=0; i<E->nLatWaves; i++) { flipLat[i] = E->wavesLat[E->nLatWaves-1-i]; } // copy the flipped data back for(i=0; i<E->nLatWaves; i++) { E->wavesLat[i] = flipLat[i]; } // flip the Hs data array for(t=0; t<E->nTimeWavesSubset; t++) { for(i=0; i<E->nLatWaves; i++) { for(j=0; j<E->nLonWaves; j++) { flipData[t][i][j] = E->Hs[t][E->nLatWaves-1-i][j]; } } } // copy it back for(t=0; t<E->nTimeWavesSubset; t++) { for(i=0; i<E->nLatWaves; i++) { for(j=0; j<E->nLonWaves; j++) { E->Hs[t][i][j] = flipData[t][i][j]; } } } // flip the Tp data array for(t=0; t<E->nTimeWavesSubset; t++) { for(i=0; i<E->nLatWaves; i++) { for(j=0; j<E->nLonWaves; j++) { flipData[t][i][j] = E->Tp[t][E->nLatWaves-1-i][j]; } } } // copy it back for(t=0; t<E->nTimeWavesSubset; t++) { for(i=0; i<E->nLatWaves; i++) { for(j=0; j<E->nLonWaves; j++) { E->Tp[t][i][j] = flipData[t][i][j]; } } } free(flipData); free(flipLat); #ifdef CHECK // temporarily mess with this input data to check! for(t=0; t<E->nTimeWavesSubset; t++) { for(i=0; i<E->nLatWaves; i++) { for(j=0; j<E->nLonWaves; j++) { E->Tp[t][i][j] = (double)t; E->Hs[t][i][j] = (double)t; } } } #endif // malloc room for the output nearest neighbor interp auswave data // target grid for auswave data data // do a natural neighbour interpolation on the tide data we just read in // to fill in the land masked values before interpolating onto the ROMS grid E->Hs_on_roms = malloc3d_double(E->nTimeWavesSubset, E->nLonRho, E->nLatRho); E->Tp_on_roms = malloc3d_double(E->nTimeWavesSubset, E->nLonRho, E->nLatRho); // just for writing the netcdf file - trash this! //double *time_vector = malloc(E->nTimeWavesSubset*sizeof(double)); //printf("(E->waves_end_time_index-E->waves_start_time_index) = %d\n", E->nTimeWavesSubset); // set up variables for the lib-nn calls // nn optimized E->pin = malloc(E->nLonWaves * E->nLatWaves * sizeof(point)); E->zin = malloc(E->nLonWaves * E->nLatWaves * sizeof(double)); E->xout = malloc(E->nLonRho * E->nLatRho * sizeof(double)); E->yout = malloc(E->nLonRho * E->nLatRho * sizeof(double)); E->zout = malloc(E->nLonRho * E->nLatRho * sizeof(double)); // find out how many valid data points we have // and setup the input array for lib-nn //time_vector[t] = (double)t; //printf("setting up source grid for nn...\n"); E->nin = 0; for(i=0; i<E->nLatWaves; i++) { for(j=0; j<E->nLonWaves; j++) { if(E->Hs[0][i][j] > -999.0) { E->pin[E->nin].x = E->wavesLon[j]; E->pin[E->nin].y = E->wavesLat[i]; //E->nn_diff[E->nn_n].z = E->Hs[t][i][j]; //printf("i = %d, j = %d, lat = %.15g lon = %.15g Hs = %.15g\n", E->nn_diff[E->nn_n].x, E->nn_diff[E->nn_n].y, E->nn_diff[E->nn_n].z); E->nin++; } } } //printf("done\n");fflush(stdout); // now set up the output array for the nn interpolation // this is the roms grid E->nout = 0; for(i=0; i<E->nLonRho; i++) { for(j=0; j<E->nLatRho; j++) { E->xout[E->nout] = E->lon_rho[i][j]; E->yout[E->nout] = E->lat_rho[i][j]; E->zout[E->nout] = NaN; E->nout++; } } //printf("done\n");fflush(stdout); // setup the natural neighbour interpolation // only need to do this once E->d = delaunay_build(E->nin, E->pin, 0, NULL, 0, NULL); // create interpolator E->nn = nnai_build(E->d, E->nout, E->xout, E->yout); // for each time level for(t=0; t<E->nTimeWavesSubset; t++) { //printf("Hs: t = %d\n",t); // setup nodal values for the nn interps E->nin = 0; for(i=0; i<E->nLatWaves; i++) { for(j=0; j<E->nLonWaves; j++) { if(E->Hs[t][i][j] > -999.0) { E->pin[E->nin].z = E->Hs[t][i][j]; E->zin[E->nin] = E->pin[E->nin].z; E->nin++; } } } // do the interpolation nnai_interpolate(E->nn, E->zin, E->zout); // splat interpolated values onto the roms grid and apply land-sea mask count = 0; for(i=0; i<E->nLonRho; i++) { for(j=0; j<E->nLatRho; j++) { if(E->mask_rho[i][j] == 0){ E->Hs_on_roms[t][i][j] = NC_FILL_DOUBLE; } else{ E->Hs_on_roms[t][i][j] = E->zout[count]; } count++; } } /* // write it out to check //E->nn_nx * E->nn_ny, E->nn_interp, int lat_dimid, lon_dimid, time_dimid, dimIds[2]; int lat_varid, lon_varid, time_varid, interp_varid; // create the file nc_create("hs_interp.nc", NC_CLOBBER, &ncid); // def dimensions nc_def_dim(ncid, "lat", E->nLonRho, &lat_dimid); nc_def_dim(ncid, "lon", E->nLatRho, &lon_dimid); // def vars dimIds[0] = lat_dimid; dimIds[1] = lon_dimid; //nc_def_var(ncid, "lat", NC_DOUBLE, 1, &dimIds[0], &lat_varid); //nc_def_var(ncid, "lon", NC_DOUBLE, 1, &dimIds[1], &lon_varid); nc_def_var(ncid, "hs_interp_on_roms", NC_DOUBLE, 2, dimIds, &interp_varid); nc_enddef(ncid); // write the data //nc_put_var_double(ncid, lat_varid, &E->wavesLat[0]); //nc_put_var_double(ncid, lon_varid, &E->wavesLon[0]); nc_put_var_double(ncid, interp_varid, &E->Hs_on_roms[0][0][0]); // close the file nc_close(ncid); exit(1); */ } // end of loop over Hs time levels // now interp the Tp variable // for each time level for(t=0; t<E->nTimeWavesSubset; t++) { //printf("Tp: t = %d\n", t); E->nin = 0; for(i=0; i<E->nLatWaves; i++) { for(j=0; j<E->nLonWaves; j++) { if(E->Tp[t][i][j] > -999.0) { E->pin[E->nin].z = E->Tp[t][i][j]; E->zin[E->nin] = E->pin[E->nin].z; E->nin++; } } } // do the interpolation nnai_interpolate(E->nn, E->zin, E->zout); // splat interpolated values onto the roms grid and apply land-sea mask count = 0; for(i=0; i<E->nLonRho; i++) { for(j=0; j<E->nLatRho; j++) { if(E->mask_rho[i][j] == 0){ E->Tp_on_roms[t][i][j] = NC_FILL_DOUBLE; } else{ E->Tp_on_roms[t][i][j] = E->zout[count]; } count++; } } /* // write it out to check //E->nn_nx * E->nn_ny, E->nn_interp, int lat_dimid, lon_dimid, time_dimid, dimIds[2]; int lat_varid, lon_varid, time_varid, interp_varid; // create the file nc_create("tp_interp.nc", NC_CLOBBER, &ncid); // def dimensions nc_def_dim(ncid, "lat", E->nLonRho, &lat_dimid); nc_def_dim(ncid, "lon", E->nLatRho, &lon_dimid); // def vars dimIds[0] = lat_dimid; dimIds[1] = lon_dimid; //nc_def_var(ncid, "lat", NC_DOUBLE, 1, &dimIds[0], &lat_varid); //nc_def_var(ncid, "lon", NC_DOUBLE, 1, &dimIds[1], &lon_varid); nc_def_var(ncid, "tp_interp_on_roms", NC_DOUBLE, 2, dimIds, &interp_varid); nc_enddef(ncid); // write the data //nc_put_var_double(ncid, lat_varid, &E->wavesLat[0]); //nc_put_var_double(ncid, lon_varid, &E->wavesLon[0]); nc_put_var_double(ncid, interp_varid, &E->Tp_on_roms[0][0][0]); // close the file nc_close(ncid); exit(1); */ } // end of loop over Tp time levels free(E->pin); free(E->zin); free(E->xout); free(E->yout); free(E->zout); free(E->d); free(E->nn); //printf("done nn interp for waves\n"); // estimate wave setup on roms // setup is only calculates at the coastal points // to calculate setup, we need Hs, Tp and slope at coastal pointers // read in the slope data //printf("calculating wave setup..."); get_coastal_slope(E); // malloc room for the setup field // jNOTE: fix up the size of the time dimension here! E->setup_on_roms = malloc3d_double(E->nTimeWavesSubset, E->nLonRho, E->nLatRho); // malloc room for the time interpolated data // assign closest slope value to costline derived from the roms rho_mask double this_time; double this_lat; double this_lon; int **nearest_index = malloc2d_int(E->nLonRho, E->nLatRho); // first get the index mapping for each coastal cell for(i=0; i<E->nLonRho; i++) { for(j=0; j<E->nLatRho; j++) { if(E->coastline_mask[i][j] == 1) { // if this point is a coastal point // get longitude and latitude of the point this_time = t; this_lat = E->lat_rho[i][j]; this_lon = E->lat_rho[i][j]; nearest_index[i][j] = get_nearest_slope_index(E, this_lat, this_lon, E->slopeLat, E->slopeLon); } else{ //printf("fill it: i = %d, j = %d\n",i,j); nearest_index[i][j] = -999; } } } for(t=0; t<E->nTimeWavesSubset; t++) { //printf("#### t = %d\n",t); for(i=0; i<E->nLonRho; i++) { for(j=0; j<E->nLatRho; j++) { if(E->coastline_mask[i][j] == 1.0) { // if this point is a coastal point /* // get longitude and latitude of the point this_time = t; this_lat = E->lat_rho[i][j]; this_lon = E->lon_rho[i][j]; E->setup_on_roms[t][i][j] = get_nearest_setup(E, this_time, this_lat, this_lon, E->setup, E->wavesLat, E->wavesLon); //exit(1); */ // some cases for Hs and Tp are zero. // don't call get_setup() for these because it will divide by zero if( (E->Hs_on_roms[t][i][j] == 0.0) || (E->Tp_on_roms[t][i][j] == 0.0)) E->setup_on_roms[t][i][j] = 0.0; else E->setup_on_roms[t][i][j] = get_setup(E->Hs_on_roms[t][i][j], E->Tp_on_roms[t][i][j], E->slope[nearest_index[i][j]]); #ifdef CHECK // temporarily splat with Hs to check E->setup_on_roms[t][i][j] = E->Hs_on_roms[t][i][j]; #endif } else{ //printf("fill it: i = %d, j = %d\n",i,j); E->setup_on_roms[t][i][j] = NC_FILL_DOUBLE; } } } } //printf("...done\n"); // time interpolate the wavesetup data onto the roms time vector //printf("creating %d interpolated time levels for the setup field\n", E->nTimeRoms); E->setup_on_roms_time_interp = malloc3d_double(E->nTimeRoms, E->nLonRho, E->nLatRho); // initialize this array for(t=0; t<E->nTimeRoms; t++) { for(i=0; i<E->nLonRho; i++) { for(j=0; j<E->nLatRho; j++) { E->setup_on_roms_time_interp[t][i][j] = NC_FILL_DOUBLE; } } } // target time vector = E->romsTime // source time vector = E->wavesTime // y value vector double *ypts = malloc(E->nTimeWavesSubset*sizeof(double)); double *interp_y = malloc(E->nTimeRoms*sizeof(double)); for(i=0; i<E->nLonRho; i++) { for(j=0; j<E->nLatRho; j++) { if(E->setup_on_roms[0][i][j] != NC_FILL_DOUBLE) { for(t=0; t<E->nTimeWavesSubset; t++) { // get the wave setup vector at this location ypts[t] = E->setup_on_roms[t][i][j]; } time_interp_field(&E->wavesTime[E->waves_start_time_index], &ypts[0], E->nTimeWavesSubset, &E->romsTime[0], &interp_y[0], E->nTimeRoms); // now put this data into the time interp array for(t=0; t<E->nTimeRoms; t++) { // get the wave setup vector at this location E->setup_on_roms_time_interp[t][i][j] = interp_y[t]; } } } } //printf("done\n"); free(ypts); free(interp_y); free(E->Hs); free(E->Tp); free(E->Hs_on_roms); free(E->Tp_on_roms); free(E->wavesLon); free(E->wavesLat); free(E->setup_on_roms); free(E->slope); free(E->slopeLat); free(E->slopeLon); }