void setNextEvapDate(DateTime theDate) // // Input: theDate = current simulation date // Output: sets a new value for NextEvapDate // Purpose: finds date for next change in evaporation after the current date. // { int yr, mon, day, k; double d, e; // --- do nothing if current date hasn't reached the current next date if ( NextEvapDate > theDate ) return; switch ( Evap.type ) { // --- for constant evaporation, use a next date far in the future case CONSTANT_EVAP: NextEvapDate = theDate + 365.; break; // --- for monthly evaporation, use the start of the next month case MONTHLY_EVAP: datetime_decodeDate(theDate, &yr, &mon, &day); if ( mon == 12 ) { mon = 1; yr++; } else mon++; NextEvapDate = datetime_encodeDate(yr, mon, 1); break; // --- for time series evaporation, find the next entry in the // series on or after the current date case TIMESERIES_EVAP: k = Evap.tSeries; if ( k >= 0 ) { NextEvapDate = theDate + 365.; while ( table_getNextEntry(&Tseries[k], &d, &e) && d <= EndDateTime ) { if ( d >= theDate ) { NextEvapDate = d; NextEvapRate = e; break; } } } break; // --- for climate file daily evaporation, use the next day case FILE_EVAP: NextEvapDate = floor(theDate) + 1.0; break; default: NextEvapDate = theDate + 365.; } }
void exfil_initState(int k) // // Input: k = storage unit index // Output: none // Purpose: initializes the state of a storage unit's exfiltration object. // { int i; double a, alast, d; TTable* aCurve; TExfil* exfil = Storage[k].exfil; // --- initialize exfiltration object if ( exfil != NULL ) { // --- initialize the Green-Ampt infil. parameters grnampt_initState(exfil->btmExfil); grnampt_initState(exfil->bankExfil); // --- shape given by a Storage Curve i = Storage[k].aCurve; if ( i >= 0 ) { // --- get bottom area aCurve = &Curve[i]; Storage[k].exfil->btmArea = table_lookupEx(aCurve, 0.0); // --- find min/max bank depths and max. bank area table_getFirstEntry(aCurve, &d, &a); exfil->bankMinDepth = 0.0; exfil->bankMaxDepth = 0.0; exfil->bankMaxArea = 0.0; alast = a; while ( table_getNextEntry(aCurve, &d, &a) ) { if ( a < alast ) break; else if ( a > alast ) { exfil->bankMaxArea = a; exfil->bankMaxDepth = d; } else if ( exfil->bankMaxArea == 0.0 ) exfil->bankMinDepth = d; else break; alast = a; } } // --- functional storage shape curve else { exfil->btmArea = Storage[k].aConst; if ( Storage[k].aExpon == 0.0 ) exfil->btmArea +=Storage[k].aCoeff; exfil->bankMinDepth = 0.0; exfil->bankMaxDepth = BIG; exfil->bankMaxArea = BIG; } } }
DateTime climate_getNextEvap(DateTime days) // // Input: days = current simulation date //(5.0.019 - LR) // Output: returns date (in whole days) when evaporation rate next changes // Purpose: finds date for next change in evaporation. // { int yr, mon, day, k; double d, e; days = floor(days); //(5.0.019 - LR) switch ( Evap.type ) { case CONSTANT_EVAP: return days + 365.; case MONTHLY_EVAP: datetime_decodeDate(days, &yr, &mon, &day); if ( mon == 12 ) { mon = 1; yr++; } else mon++; return datetime_encodeDate(yr, mon, 1); case TIMESERIES_EVAP: //// Following section modified for release 5.0.019 //// //(5.0.019 - LR) if ( NextEvapDate > days ) return NextEvapDate; k = Evap.tSeries; if ( k >= 0 ) { while ( table_getNextEntry(&Tseries[k], &d, &e) && d <= EndDateTime ) { if ( d > days ) { NextEvapDate = d; NextEvapRate = e; return d; } } } ////////////////////////////////////////////////////////// return days + 365.; case FILE_EVAP: return days + 1.0; default: return days + 365.; } }
int getNextInterval(TTable *curve, double y, double yLast, double wLast, double *y1, double *y2, double *w1, double *w2, double *wMax) // // Input: curve = pointer to a user-supplied shape curve table // y = current height in a geometry table // yLast = previous height in a geometry table // wLast = previous width in a geometry table // y1 = height at start of current curve interval // y2 = height at end of current curve interval // w1 = width at start of current curve interval // w2 = width at end of current curve interval // wMax = current maximum width of curve // Output: updated values for yLast, wLast, y1, y2, w1, w2, and wMax; // returns TRUE if successful, FALSE if not. // Purpose: advances to the next height interval of a shape's curve that // contains the current height being evaluated in the shape's // geometry table. // // Note: heights and widths are with repsect to a shape of unit height. { // --- keep advancing while the current geom. table height is // above the end of the curve table interval while ( y > *y2 ) { // --- move start of geom. table interval up to the end of // the current curve table interval if ( *y2 > yLast ) { Atotal += getArea(*y2, *w2, yLast, wLast); Ptotal += getPerim(*y2, *w2, yLast, wLast); yLast = *y2; wLast = *w2; } // --- move to the next curve table interval *y1 = *y2; *w1 = *w2; if ( !table_getNextEntry(curve, y2, w2) ) { *y2 = 1.0; return TRUE; } // --- update curve table's max. width if ( *w2 > *wMax ) *wMax = *w2; // --- check for valid curve table values if ( *y2 < *y1 || *w2 < 0.0 ) return FALSE; if ( *y2 > 1.0 ) *y2 = 1.0; } return TRUE; }
double table_tseriesLookup(TTable *table, double x, char extend) // // Input: table = pointer to a TTable structure // x = a date/time value // extend = TRUE if time series extended on either end // Output: returns a y-value // Purpose: retrieves the y-value corresponding to a time series date, // using interploation if necessary. // // NOTE: if extend is FALSE and date x is outside the range of the table // then 0 is returned; if TRUE then the first or last value is // returned. // { // --- x lies within current time bracket if ( table->x1 <= x && table->x2 >= x && table->x1 != table->x2 ) return table_interpolate(x, table->x1, table->y1, table->x2, table->y2); // --- x lies before current time bracket: // move to start of time series if ( table->x1 == table->x2 || x < table->x1 ) { table_getFirstEntry(table, &(table->x1), &(table->y1)); if ( x < table->x1 ) { if ( extend == TRUE ) return table->y1; else return 0; } } // --- x lies beyond current time bracket: // update start of next time bracket table->x1 = table->x2; table->y1 = table->y2; // --- get end of next time bracket while ( table_getNextEntry(table, &(table->x2), &(table->y2)) ) { // --- x lies within the bracket if ( x <= table->x2 ) return table_interpolate(x, table->x1, table->y1, table->x2, table->y2); // --- otherwise move to next time bracket table->x1 = table->x2; table->y1 = table->y2; } // --- return last value or 0 if beyond last data value if ( extend == TRUE ) return table->y1; else return 0.0; }
void table_tseriesInit(TTable *table) // // Input: table = pointer to a TTable structure // Output: none // Purpose: initializes the time bracket within a time series table. // { table_getFirstEntry(table, &(table->x1), &(table->y1)); table->x2 = table->x1; table->y2 = table->y1; table_getNextEntry(table, &(table->x2), &(table->y2)); }
int getNextRainfall(int j) // // Input: j = rain gage index // Output: returns 1 if successful; 0 if not // Purpose: positions rainfall record to date with next non-zero rainfall // while updating the gage's next rain intensity value. // // Note: zero rainfall values explicitly entered into a rain file or // time series are skipped over so that a proper accounting of // wet and dry periods can be maintained. // { int k; // time series index float vNext; // next rain volume (ft or m) double rNext; // next rain intensity (in/hr or mm/hr) Gage[j].nextRainfall = 0.0; do { if ( Gage[j].dataSource == RAIN_FILE ) { if ( Frain.file && Gage[j].currentFilePos < Gage[j].endFilePos ) { fseek(Frain.file, Gage[j].currentFilePos, SEEK_SET); fread(&Gage[j].nextDate, sizeof(DateTime), 1, Frain.file); fread(&vNext, sizeof(float), 1, Frain.file); Gage[j].currentFilePos = ftell(Frain.file); rNext = convertRainfall(j, (double)vNext); } else return 0; } else { k = Gage[j].tSeries; if ( k >= 0 ) { if ( !table_getNextEntry(&Tseries[k], &Gage[j].nextDate, &rNext) ) return 0; rNext = convertRainfall(j, rNext); } else return 0; } } while (rNext == 0.0); Gage[j].nextRainfall = rNext; return 1; }
int table_validate(TTable *table) // // Input: table = pointer to a TTable structure // Output: returns error code // Purpose: checks that table's x-values are in ascending order. // { int result; double x1, x2, y1, y2; double dx, dxMin = BIG; // --- open external file if used as the table's data source if ( table->file.mode == USE_FILE ) { table->file.file = fopen(table->file.name, "rt"); if ( table->file.file == NULL ) return ERR_TABLE_FILE_OPEN; } // --- retrieve the first data entry in the table result = table_getFirstEntry(table, &x1, &y1); // --- return error condition if external file has no valid data if ( !result && table->file.mode == USE_FILE ) return ERR_TABLE_FILE_READ; // --- retrieve successive table entries and check for non-increasing x-values while ( table_getNextEntry(table, &x2, &y2) ) { dx = x2 - x1; if ( dx <= 0.0 ) { table->x2 = x2; return ERR_CURVE_SEQUENCE; } dxMin = MIN(dxMin, dx); x1 = x2; } table->dxMin = dxMin; // --- return error if external file could not be read completely if ( table->file.mode == USE_FILE && !feof(table->file.file) ) return ERR_TABLE_FILE_READ; return 0; }
DateTime climate_getNextEvap(DateTime days) // // Input: days = current simulation date (in whole days) // Output: returns date (in whole days) when evaporation rate next changes // Purpose: finds date for next change in evaporation. // { int yr, mon, day, k; double d, e; switch ( Evap.type ) { case CONSTANT_EVAP: return days + 365.; case MONTHLY_EVAP: datetime_decodeDate(days, &yr, &mon, &day); if ( mon == 12 ) { mon = 1; yr++; } else mon++; return datetime_encodeDate(yr, mon, 1); case TIMESERIES_EVAP: k = Evap.tSeries; while ( table_getNextEntry(&Tseries[k], &d, &e) ) { if ( d > days ) return d; } return days + 365.; case FILE_EVAP: return days + 1.0; default: return days + 365.; } }
int getNextRainfall(int j) // // Input: j = rain gage index // Output: returns TRUE if successful // Purpose: positions rainfall record to date with next rainfall. // { int k; // time series index int result; // result of table query (TRUE/FALSE) float vNext; // next rain volume (ft or m) double rNext; // next rain intensity (in/hr or mm/hr) Gage[j].nextRainfall = 0.0; if ( Gage[j].dataSource == RAIN_FILE ) { if ( Frain.file && Gage[j].currentFilePos < Gage[j].endFilePos ) { fseek(Frain.file, Gage[j].currentFilePos, SEEK_SET); fread(&Gage[j].nextDate, sizeof(DateTime), 1, Frain.file); fread(&vNext, sizeof(float), 1, Frain.file); Gage[j].currentFilePos = ftell(Frain.file); Gage[j].nextRainfall = convertRainfall(j, (double)vNext); return 1; } return 0; } else { k = Gage[j].tSeries; if ( k >= 0 ) { result = table_getNextEntry(&Tseries[k], &Gage[j].nextDate, &rNext); if ( result ) Gage[j].nextRainfall = convertRainfall(j, rNext); return result; } return 0; } }
int computeShapeTables(TShape *shape, TTable *curve) // // Input: shape = pointer to a TShape object // curve = pointer to shape's table of width v. depth // Output: returns TRUE if successful. FALSE if not // Purpose: computes the entries in a shape's geometry tables from // the shape's width v. height curve normalized with repsect // to full height. // // Note: the shape curve is a user-supplied table of width v. height // for a custom x-section of unit height. { int i, n; double dy, y, y1, y2, w, w1, w2; double yLast, wLast, wMax; // --- get first entry of user's shape curve if ( !table_getFirstEntry(curve, &y1, &w1) ) return FALSE; if ( y1 < 0.0 || y1 >= 1.0 || w1 < 0.0 ) return FALSE; wMax = w1; // --- if first entry not at zero ht. then add an initial entry if ( y1 != 0.0 ) { y2 = y1; w2 = w1; y1 = 0.0; w1 = 0.0; } // --- otherwise get next entry in the user's shape curve else { if ( !table_getNextEntry(curve, &y2, &w2) ) return FALSE; if ( y2 < y1 || w2 < 0.0 ) return FALSE; if ( y2 > 1.0 ) y2 = 1.0; if ( w2 > wMax ) wMax = w2; } // --- determine number of entries & interval size in geom. tables shape->nTbl = N_SHAPE_TBL; n = shape->nTbl - 1; dy = 1.0 / (double)(n); // --- initialize geometry tables shape->areaTbl[0] = 0.0; shape->hradTbl[0] = 0.0; shape->widthTbl[0] = w1; Ptotal = w1; Atotal = 0.0; // --- fill in rest of geometry tables y = 0.0; w = w1; for ( i = 1; i <= n; i++ ) { // --- advance to next relative height level yLast = y; wLast = w; y = y + dy; // --- do not allow height to exceed 1.0 if ( fabs(y - 1.0) < TINY ) y = 1.0; // --- if height exceeds current shape curve interval, // move to next interval of shape curve if ( y > y2 ) { if ( !getNextInterval(curve, y, yLast, wLast, &y1, &y2, &w1, &w2, &wMax) ) return FALSE; yLast = y1; wLast = w1; } // --- get top width, area, & perimeter of current interval w = getWidth(y, y1, y2, w1, w2); Atotal += getArea(y, w, yLast, wLast); Ptotal += getPerim(y, w, yLast, wLast); // --- add top width to total perimeter if at top of shape if ( y == 1.0 ) Ptotal += w2; // --- update table values shape->widthTbl[i] = w; shape->areaTbl[i] = Atotal; if ( Ptotal > 0.0) shape->hradTbl[i] = Atotal / Ptotal; else shape->hradTbl[i] = 0.0; } // --- assign values to shape'a area and hyd. radius when full shape->aFull = shape->areaTbl[n]; shape->rFull = shape->hradTbl[n]; // --- assign values to shape's max. width and section factor shape->wMax = wMax; getSmax(shape); return TRUE; }