void climate_initState() // // Input: none // Output: none // Purpose: initializes climate state variables. // { LastDay = NO_DATE; Temp.tmax = MISSING; Snow.removed = 0.0; NextEvapDate = StartDate; NextEvapRate = 0.0; // --- initialize variables for time series evaporation if ( Evap.type == TIMESERIES_EVAP && Evap.tSeries >= 0 ) { // --- initialize NextEvapDate & NextEvapRate to first entry of // time series whose date <= the simulation start date table_getFirstEntry(&Tseries[Evap.tSeries], &NextEvapDate, &NextEvapRate); if ( NextEvapDate < StartDate ) { setNextEvapDate(StartDate); } Evap.rate = NextEvapRate / UCF(EVAPRATE); // --- find the next time evaporation rates change after this setNextEvapDate(NextEvapDate); } }
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; } } }
int getFirstRainfall(int j) // // Input: j = rain gage index // Output: returns TRUE if successful // Purpose: positions rainfall record to date with first rainfall. // { int k; // time series index float vFirst; // first rain volume (ft or m) double rFirst; // first rain intensity (in/hr or mm/hr) // --- assign default values to date & rainfall Gage[j].startDate = NO_DATE; Gage[j].rainfall = 0.0; // --- initialize internal cumulative rainfall value Gage[j].rainAccum = 0; // --- use rain interface file if applicable if ( Gage[j].dataSource == RAIN_FILE ) { if ( Frain.file && Gage[j].endFilePos > Gage[j].startFilePos ) { // --- retrieve 1st date & rainfall volume from file fseek(Frain.file, Gage[j].startFilePos, SEEK_SET); fread(&Gage[j].startDate, sizeof(DateTime), 1, Frain.file); fread(&vFirst, sizeof(float), 1, Frain.file); Gage[j].currentFilePos = ftell(Frain.file); // --- convert rainfall to intensity Gage[j].rainfall = convertRainfall(j, (double)vFirst); return 1; } return 0; } // --- otherwise access user-supplied rainfall time series else { k = Gage[j].tSeries; if ( k >= 0 ) { // --- retrieve first rainfall value from time series if ( table_getFirstEntry(&Tseries[k], &Gage[j].startDate, &rFirst) ) { // --- convert rainfall to intensity Gage[j].rainfall = convertRainfall(j, rFirst); return 1; } } return 0; } }
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 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; }
void climate_initState() // // Input: none // Output: none // Purpose: initializes climate state variables. // { LastDay = NO_DATE; Temp.tmax = MISSING; Snow.removed = 0.0; NextEvapDate = StartDate; NextEvapRate = 0.0; // --- initialize variables for time series evaporation if ( Evap.type == TIMESERIES_EVAP && Evap.tSeries >= 0 ) { // --- initialize NextEvapDate & NextEvapRate to first entry of // time series whose date <= the simulation start date table_getFirstEntry(&Tseries[Evap.tSeries], &NextEvapDate, &NextEvapRate); if ( NextEvapDate < StartDate ) { setNextEvapDate(StartDate); } Evap.rate = NextEvapRate / UCF(EVAPRATE); // --- find the next time evaporation rates change after this setNextEvapDate(NextEvapDate); } //// Following section added to release 5.1.010. //// //(5.1.010) // --- initialize variables for temperature evaporation if ( Evap.type == TEMPERATURE_EVAP ) { Tma.maxCount = sizeof(Tma.ta) / sizeof(double); Tma.count = 0; Tma.front = 0; Tma.tAve = 0.0; Tma.tRng = 0.0; } //// }
void outfall_setOutletDepth(int j, double yNorm, double yCrit, double z) // // Input: j = node index // yNorm = normal flow depth in outfall conduit (ft) // yCrit = critical flow depth in outfall conduit (ft) // z = height to outfall conduit invert (ft) // Output: none // Purpose: sets water depth at an outfall node. // { double x, y; // x,y values in table double yNew; // new depth above invert elev. (ft) double stage; // water elevation at outfall (ft) int k; // table index int i = Node[j].subIndex; // outfall index DateTime currentDate; // current date/time in days switch ( Outfall[i].type ) { case FREE_OUTFALL: if ( z > 0.0 ) Node[j].newDepth = 0.0; else Node[j].newDepth = MIN(yNorm, yCrit); return; case NORMAL_OUTFALL: if ( z > 0.0 ) Node[j].newDepth = 0.0; else Node[j].newDepth = yNorm; return; case FIXED_OUTFALL: stage = Outfall[i].fixedStage; break; case TIDAL_OUTFALL: k = Outfall[i].tideCurve; table_getFirstEntry(&Curve[k], &x, &y); currentDate = NewRoutingTime / MSECperDAY; x += ( currentDate - floor(currentDate) ) * 24.0; stage = table_lookup(&Curve[k], x) / UCF(LENGTH); break; case TIMESERIES_OUTFALL: k = Outfall[i].stageSeries; currentDate = StartDateTime + NewRoutingTime / MSECperDAY; stage = table_tseriesLookup(&Tseries[k], currentDate, TRUE) / UCF(LENGTH); break; default: stage = Node[j].invertElev; } // --- now determine depth at node given outfall stage elev. // --- let critical flow depth be min. of critical & normal depth yCrit = MIN(yCrit, yNorm); // --- if elev. of critical depth is below outfall stage elev. then // the outfall stage determines node depth if ( yCrit + z + Node[j].invertElev < stage ) { yNew = stage - Node[j].invertElev; } // --- otherwise if the outfall conduit lies above the outfall invert else if ( z > 0.0 ) { // --- if the outfall stage lies below the bottom of the outfall // conduit then the result is distance from node invert to stage if ( stage < Node[j].invertElev + z ) yNew = MAX(0.0, (stage - Node[j].invertElev)); // --- otherwise stage lies between bottom of conduit and critical // depth in conduit so result is elev. of critical depth else yNew = z + yCrit; } // --- and for case where there is no conduit offset and outfall stage // lies below critical depth, then node depth = critical depth else yNew = yCrit; Node[j].newDepth = yNew; }
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; }