void writeGroundwater(void) { int i, j; int count = 0; double totalSeconds = NewRunoffTime / 1000.; double x[9]; if ( Nobjects[SUBCATCH] == 0 ) return; for ( j = 0; j < Nobjects[SUBCATCH]; j++ ) { if ( Subcatch[j].groundwater != NULL ) count++; } if ( count == 0 ) return; WRITE(""); WRITE("*******************"); WRITE("Groundwater Summary"); WRITE("*******************"); WRITE(""); fprintf(Frpt.file, "\n -----------------------------------------------------------------------------------------------------" "\n Total Total Maximum Average Average Final Final" "\n Total Total Lower Lateral Lateral Upper Water Upper Water" "\n Infil Evap Seepage Outflow Outflow Moist. Table Moist. Table"); if ( UnitSystem == US ) fprintf(Frpt.file, "\n Subcatchment in in in in %3s ft ft", FlowUnitWords[FlowUnits]); else fprintf(Frpt.file, "\n Subcatchment mm mm mm mm %3s m m", FlowUnitWords[FlowUnits]); fprintf(Frpt.file, "\n -----------------------------------------------------------------------------------------------------"); for ( j = 0; j < Nobjects[SUBCATCH]; j++ ) { if ( Subcatch[j].area == 0.0 || Subcatch[j].groundwater == NULL ) continue; fprintf(Frpt.file, "\n %-20s", Subcatch[j].ID); x[0] = Subcatch[j].groundwater->stats.infil * UCF(RAINDEPTH); x[1] = Subcatch[j].groundwater->stats.evap * UCF(RAINDEPTH); x[2] = Subcatch[j].groundwater->stats.deepFlow * UCF(RAINDEPTH); x[3] = Subcatch[j].groundwater->stats.latFlow * UCF(RAINDEPTH); x[4] = Subcatch[j].groundwater->stats.maxFlow * UCF(FLOW) * Subcatch[j].area; x[5] = Subcatch[j].groundwater->stats.avgUpperMoist / totalSeconds; x[6] = Subcatch[j].groundwater->stats.avgWaterTable * UCF(LENGTH) / totalSeconds; x[7] = Subcatch[j].groundwater->stats.finalUpperMoist; x[8] = Subcatch[j].groundwater->stats.finalWaterTable * UCF(LENGTH); for (i = 0; i < 9; i++) fprintf(Frpt.file, " %8.2f", x[i]); } WRITE(""); }
void climate_validate() // // Input: none // Output: none // Purpose: validates climatological variables // { int i; //(5.1.007) double a, z, pa; // --- check if climate data comes from external data file //(5.1.007) if ( Wind.type == FILE_WIND || Evap.type == FILE_EVAP || Evap.type == TEMPERATURE_EVAP ) { if ( Fclimate.mode == NO_FILE ) { report_writeErrorMsg(ERR_NO_CLIMATE_FILE, ""); } } // --- open the climate data file //(5.1.007) if ( Fclimate.mode == USE_FILE ) climate_openFile(); //(5.1.007) // --- snow melt parameters tipm & rnm must be fractions if ( Snow.tipm < 0.0 || Snow.tipm > 1.0 || Snow.rnm < 0.0 || Snow.rnm > 1.0 ) report_writeErrorMsg(ERR_SNOWMELT_PARAMS, ""); // --- latitude should be between -90 & 90 degrees a = Temp.anglat; if ( a <= -89.99 || a >= 89.99 ) report_writeErrorMsg(ERR_SNOWMELT_PARAMS, ""); else Temp.tanAnglat = tan(a * PI / 180.0); // --- compute psychrometric constant z = Temp.elev / 1000.0; if ( z <= 0.0 ) pa = 29.9; else pa = 29.9 - 1.02*z + 0.0032*pow(z, 2.4); // atmos. pressure Temp.gamma = 0.000359 * pa; // --- convert units of monthly temperature & evap adjustments //(5.1.007) for (i = 0; i < 12; i++) { if (UnitSystem == SI) Adjust.temp[i] *= 9.0/5.0; Adjust.evap[i] /= UCF(EVAPRATE); } }
double getVariableValue(Project* project, int varIndex) // // Input: varIndex = index of a project->GW variable // Output: returns current value of project->GW variable // Purpose: finds current value of a project->GW variable. // { switch (varIndex) { case gwvHGW: return project->Hgw * UCF(project,LENGTH); case gwvHSW: return project->Hsw * UCF(project, LENGTH); case gwvHCB: return project->Hstar * UCF(project, LENGTH); case gwvHGS: return project->TotalDepth * UCF(project, LENGTH); case gwvKS: return project->A.conductivity * UCF(project, RAINFALL); case gwvK: return project->HydCon * UCF(project, RAINFALL); //(5.1.010) case gwvTHETA:return project->Theta; //(5.1.008) case gwvPHI: return project->A.porosity; //(5.1.008) case gwvFI: return project->Infil * UCF(project, RAINFALL); //(5.1.008) case gwvFU: return project->UpperPerc * UCF(project, RAINFALL); //(5.1.008) case gwvA: return project->Area * UCF(project, LANDAREA); //(5.1.008) default: return 0.0; } }
void subcatch_getBuildup(int j, double tStep) // // Input: j = subcatchment index // tStep = time step (sec) // Output: none // Purpose: adds to pollutant buildup on subcatchment. // { int i; // land use index int p; // pollutant index double f; // land use fraction double area; // land use area (acres or hectares) double curb; // land use curb length (user units) double oldBuildup; // buildup at start of time step double newBuildup; // buildup at end of time step // --- consider each landuse for (i = 0; i < Nobjects[LANDUSE]; i++) { // --- skip landuse if not in subcatch f = Subcatch[j].landFactor[i].fraction; if ( f == 0.0 ) continue; // --- get land area (in acres or hectares) & curb length area = f * Subcatch[j].area * UCF(LANDAREA); curb = f * Subcatch[j].curbLength; // --- examine each pollutant for (p = 0; p < Nobjects[POLLUT]; p++) { // --- see if snow-only buildup is in effect if (Pollut[p].snowOnly && Subcatch[j].newSnowDepth < 0.001/12.0) continue; // --- use land use's buildup function to update buildup amount oldBuildup = Subcatch[j].landFactor[i].buildup[p]; newBuildup = landuse_getBuildup(i, p, area, curb, oldBuildup, tStep); newBuildup = MAX(newBuildup, oldBuildup); Subcatch[j].landFactor[i].buildup[p] = newBuildup; massbal_updateLoadingTotals(BUILDUP_LOAD, p, (newBuildup - oldBuildup)); } } }
double getVariableValue(int varIndex) // // Input: varIndex = index of a GW variable // Output: returns current value of GW variable // Purpose: finds current value of a GW variable. // { switch (varIndex) { case gwvHGW: return Hgw * UCF(LENGTH); case gwvHSW: return Hsw * UCF(LENGTH); case gwvHCB: return Hstar * UCF(LENGTH); case gwvHGS: return TotalDepth * UCF(LENGTH); case gwvKS: return A.conductivity * UCF(RAINFALL); case gwvK: return HydCon * UCF(RAINFALL); //(5.1.010) case gwvTHETA:return Theta; //(5.1.008) case gwvPHI: return A.porosity; //(5.1.008) case gwvFI: return Infil * UCF(RAINFALL); //(5.1.008) case gwvFU: return UpperPerc * UCF(RAINFALL); //(5.1.008) case gwvA: return Area * UCF(LANDAREA); //(5.1.008) default: return 0.0; } }
void setMeltParams(int j, int k, float x[]) // // Input: j = snowmelt parameter set index // k = data category index // x = array of snow parameter values // Output: none // Purpose: assigns values to parameters in a snow melt data set. // { int i; // --- snow pack melt parameters if ( k >= SNOW_PLOWABLE && k <= SNOW_PERV ) { // --- min/max melt coeffs. Snowmelt[j].dhmin[k] = x[0] * UCF(TEMPERATURE) / UCF(RAINFALL); Snowmelt[j].dhmax[k] = x[1] * UCF(TEMPERATURE) / UCF(RAINFALL); // --- base melt temp (deg F) Snowmelt[j].tbase[k] = x[2]; if ( UnitSystem == SI ) Snowmelt[j].tbase[k] = (9./5.) * Snowmelt[j].tbase[k] + 32.0; // --- free water fractions Snowmelt[j].fwfrac[k] = x[3]; // --- initial snow depth & free water depth Snowmelt[j].wsnow[k] = x[4] / UCF(RAINDEPTH); Snowmelt[j].fwnow[k] = x[5] / UCF(RAINDEPTH); // --- fraction of impervious area that is plowable if ( k == SNOW_PLOWABLE ) Snowmelt[j].snn = x[6]; // --- min. depth for 100% areal coverage on remaining // impervious area or total pervious area else Snowmelt[j].si[k] = x[6] / UCF(RAINDEPTH); } // --- removal parameters else if ( k == SNOW_REMOVAL ) { Snowmelt[j].weplow = x[0]; for (i=0; i<=4; i++) Snowmelt[j].sfrac[i] = x[i+1]; if ( x[6] >= 0.0 ) Snowmelt[j].toSubcatch = (int)(x[6] + 0.01); else Snowmelt[j].toSubcatch = -1; } }
void getFluxes(Project* project, double theta, double lowerDepth) // // Input: upperVolume = vol. depth of upper zone (ft) // upperDepth = depth of upper zone (ft) // Output: none // Purpose: computes water fluxes into/out of upper/lower project->GW zones. // { double upperDepth; // --- find upper zone depth lowerDepth = MAX(lowerDepth, 0.0); lowerDepth = MIN(lowerDepth, project->TotalDepth); upperDepth = project->TotalDepth - lowerDepth; // --- save lower depth and theta to global variables project->Hgw = lowerDepth; project->Theta = theta; // --- find evaporation rate from both zones getEvapRates(project,theta, upperDepth); // --- find percolation rate from upper to lower zone project->UpperPerc = getUpperPerc(project,theta, upperDepth); project->UpperPerc = MIN(project->UpperPerc, project->MaxUpperPerc); // --- find loss rate to deep project->GW if ( project->DeepFlowExpr != NULL ) project->LowerLoss = mathexpr_eval(project, project->DeepFlowExpr, getVariableValue) / UCF(project,RAINFALL); else project->LowerLoss = project->A.lowerLossCoeff * lowerDepth / project->TotalDepth; project->LowerLoss = MIN(project->LowerLoss, lowerDepth/project->Tstep); // --- find project->GW flow rate from lower zone to drainage system node project->GWFlow = getGWFlow(project,lowerDepth); if ( project->LatFlowExpr != NULL ) { project->GWFlow += mathexpr_eval(project, project->LatFlowExpr, getVariableValue) / UCF(project, GWFLOW); } if ( project->GWFlow >= 0.0 ) project->GWFlow = MIN(project->GWFlow, project->MaxGWFlowPos); else project->GWFlow = MAX(project->GWFlow, project->MaxGWFlowNeg); }
int rdii_readRdiiInflow(char* tok[], int ntoks) // // Input: tok[] = array of string tokens // ntoks = number of tokens // Output: returns an error code // Purpose: reads properties of an RDII inflow from a line of input. // { int j, k; float a; TRdiiInflow* inflow; // --- check for proper number of items if ( ntoks < 3 ) return error_setInpError(ERR_ITEMS, ""); // --- check that node receiving RDII exists j = project_findObject(NODE, tok[0]); if ( j < 0 ) return error_setInpError(ERR_NAME, tok[0]); // --- check that RDII unit hydrograph exists k = project_findObject(UNITHYD, tok[1]); if ( k < 0 ) return error_setInpError(ERR_NAME, tok[1]); // --- read in sewer area value if ( !getFloat(tok[2], &a) || a < 0.0 ) return error_setInpError(ERR_NUMBER, tok[2]); // --- create the RDII inflow object if it doesn't already exist inflow = Node[j].rdiiInflow; if ( inflow == NULL ) { inflow = (TRdiiInflow *) malloc(sizeof(TRdiiInflow)); if ( !inflow ) return error_setInpError(ERR_MEMORY, ""); } // --- assign UH & area to inflow object inflow->unitHyd = k; inflow->area = a / UCF(LANDAREA); // --- assign inflow object to node Node[j].rdiiInflow = inflow; return 0; }
void writeSubcatchRunoff() { int j; double a, x, r; if ( Nobjects[SUBCATCH] == 0 ) return; WRITE(""); WRITE("***************************"); WRITE("Subcatchment Runoff Summary"); WRITE("***************************"); WRITE(""); fprintf(Frpt.file, "\n --------------------------------------------------------------------------------------------------------" "\n Total Total Total Total Total Total Peak Runoff" "\n Precip Runon Evap Infil Runoff Runoff Runoff Coeff"); if ( UnitSystem == US ) fprintf(Frpt.file, "\n Subcatchment in in in in in %8s %3s", VolUnitsWords[UnitSystem], FlowUnitWords[FlowUnits]); else fprintf(Frpt.file, "\n Subcatchment mm mm mm mm mm %8s %3s", VolUnitsWords[UnitSystem], FlowUnitWords[FlowUnits]); fprintf(Frpt.file, "\n --------------------------------------------------------------------------------------------------------"); for ( j = 0; j < Nobjects[SUBCATCH]; j++ ) { a = Subcatch[j].area; if ( a == 0.0 ) continue; fprintf(Frpt.file, "\n %-20s", Subcatch[j].ID); x = SubcatchStats[j].precip * UCF(RAINDEPTH); fprintf(Frpt.file, " %10.2f", x/a); x = SubcatchStats[j].runon * UCF(RAINDEPTH); fprintf(Frpt.file, " %10.2f", x/a); x = SubcatchStats[j].evap * UCF(RAINDEPTH); fprintf(Frpt.file, " %10.2f", x/a); x = SubcatchStats[j].infil * UCF(RAINDEPTH); fprintf(Frpt.file, " %10.2f", x/a); x = SubcatchStats[j].runoff * UCF(RAINDEPTH); fprintf(Frpt.file, " %10.2f", x/a); x = SubcatchStats[j].runoff * Vcf; fprintf(Frpt.file, "%12.2f", x); x = SubcatchStats[j].maxFlow * UCF(FLOW); fprintf(Frpt.file, " %8.2f", x); r = SubcatchStats[j].precip + SubcatchStats[j].runon; if ( r > 0.0 ) r = SubcatchStats[j].runoff / r; fprintf(Frpt.file, "%8.3f", r); } WRITE(""); }
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; } //// }
int gwater_readAquiferParams(int j, char* tok[], int ntoks) // // Input: j = aquifer index // tok[] = array of string tokens // ntoks = number of tokens // Output: returns error message // Purpose: reads aquifer parameter values from line of input data // // Data line contains following parameters: // ID, porosity, wiltingPoint, fieldCapacity, conductivity, // conductSlope, tensionSlope, upperEvapFraction, lowerEvapDepth, // gwRecession, bottomElev, waterTableElev, upperMoisture // { int i; double x[12]; char *id; // --- check that aquifer exists if ( ntoks < 12 ) return error_setInpError(ERR_ITEMS, ""); id = project_findID(AQUIFER, tok[0]); if ( id == NULL ) return error_setInpError(ERR_NAME, tok[0]); // --- read remaining tokens as floats for (i = 0; i < 11; i++) x[i] = 0.0; for (i = 1; i < 13; i++) { if ( ! getDouble(tok[i], &x[i-1]) ) return error_setInpError(ERR_NUMBER, tok[i]); } // --- assign parameters to aquifer object Aquifer[j].ID = id; Aquifer[j].porosity = x[0]; Aquifer[j].wiltingPoint = x[1]; Aquifer[j].fieldCapacity = x[2]; Aquifer[j].conductivity = x[3] / UCF(RAINFALL); Aquifer[j].conductSlope = x[4]; Aquifer[j].tensionSlope = x[5] / UCF(LENGTH); Aquifer[j].upperEvapFrac = x[6]; Aquifer[j].lowerEvapDepth = x[7] / UCF(LENGTH); Aquifer[j].lowerLossCoeff = x[8] / UCF(RAINFALL); Aquifer[j].bottomElev = x[9] / UCF(LENGTH); Aquifer[j].waterTableElev = x[10] / UCF(LENGTH); Aquifer[j].upperMoisture = x[11]; return 0; }
void setWind(DateTime theDate) // // Input: theDate = simulation date // Output: none // Purpose: sets wind speed (mph) for a specified date. // { int yr, mon, day; switch ( Wind.type ) { case MONTHLY_WIND: datetime_decodeDate(theDate, &yr, &mon, &day); Wind.ws = Wind.aws[mon-1] / UCF(WINDSPEED); break; case FILE_WIND: Wind.ws = FileValue[WIND]; break; default: Wind.ws = 0.0; } }
void output_saveNodeResults(double reportTime, FILE* file) // // Input: reportTime = elapsed simulation time (millisec) // file = ptr. to binary output file // Output: none // Purpose: writes computed node results to binary file. // { extern TRoutingTotals StepFlowTotals; // defined in massbal.c int j; // --- find where current reporting time lies between latest routing times double f = (reportTime - OldRoutingTime) / (NewRoutingTime - OldRoutingTime); // --- write node results to file for (j=0; j<Nobjects[NODE]; j++) { // --- retrieve interpolated results for reporting time & write to file node_getResults(j, f, NodeResults); if ( Node[j].rptFlag ) //(5.0.014 - LR) fwrite(NodeResults, sizeof(REAL4), NnodeResults, file); //(5.0.014 - LR) // --- update system-wide storage volume //(5.0.012 - LR) //SysResults[SYS_FLOODING] += NodeResults[NODE_OVERFLOW]; //(5.0.012 - LR) SysResults[SYS_STORAGE] += NodeResults[NODE_VOLUME]; //if ( Node[j].degree == 0 ) //(5.0.012 - LR) //{ //(5.0.012 - LR) // SysResults[SYS_OUTFLOW] += NodeResults[NODE_INFLOW]; //(5.0.012 - LR) //} //(5.0.012 - LR) } // --- update system-wide flows //(5.0.012 - LR) SysResults[SYS_FLOODING] = (REAL4) (StepFlowTotals.flooding * UCF(FLOW)); //(5.0.012 - LR) SysResults[SYS_OUTFLOW] = (REAL4) (StepFlowTotals.outflow * UCF(FLOW)); //(5.0.012 - LR) SysResults[SYS_DWFLOW] = (REAL4)(StepFlowTotals.dwInflow * UCF(FLOW)); SysResults[SYS_GWFLOW] = (REAL4)(StepFlowTotals.gwInflow * UCF(FLOW)); SysResults[SYS_IIFLOW] = (REAL4)(StepFlowTotals.iiInflow * UCF(FLOW)); SysResults[SYS_EXFLOW] = (REAL4)(StepFlowTotals.exInflow * UCF(FLOW)); SysResults[SYS_INFLOW] = SysResults[SYS_RUNOFF] + SysResults[SYS_DWFLOW] + SysResults[SYS_GWFLOW] + SysResults[SYS_IIFLOW] + SysResults[SYS_EXFLOW]; }
void setEvap(DateTime theDate) // // Input: theDate = simulation date // Output: none // Purpose: sets evaporation rate (ft/sec) for a specified date. // { int yr, mon, day, k; switch ( Evap.type ) { case CONSTANT_EVAP: Evap.rate = Evap.monthlyEvap[0]; break; case MONTHLY_EVAP: datetime_decodeDate(theDate, &yr, &mon, &day); Evap.rate = Evap.monthlyEvap[mon-1]; break; case TIMESERIES_EVAP: k = Evap.tSeries; Evap.rate = table_tseriesLookup(&Tseries[k], theDate, TRUE); break; case FILE_EVAP: Evap.rate = FileValue[EVAP]; datetime_decodeDate(theDate, &yr, &mon, &day); Evap.rate *= Evap.panCoeff[mon-1]; break; default: Evap.rate = 0.0; } // --- convert rate from in/day (mm/day) to ft/sec Evap.rate /= UCF(EVAPRATE); }
void massbal_getSysFlows(double f, double sysFlows[]) // // Input: f = time weighting factor // Output: sysFlows = array of total system flows // Purpose: retrieves time-weighted average of old and new system flows. // { double f1 = 1.0 - f; sysFlows[SYS_DWFLOW] = (f1 * OldStepFlowTotals.dwInflow + f * StepFlowTotals.dwInflow) * UCF(FLOW); sysFlows[SYS_GWFLOW] = (f1 * OldStepFlowTotals.gwInflow + f * StepFlowTotals.gwInflow) * UCF(FLOW); sysFlows[SYS_IIFLOW] = (f1 * OldStepFlowTotals.iiInflow + f * StepFlowTotals.iiInflow) * UCF(FLOW); sysFlows[SYS_EXFLOW] = (f1 * OldStepFlowTotals.exInflow + f * StepFlowTotals.exInflow) * UCF(FLOW); sysFlows[SYS_FLOODING] = (f1 * OldStepFlowTotals.flooding + f * StepFlowTotals.flooding) * UCF(FLOW); sysFlows[SYS_OUTFLOW] = (f1 * OldStepFlowTotals.outflow + f * StepFlowTotals.outflow) * UCF(FLOW); sysFlows[SYS_STORAGE] = (f1 * OldStepFlowTotals.finalStorage + f * StepFlowTotals.finalStorage) * UCF(VOLUME); }
void output_saveNodeResults(Project* project, double reportTime, FILE* file) // // Input: reportTime = elapsed simulation time (millisec) // file = ptr. to binary output file // Output: none // Purpose: writes computed node results to binary file. // { //project->project->StepFlowTotals; // defined in massbal.c int j; // --- find where current reporting time lies between latest routing times double f = (reportTime - project->OldRoutingTime) / (project->NewRoutingTime - project->OldRoutingTime); // --- write node results to file for (j=0; j<project->Nobjects[NODE]; j++) { // --- retrieve interpolated results for reporting time & write to file node_getResults(project,j, f, project->NodeResults); if ( project->Node[j].rptFlag ) fwrite(project->NodeResults, sizeof(REAL4), project->NnodeResults, file); stats_updateMaxNodeDepth(project,j, project->NodeResults[NODE_DEPTH]); //(5.1.008) // --- update system-wide storage volume project->SysResults[SYS_STORAGE] += project->NodeResults[NODE_VOLUME]; } // --- update system-wide flows project->SysResults[SYS_FLOODING] = (REAL4) (project->StepFlowTotals.flooding * UCF(project,FLOW)); project->SysResults[SYS_OUTFLOW] = (REAL4)(project->StepFlowTotals.outflow * UCF(project, FLOW)); project->SysResults[SYS_DWFLOW] = (REAL4)(project->StepFlowTotals.dwInflow * UCF(project, FLOW)); project->SysResults[SYS_GWFLOW] = (REAL4)(project->StepFlowTotals.gwInflow * UCF(project, FLOW)); project->SysResults[SYS_IIFLOW] = (REAL4)(project->StepFlowTotals.iiInflow * UCF(project, FLOW)); project->SysResults[SYS_EXFLOW] = (REAL4)(project->StepFlowTotals.exInflow * UCF(project, FLOW)); project->SysResults[SYS_INFLOW] = project->SysResults[SYS_RUNOFF] + project->SysResults[SYS_DWFLOW] + project->SysResults[SYS_GWFLOW] + project->SysResults[SYS_IIFLOW] + project->SysResults[SYS_EXFLOW]; }
int climate_readParams(char* tok[], int ntoks) // // Input: tok[] = array of string tokens // ntoks = number of tokens // Output: returns error code // Purpose: reads climate/temperature parameters from input line of data // // Format of data can be // TIMESERIES name // FILE name // WINDSPEED MONTHLY v1 v2 ... v12 // WINDSPEED FILE // SNOWMELT v1 v2 ... v6 // ADC IMPERV/PERV v1 v2 ... v10 // { int i, j, k; double x[6], y; DateTime aDate; // --- identify keyword k = findmatch(tok[0], TempKeyWords); if ( k < 0 ) return error_setInpError(ERR_KEYWORD, tok[0]); switch (k) { case 0: // Time series name // --- check that time series name exists if ( ntoks < 2 ) return error_setInpError(ERR_ITEMS, ""); i = project_findObject(TSERIES, tok[1]); if ( i < 0 ) return error_setInpError(ERR_NAME, tok[1]); // --- record the time series as being the data source for temperature Temp.dataSource = TSERIES_TEMP; Temp.tSeries = i; break; case 1: // Climate file // --- record file as being source of temperature data if ( ntoks < 2 ) return error_setInpError(ERR_ITEMS, ""); Temp.dataSource = FILE_TEMP; // --- save name and usage mode of external climate file Fclimate.mode = USE_FILE; sstrncpy(Fclimate.name, tok[1], MAXFNAME); // --- save starting date to read from file if one is provided Temp.fileStartDate = NO_DATE; if ( ntoks > 2 ) { if ( *tok[2] != '*') { if ( !datetime_strToDate(tok[2], &aDate) ) return error_setInpError(ERR_DATETIME, tok[2]); Temp.fileStartDate = aDate; } } break; case 2: // Wind speeds // --- check if wind speeds will be supplied from climate file if ( strcomp(tok[1], w_FILE) ) { Wind.type = FILE_WIND; } // --- otherwise read 12 monthly avg. wind speed values else { if ( ntoks < 14 ) return error_setInpError(ERR_ITEMS, ""); Wind.type = MONTHLY_WIND; for (i=0; i<12; i++) { if ( !getDouble(tok[i+2], &y) ) return error_setInpError(ERR_NUMBER, tok[i+2]); Wind.aws[i] = y; } } break; case 3: // Snowmelt params if ( ntoks < 7 ) return error_setInpError(ERR_ITEMS, ""); for (i=1; i<7; i++) { if ( !getDouble(tok[i], &x[i-1]) ) return error_setInpError(ERR_NUMBER, tok[i]); } // --- convert deg. C to deg. F for snowfall temperature if ( UnitSystem == SI ) x[0] = 9./5.*x[0] + 32.0; Snow.snotmp = x[0]; Snow.tipm = x[1]; Snow.rnm = x[2]; Temp.elev = x[3] / UCF(LENGTH); Temp.anglat = x[4]; Temp.dtlong = x[5] / 60.0; break; case 4: // Areal Depletion Curve data // --- check if data is for impervious or pervious areas if ( ntoks < 12 ) return error_setInpError(ERR_ITEMS, ""); if ( match(tok[1], w_IMPERV) ) i = 0; else if ( match(tok[1], w_PERV) ) i = 1; else return error_setInpError(ERR_KEYWORD, tok[1]); // --- read 10 fractional values for (j=0; j<10; j++) { if ( !getDouble(tok[j+2], &y) || y < 0.0 || y > 1.0 ) return error_setInpError(ERR_NUMBER, tok[j+2]); Snow.adc[i][j] = y; } break; } return 0; }
void runoff_readFromFile(void) // // Input: none // Output: none // Purpose: reads runoff results from Runoff Interface file for current time. // { int i, j; int nResults; // number of results per subcatch. int kount; // count of items read from file float tStep; // runoff time step (sec) TGroundwater* gw; // ptr. to Groundwater object // --- make sure not past end of file if ( Nsteps > MaxSteps ) { report_writeErrorMsg(ERR_RUNOFF_FILE_END, ""); return; } // --- replace old state with current one for all subcatchments for (j = 0; j < Nobjects[SUBCATCH]; j++) subcatch_setOldState(j); // --- read runoff time step kount = 0; kount += fread(&tStep, sizeof(float), 1, Frunoff.file); // --- compute number of results saved for each subcatchment nResults = MAX_SUBCATCH_RESULTS + Nobjects[POLLUT] - 1; // --- for each subcatchment for (j = 0; j < Nobjects[SUBCATCH]; j++) { // --- read vector of saved results kount += fread(SubcatchResults, sizeof(float), nResults, Frunoff.file); // --- extract hydrologic results, converting units where necessary // (results were saved to file in user's units) Subcatch[j].newSnowDepth = SubcatchResults[SUBCATCH_SNOWDEPTH] / UCF(RAINDEPTH); Subcatch[j].evapLoss = SubcatchResults[SUBCATCH_EVAP] / UCF(RAINFALL); Subcatch[j].infilLoss = SubcatchResults[SUBCATCH_INFIL] / UCF(RAINFALL); Subcatch[j].newRunoff = SubcatchResults[SUBCATCH_RUNOFF] / UCF(FLOW); gw = Subcatch[j].groundwater; if ( gw ) { gw->newFlow = SubcatchResults[SUBCATCH_GW_FLOW] / UCF(FLOW); gw->lowerDepth = Aquifer[gw->aquifer].bottomElev - (SubcatchResults[SUBCATCH_GW_ELEV] / UCF(LENGTH)); gw->theta = SubcatchResults[SUBCATCH_SOIL_MOIST]; } // --- extract water quality results for (i = 0; i < Nobjects[POLLUT]; i++) { Subcatch[j].newQual[i] = SubcatchResults[SUBCATCH_WASHOFF + i]; } } // --- report error if not enough values were read if ( kount < 1 + Nobjects[SUBCATCH] * nResults ) { report_writeErrorMsg(ERR_RUNOFF_FILE_READ, ""); return; } // --- update runoff time clock OldRunoffTime = NewRunoffTime; NewRunoffTime = OldRunoffTime + (double)(tStep)*1000.0; Nsteps++; }
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; }
void output_saveSubcatchResults(double reportTime, FILE* file) // // Input: reportTime = elapsed simulation time (millisec) // file = ptr. to binary output file // Output: none // Purpose: writes computed subcatchment results to binary file. // { int j; double f; double area; REAL4 totalArea = 0.0f; DateTime reportDate = getDateTime(reportTime); FILE *fptr; // --- dbf variables DBFHandle hDBF; char fieldName[128]; int n; double f1,f0; double value; int numFields; // --- update reported rainfall at each rain gage for ( j=0; j<Nobjects[GAGE]; j++ ) { gage_setReportRainfall(j, reportDate); } // --- find where current reporting time lies between latest runoff times f = (reportTime - OldRunoffTime) / (NewRunoffTime - OldRunoffTime); f1 = 1.0 - f; f0 = f; // --- write subcatchment results to file for ( j=0; j<Nobjects[SUBCATCH]; j++) { // --- retrieve interpolated results for reporting time & write to file subcatch_getResults(j, f, SubcatchResults); if ( Subcatch[j].rptFlag ) fwrite(SubcatchResults, sizeof(REAL4), NsubcatchResults, file); // --- update system-wide results area = Subcatch[j].area * UCF(LANDAREA); totalArea += (REAL4)area; SysResults[SYS_RAINFALL] += (REAL4)(SubcatchResults[SUBCATCH_RAINFALL] * area); SysResults[SYS_SNOWDEPTH] += (REAL4)(SubcatchResults[SUBCATCH_SNOWDEPTH] * area); SysResults[SYS_EVAP] += (REAL4)(SubcatchResults[SUBCATCH_EVAP] * area); if ( Subcatch[j].groundwater ) SysResults[SYS_EVAP] += (REAL4)(Subcatch[j].groundwater->evapLoss * UCF(EVAPRATE) * area); SysResults[SYS_INFIL] += (REAL4)(SubcatchResults[SUBCATCH_INFIL] * area); SysResults[SYS_RUNOFF] += (REAL4)SubcatchResults[SUBCATCH_RUNOFF]; } // --- normalize system-wide results to catchment area if ( UnitSystem == SI ) f = (5./9.) * (Temp.ta - 32.0); else f = Temp.ta; SysResults[SYS_TEMPERATURE] = (REAL4)f; SysResults[SYS_EVAP] /= totalArea; SysResults[SYS_RAINFALL] /= totalArea; SysResults[SYS_SNOWDEPTH] /= totalArea; SysResults[SYS_INFIL] /= totalArea; // --- open DBF hDBF = DBFOpen(F2Dmesh.name, "r+b"); if( hDBF == NULL ) { //TODO //printf( "DBFOpen(%s,\"rb+\") failed.\n", argv[1] ); //exit( 2 ); } // --- create new field name n=sprintf (fieldName, "h_%07.0f", (reportTime / 1000.f)); if( DBFAddField( hDBF, fieldName, FTDouble, 12, 6 ) == -1 ) { //TODO //printf( "DBFAddField(%s,FTDouble,%d,%d) failed.\n", fieldName, 12, 3 ); //exit( 4 ); } n=sprintf (fieldName, "V_%07.0f", (reportTime / 1000.f)); if( DBFAddField( hDBF, fieldName, FTDouble, 12, 6 ) == -1 ) { //TODO //printf( "DBFAddField(%s,FTDouble,%d,%d) failed.\n", fieldName, 12, 3 ); //exit( 4 ); } // --- number of existing fields numFields = DBFGetFieldCount( hDBF ); // --- write subcatchment results to file for ( j=0; j<Nobjects[SUBCATCH]; j++) { if (Subcatch[j].isStreet) { value = ( f1 * Subcatch[j].oldGlobalDepth + f0 * Subcatch[j].newGlobalDepth ) * UCF(LENGTH); //Write value DBFWriteDoubleAttribute(hDBF, Subcatch[j].dbf_record, numFields - 2, value ); value = ( f1 * Subcatch[j].oldVel + f0 * Subcatch[j].newVel ) * UCF(LENGTH); //Write value DBFWriteDoubleAttribute(hDBF, Subcatch[j].dbf_record, numFields - 1, value ); } } //CLose DBFClose( hDBF ); // --- create file to print outflow fptr = fopen(F2Doutflow.name, "a+"); if (fptr == NULL) { printf("ERROR: Impossible to create Outflow.txt\n"); } else { fprintf(fptr, "%12.3f %12.3f\n", (reportTime / 1000.f), M2DControl.totalOutflow); fclose(fptr); } }
double massbal_getQualError() // // Input: none // Output: none // Purpose: computes water quality routing mass balance error. // { int p; double maxQualError = 0.0; double totalInflow; double totalOutflow; double cf; // --- analyze each pollutant for (p = 0; p < Nobjects[POLLUT]; p++) { // --- get final mass stored in nodes and links QualTotals[p].finalStorage += massbal_getStoredMass(p); //(5.1.008) // --- compute % difference between total inflow and outflow totalInflow = QualTotals[p].dwInflow + QualTotals[p].wwInflow + QualTotals[p].gwInflow + QualTotals[p].iiInflow + QualTotals[p].exInflow + QualTotals[p].initStorage; totalOutflow = QualTotals[p].flooding + QualTotals[p].outflow + QualTotals[p].reacted + QualTotals[p].seepLoss + //(5.1.008) QualTotals[p].finalStorage; QualTotals[p].pctError = 0.0; if ( fabs(totalInflow - totalOutflow) < 0.001 ) { QualTotals[p].pctError = TINY; } else if ( totalInflow > 0.0 ) { QualTotals[p].pctError = 100.0 * (1.0 - totalOutflow / totalInflow); } else if ( totalOutflow > 0.0 ) { QualTotals[p].pctError = 100.0 * (totalInflow / totalOutflow - 1.0); } // --- update max. error among all pollutants if ( fabs(QualTotals[p].pctError) > fabs(maxQualError) ) { maxQualError = QualTotals[p].pctError; } // --- convert totals to reporting units (lbs, kg, or Log(Count)) cf = LperFT3; if ( Pollut[p].units == COUNT ) { QualTotals[p].dwInflow = LOG10(cf * QualTotals[p].dwInflow); QualTotals[p].wwInflow = LOG10(cf * QualTotals[p].wwInflow); QualTotals[p].gwInflow = LOG10(cf * QualTotals[p].gwInflow); QualTotals[p].iiInflow = LOG10(cf * QualTotals[p].iiInflow); QualTotals[p].exInflow = LOG10(cf * QualTotals[p].exInflow); QualTotals[p].flooding = LOG10(cf * QualTotals[p].flooding); QualTotals[p].outflow = LOG10(cf * QualTotals[p].outflow); QualTotals[p].reacted = LOG10(cf * QualTotals[p].reacted); QualTotals[p].seepLoss = LOG10(cf * QualTotals[p].seepLoss); //(5.1.008) QualTotals[p].initStorage = LOG10(cf * QualTotals[p].initStorage); QualTotals[p].finalStorage = LOG10(cf * QualTotals[p].finalStorage); } else { cf = cf * UCF(MASS); if ( Pollut[p].units == UG ) cf /= 1000.0; QualTotals[p].dwInflow *= cf; QualTotals[p].wwInflow *= cf; QualTotals[p].gwInflow *= cf; QualTotals[p].iiInflow *= cf; QualTotals[p].exInflow *= cf; QualTotals[p].flooding *= cf; QualTotals[p].outflow *= cf; QualTotals[p].reacted *= cf; QualTotals[p].seepLoss *= cf; QualTotals[p].initStorage *= cf; QualTotals[p].finalStorage *= cf; } } QualError = maxQualError; return maxQualError; }
int subcatch_readSubareaParams(char* tok[], int ntoks) // // Input: tok[] = array of string tokens // ntoks = number of tokens // Output: returns an error code // Purpose: reads subcatchment's subarea parameters from a tokenized // line of input data. // // Data has format: // Subcatch Imperv_N Perv_N Imperv_S Perv_S PctZero RouteTo (PctRouted) // { int i, j, k, m; double x[7]; // --- check for enough tokens if ( ntoks < 7 ) return error_setInpError(ERR_ITEMS, ""); // --- check that named subcatch exists j = project_findObject(SUBCATCH, tok[0]); if ( j < 0 ) return error_setInpError(ERR_NAME, tok[0]); // --- read in Mannings n, depression storage, & PctZero values for (i = 0; i < 5; i++) { if ( ! getDouble(tok[i+1], &x[i]) || x[i] < 0.0 ) return error_setInpError(ERR_NAME, tok[i+1]); } // --- check for valid runoff routing keyword m = findmatch(tok[6], RunoffRoutingWords); if ( m < 0 ) return error_setInpError(ERR_KEYWORD, tok[6]); // --- get percent routed parameter if present (default is 100) x[5] = m; x[6] = 1.0; if ( ntoks >= 8 ) { if ( ! getDouble(tok[7], &x[6]) || x[6] < 0.0 || x[6] > 100.0 ) return error_setInpError(ERR_NUMBER, tok[7]); x[6] /= 100.0; } // --- assign input values to each type of subarea Subcatch[j].subArea[IMPERV0].N = x[0]; Subcatch[j].subArea[IMPERV1].N = x[0]; Subcatch[j].subArea[PERV].N = x[1]; Subcatch[j].subArea[IMPERV0].dStore = 0.0; Subcatch[j].subArea[IMPERV1].dStore = x[2] / UCF(RAINDEPTH); Subcatch[j].subArea[PERV].dStore = x[3] / UCF(RAINDEPTH); Subcatch[j].subArea[IMPERV0].fArea = Subcatch[j].fracImperv * x[4] / 100.0; Subcatch[j].subArea[IMPERV1].fArea = Subcatch[j].fracImperv * (1.0 - x[4] / 100.0); Subcatch[j].subArea[PERV].fArea = (1.0 - Subcatch[j].fracImperv); // --- assume that all runoff from each subarea goes to subcatch outlet for (i = IMPERV0; i <= PERV; i++) { Subcatch[j].subArea[i].routeTo = TO_OUTLET; Subcatch[j].subArea[i].fOutlet = 1.0; } // --- modify routing if pervious runoff routed to impervious area // (fOutlet is the fraction of runoff not routed) k = (int)x[5]; if ( Subcatch[j].fracImperv == 0.0 || Subcatch[j].fracImperv == 1.0 ) k = TO_OUTLET; if ( k == TO_IMPERV && Subcatch[j].fracImperv ) { Subcatch[j].subArea[PERV].routeTo = k; Subcatch[j].subArea[PERV].fOutlet = 1.0 - x[6]; } // --- modify routing if impervious runoff routed to pervious area if ( k == TO_PERV ) { Subcatch[j].subArea[IMPERV0].routeTo = k; Subcatch[j].subArea[IMPERV1].routeTo = k; Subcatch[j].subArea[IMPERV0].fOutlet = 1.0 - x[6]; Subcatch[j].subArea[IMPERV1].fOutlet = 1.0 - x[6]; } return 0; }
void subcatch_getResults(int j, double f, float x[]) // // Input: j = subcatchment index // f = weighting factor // Output: x = array of results // Purpose: computes wtd. combination of old and new subcatchment results. // { int p; // pollutant index int k; // rain gage index double f1 = 1.0 - f; double z; double runoff; TGroundwater* gw; // ptr. to groundwater object // --- retrieve rainfall for current report period k = Subcatch[j].gage; if ( k >= 0 ) x[SUBCATCH_RAINFALL] = (float)Gage[k].reportRainfall; else x[SUBCATCH_RAINFALL] = 0.0f; // --- retrieve snow depth z = ( f1 * Subcatch[j].oldSnowDepth + f * Subcatch[j].newSnowDepth ) * UCF(RAINDEPTH); x[SUBCATCH_SNOWDEPTH] = (float)z; // --- retrieve runoff and losses x[SUBCATCH_EVAP] = (float)(Subcatch[j].evapLoss * UCF(EVAPRATE)); x[SUBCATCH_INFIL] = (float)(Subcatch[j].infilLoss * UCF(RAINFALL)); runoff = f1 * Subcatch[j].oldRunoff + f * Subcatch[j].newRunoff; //// Following code segement added to release 5.1.008. //// //(5.1.008) //// // --- add any LID drain flow to reported runoff if ( Subcatch[j].lidArea > 0.0 ) { runoff += f1 * lid_getDrainFlow(j, PREVIOUS) + f * lid_getDrainFlow(j, CURRENT); } //// // --- if runoff is really small, report it as zero if ( runoff < MIN_RUNOFF * Subcatch[j].area ) runoff = 0.0; //(5.1.008) x[SUBCATCH_RUNOFF] = (float)(runoff * UCF(FLOW)); // --- retrieve groundwater results gw = Subcatch[j].groundwater; if ( gw ) { z = (f1 * gw->oldFlow + f * gw->newFlow) * Subcatch[j].area * UCF(FLOW); x[SUBCATCH_GW_FLOW] = (float)z; z = (Aquifer[gw->aquifer].bottomElev + gw->lowerDepth) * UCF(LENGTH); x[SUBCATCH_GW_ELEV] = (float)z; z = gw->theta; x[SUBCATCH_SOIL_MOIST] = (float)z; } else { x[SUBCATCH_GW_FLOW] = 0.0f; x[SUBCATCH_GW_ELEV] = 0.0f; x[SUBCATCH_SOIL_MOIST] = 0.0f; } // --- retrieve pollutant washoff if ( !IgnoreQuality ) for (p = 0; p < Nobjects[POLLUT]; p++ ) { if ( runoff == 0.0 ) z = 0.0; else z = f1 * Subcatch[j].oldQual[p] + f * Subcatch[j].newQual[p]; x[SUBCATCH_WASHOFF+p] = (float)z; } }
int subcatch_readParams(int j, char* tok[], int ntoks) // // Input: j = subcatchment index // tok[] = array of string tokens // ntoks = number of tokens // Output: returns an error code // Purpose: reads subcatchment parameters from a tokenized line of input data. // // Data has format: // Name RainGage Outlet Area %Imperv Width Slope CurbLength Snowpack // { int i, k, m; char* id; double x[9]; // --- check for enough tokens if ( ntoks < 8 ) return error_setInpError(ERR_ITEMS, ""); // --- check that named subcatch exists id = project_findID(SUBCATCH, tok[0]); if ( id == NULL ) return error_setInpError(ERR_NAME, tok[0]); // --- check that rain gage exists k = project_findObject(GAGE, tok[1]); if ( k < 0 ) return error_setInpError(ERR_NAME, tok[1]); x[0] = k; // --- check that outlet node or subcatch exists m = project_findObject(NODE, tok[2]); x[1] = m; m = project_findObject(SUBCATCH, tok[2]); x[2] = m; if ( x[1] < 0.0 && x[2] < 0.0 ) return error_setInpError(ERR_NAME, tok[2]); // --- read area, %imperv, width, slope, & curb length for ( i = 3; i < 8; i++) { if ( ! getDouble(tok[i], &x[i]) || x[i] < 0.0 ) return error_setInpError(ERR_NUMBER, tok[i]); } // --- if snowmelt object named, check that it exists x[8] = -1; if ( ntoks > 8 ) { k = project_findObject(SNOWMELT, tok[8]); if ( k < 0 ) return error_setInpError(ERR_NAME, tok[8]); x[8] = k; } // --- assign input values to subcatch's properties Subcatch[j].ID = id; Subcatch[j].gage = (int)x[0]; Subcatch[j].outNode = (int)x[1]; Subcatch[j].outSubcatch = (int)x[2]; Subcatch[j].area = x[3] / UCF(LANDAREA); Subcatch[j].fracImperv = x[4] / 100.0; Subcatch[j].width = x[5] / UCF(LENGTH); Subcatch[j].slope = x[6] / 100.0; Subcatch[j].curbLength = x[7]; // --- create the snow pack object if it hasn't already been created if ( x[8] >= 0 ) { if ( !snow_createSnowpack(j, (int)x[8]) ) return error_setInpError(ERR_MEMORY, ""); } return 0; }
double massbal_getQualError() // // Input: none // Output: none // Purpose: computes water quality routing mass balance error. // { int j, p; double maxQualError = 0.0; double finalStorage; double totalInflow; double totalOutflow; double cf; // --- analyze each pollutant for (p = 0; p < Nobjects[POLLUT]; p++) { // --- get final mass stored in nodes and links finalStorage = 0.0; for (j = 0; j < Nobjects[NODE]; j++) { finalStorage += Node[j].newVolume * Node[j].newQual[p]; } for (j = 0; j < Nobjects[LINK]; j++) { finalStorage += Link[j].newVolume * Link[j].newQual[p]; } QualTotals[p].finalStorage = finalStorage; // --- compute % difference between total inflow and outflow totalInflow = QualTotals[p].dwInflow + QualTotals[p].wwInflow + QualTotals[p].gwInflow + QualTotals[p].iiInflow + QualTotals[p].exInflow + QualTotals[p].initStorage; totalOutflow = QualTotals[p].outflow + QualTotals[p].pumpedVol + finalStorage; QualTotals[p].internalOutflow = 0.0; if ( fabs(totalInflow - totalOutflow) < 0.001 ) { QualTotals[p].internalOutflow = TINY; } else if ( totalInflow > 0.0 ) { QualTotals[p].internalOutflow = 100.0 * (1.0 - totalOutflow / totalInflow); } else if ( totalOutflow > 0.0 ) { QualTotals[p].internalOutflow = 100.0 * (totalInflow / totalOutflow - 1.0); } // --- update max. error among all pollutants if ( fabs(QualTotals[p].internalOutflow) > fabs(maxQualError) ) { maxQualError = QualTotals[p].internalOutflow; } // --- convert totals to reporting units (lbs, kg, or Log(Count)) cf = LperFT3; if ( Pollut[p].units == COUNT ) { QualTotals[p].dwInflow = LOG10(cf * QualTotals[p].dwInflow); QualTotals[p].wwInflow = LOG10(cf * QualTotals[p].wwInflow); QualTotals[p].gwInflow = LOG10(cf * QualTotals[p].gwInflow); QualTotals[p].iiInflow = LOG10(cf * QualTotals[p].iiInflow); QualTotals[p].exInflow = LOG10(cf * QualTotals[p].exInflow); QualTotals[p].outflow = LOG10(cf * QualTotals[p].outflow); QualTotals[p].pumpedVol = LOG10(cf * QualTotals[p].pumpedVol); QualTotals[p].initStorage = LOG10(cf * QualTotals[p].initStorage); QualTotals[p].finalStorage = LOG10(cf * QualTotals[p].finalStorage); } else { cf = cf * UCF(MASS); if ( Pollut[p].units == UG ) cf /= 1000.0; QualTotals[p].dwInflow *= cf; QualTotals[p].wwInflow *= cf; QualTotals[p].gwInflow *= cf; QualTotals[p].iiInflow *= cf; QualTotals[p].exInflow *= cf; QualTotals[p].outflow *= cf; QualTotals[p].pumpedVol *= cf; QualTotals[p].initStorage *= cf; QualTotals[p].finalStorage *= cf; } } QualError = maxQualError; return maxQualError; }
int evaluatePremise(struct TPremise* p, DateTime theDate, DateTime theTime, DateTime elapsedTime, double tStep) // // Input: p = a control rule premise condition // theDate = the current simulation date // theTime = the current simulation time of day // elpasedTime = decimal days since the start of the simulation // tStep = current time step (days) //(5.0.013 - LR) // Output: returns TRUE if the condition is true or FALSE otherwise // Purpose: evaluates the truth of a control rule premise condition. // { int i = p->node; int j = p->link; double head; switch ( p->attribute ) { case r_TIME: return checkTimeValue(p, elapsedTime, elapsedTime + tStep); case r_DATE: return checkValue(p, theDate); case r_CLOCKTIME: return checkTimeValue(p, theTime, theTime + tStep); case r_DAY: //(5.0.014 - LR) return checkValue(p, datetime_dayOfWeek(theDate)); //(5.0.014 - LR) case r_MONTH: //(5.0.014 - LR) return checkValue(p, datetime_monthOfYear(theDate)); //(5.0.014 - LR) case r_STATUS: if ( j < 0 || Link[j].type != PUMP ) return FALSE; else return checkValue(p, Link[j].setting); case r_SETTING: if ( j < 0 || (Link[j].type != ORIFICE && Link[j].type != WEIR) ) return FALSE; else return checkValue(p, Link[j].setting); case r_FLOW: if ( j < 0 ) return FALSE; else return checkValue(p, Link[j].direction*Link[j].newFlow*UCF(FLOW));//(5.0.019 - LR) case r_DEPTH: if ( j >= 0 ) return checkValue(p, Link[j].newDepth*UCF(LENGTH)); else if ( i >= 0 ) return checkValue(p, Node[i].newDepth*UCF(LENGTH)); else return FALSE; case r_HEAD: if ( i < 0 ) return FALSE; head = (Node[i].newDepth + Node[i].invertElev) * UCF(LENGTH); return checkValue(p, head); case r_INFLOW: if ( i < 0 ) return FALSE; else return checkValue(p, Node[i].newLatFlow*UCF(FLOW)); default: return FALSE; } }
void output_saveSubcatchResults(Project* project, double reportTime, FILE* file) // // Input: reportTime = elapsed simulation time (millisec) // file = ptr. to binary output file // Output: none // Purpose: writes computed subcatchment results to binary file. // { int j; double f; double area; REAL4 totalArea = 0.0f; DateTime reportDate = getDateTime(project,reportTime); // --- update reported rainfall at each rain gage for ( j=0; j<project->Nobjects[GAGE]; j++ ) { gage_setReportRainfall(project,j, reportDate); } // --- find where current reporting time lies between latest runoff times f = (reportTime - project->OldRunoffTime) / (project->NewRunoffTime - project->OldRunoffTime); // --- write subcatchment results to file for ( j=0; j<project->Nobjects[SUBCATCH]; j++) { // --- retrieve interpolated results for reporting time & write to file subcatch_getResults(project, j, f, project->SubcatchResults); if ( project->Subcatch[j].rptFlag ) fwrite(project->SubcatchResults, sizeof(REAL4), project->NsubcatchResults, file); // --- update system-wide results area = project->Subcatch[j].area * UCF(project,LANDAREA); totalArea += (REAL4)area; project->SysResults[SYS_RAINFALL] += (REAL4)(project->SubcatchResults[SUBCATCH_RAINFALL] * area); project->SysResults[SYS_SNOWDEPTH] += (REAL4)(project->SubcatchResults[SUBCATCH_SNOWDEPTH] * area); project->SysResults[SYS_EVAP] += (REAL4)(project->SubcatchResults[SUBCATCH_EVAP] * area); if ( project->Subcatch[j].groundwater ) project->SysResults[SYS_EVAP] += (REAL4)(project->Subcatch[j].groundwater->evapLoss * UCF(project,EVAPRATE) * area); project->SysResults[SYS_INFIL] += (REAL4)(project->SubcatchResults[SUBCATCH_INFIL] * area); project->SysResults[SYS_RUNOFF] += (REAL4)project->SubcatchResults[SUBCATCH_RUNOFF]; } // --- normalize system-wide results to catchment area if ( project->UnitSystem == SI ) f = (5./9.) * (project->Temp.ta - 32.0); else f = project->Temp.ta; project->SysResults[SYS_TEMPERATURE] = (REAL4)f; f = project->Evap.rate * UCF(project,EVAPRATE); //(5.1.010) project->SysResults[SYS_PET] = (REAL4)f; //(5.1.010) if ( totalArea > 0.0 ) //(5.1.008) { project->SysResults[SYS_EVAP] /= totalArea; project->SysResults[SYS_RAINFALL] /= totalArea; project->SysResults[SYS_SNOWDEPTH] /= totalArea; project->SysResults[SYS_INFIL] /= totalArea; } }
void getRainfall(DateTime currentDate) // // Input: currentDate = current calendar date/time // Output: none // Purpose: determines rainfall at current RDII processing date. // // { int j; // rain gage index int i; // past rainfall index int month; // month of current date int gageInterval; // gage recording interval (sec) float rainfall; // rainfall volume (inches or mm) DateTime gageDate; // calendar date for rain gage // --- examine each rain gage for (j = 0; j < Nobjects[GAGE]; j++) { // --- repeat until gage's date reaches or exceeds current date if ( Gage[j].isUsed == FALSE ) continue; while ( GageData[j].gageDate < currentDate ) { // --- get rainfall volume over gage's recording interval // at gage'a current date (in original depth units) gageDate = GageData[j].gageDate; gageInterval = Gage[j].rainInterval; gage_setState(j, gageDate); rainfall = Gage[j].rainfall * (float)gageInterval / 3600.0; // --- if rainfall occurs if ( rainfall > 0.0 ) { // --- if previous dry period long enough then begin // new RDII event with time period index set to 0 ////////////////////////////////////////////////////////////////////////////// // New RDII event occurs when dry period > base of longest UH. (LR - 9/19/06) ////////////////////////////////////////////////////////////////////////////// //if ( GageData[j].drySeconds >= RDII_MIT ) if ( GageData[j].drySeconds >= gageInterval * GageData[j].maxPeriods ) { for (i=0; i<GageData[j].maxPeriods; i++) { GageData[j].pastRain[i] = 0.0; } GageData[j].period = 0; } GageData[j].drySeconds = 0; GageData[j].hasPastRain = TRUE; // --- update count of total rainfall volume (ft3) TotalRainVol += rainfall / UCF(RAINDEPTH) * GageData[j].area; } // --- if no rainfall, update duration of dry period else { GageData[j].drySeconds += gageInterval; if ( GageData[j].drySeconds >= gageInterval * GageData[j].maxPeriods ) { GageData[j].hasPastRain = FALSE; } ////////////////////////// //// Added (LR - 9/19/06) ////////////////////////// else GageData[j].hasPastRain = TRUE; } // --- add rainfall to list of past values, wrapping // array index if necessary if ( GageData[j].period < GageData[j].maxPeriods ) { i = GageData[j].period; } else i = 0; GageData[j].pastRain[i] = rainfall; month = datetime_monthOfYear(currentDate) - 1; GageData[j].pastMonth[i] = (char)month; GageData[j].period = i + 1; // --- advance rain gage's date by gage recording interval GageData[j].gageDate = datetime_addSeconds(gageDate, gageInterval); } } }
void project_validate() // // Input: none // Output: none // Purpose: checks validity of project data. // { int i; int j; int err; // --- validate Curves and TimeSeries for ( i=0; i<Nobjects[CURVE]; i++ ) { err = table_validate(&Curve[i]); if ( err ) report_writeErrorMsg(ERR_CURVE_SEQUENCE, Curve[i].ID); } for ( i=0; i<Nobjects[TSERIES]; i++ ) { err = table_validate(&Tseries[i]); if ( err ) report_writeTseriesErrorMsg(err, &Tseries[i]); } // --- validate hydrology objects // (NOTE: order is important !!!!) climate_validate(); lid_validate(); if ( Nobjects[SNOWMELT] == 0 ) IgnoreSnowmelt = TRUE; if ( Nobjects[AQUIFER] == 0 ) IgnoreGwater = TRUE; for ( i=0; i<Nobjects[GAGE]; i++ ) gage_validate(i); for ( i=0; i<Nobjects[AQUIFER]; i++ ) gwater_validateAquifer(i); for ( i=0; i<Nobjects[SUBCATCH]; i++ ) subcatch_validate(i); for ( i=0; i<Nobjects[SNOWMELT]; i++ ) snow_validateSnowmelt(i); // --- compute geometry tables for each shape curve j = 0; for ( i=0; i<Nobjects[CURVE]; i++ ) { if ( Curve[i].curveType == SHAPE_CURVE ) { Curve[i].refersTo = j; Shape[j].curve = i; if ( !shape_validate(&Shape[j], &Curve[i]) ) report_writeErrorMsg(ERR_CURVE_SEQUENCE, Curve[i].ID); j++; } } // --- validate links before nodes, since the latter can // result in adjustment of node depths for ( i=0; i<Nobjects[NODE]; i++) Node[i].oldDepth = Node[i].fullDepth; for ( i=0; i<Nobjects[LINK]; i++) link_validate(i); for ( i=0; i<Nobjects[NODE]; i++) node_validate(i); // --- adjust time steps if necessary if ( DryStep < WetStep ) { report_writeWarningMsg(WARN06, ""); DryStep = WetStep; } if ( RouteStep > (double)WetStep ) { report_writeWarningMsg(WARN07, ""); RouteStep = WetStep; } // --- adjust individual reporting flags to match global reporting flag if ( RptFlags.subcatchments == ALL ) for (i=0; i<Nobjects[SUBCATCH]; i++) Subcatch[i].rptFlag = TRUE; if ( RptFlags.nodes == ALL ) for (i=0; i<Nobjects[NODE]; i++) Node[i].rptFlag = TRUE; if ( RptFlags.links == ALL ) for (i=0; i<Nobjects[LINK]; i++) Link[i].rptFlag = TRUE; // --- adjust DYNWAVE options if ( MinSurfArea == 0.0 ) MinSurfArea = DEFAULT_SURFAREA; else MinSurfArea /= UCF(LENGTH) * UCF(LENGTH); if ( HeadTol == 0.0 ) HeadTol = DEFAULT_HEADTOL; else HeadTol /= UCF(LENGTH); if ( MaxTrials == 0 ) MaxTrials = DEFAULT_MAXTRIALS; }
int output_open(Project* project) // // Input: none // Output: returns an error code // Purpose: writes basic project data to binary output file. // { int j; int m; INT4 k; REAL4 x; REAL8 z; // --- open binary output file output_openOutFile(project); if ( project->ErrorCode ) return project->ErrorCode; // --- ignore pollutants if no water quality analsis performed if ( project->IgnoreQuality ) project->NumPolluts = 0; else project->NumPolluts = project->Nobjects[POLLUT]; // --- subcatchment results consist of Rainfall, Snowdepth, project->Evap, // Infil, Runoff, GW Flow, GW Elev, GW Sat, and Washoff project->NsubcatchResults = MAX_SUBCATCH_RESULTS - 1 + project->NumPolluts; // --- node results consist of Depth, Head, Volume, Lateral Inflow, // Total Inflow, Overflow and Quality project->NnodeResults = MAX_NODE_RESULTS - 1 + project->NumPolluts; // --- link results consist of Depth, Flow, Velocity, Froude No., // Capacity and Quality project->NlinkResults = MAX_LINK_RESULTS - 1 + project->NumPolluts; // --- get number of objects reported on project->NumSubcatch = 0; project->NumNodes = 0; project->NumLinks = 0; for (j=0; j<project->Nobjects[SUBCATCH]; j++) if (project->Subcatch[j].rptFlag) project->NumSubcatch++; for (j=0; j<project->Nobjects[NODE]; j++) if (project->Node[j].rptFlag) project->NumNodes++; for (j=0; j<project->Nobjects[LINK]; j++) if (project->Link[j].rptFlag) project->NumLinks++; project->BytesPerPeriod = sizeof(REAL8) + project->NumSubcatch * project->NsubcatchResults * sizeof(REAL4) + project->NumNodes * project->NnodeResults * sizeof(REAL4) + project->NumLinks * project->NlinkResults * sizeof(REAL4) + MAX_SYS_RESULTS * sizeof(REAL4); project->Nperiods = 0; project->SubcatchResults = NULL; project->NodeResults = NULL; project->LinkResults = NULL; project->SubcatchResults = (REAL4 *) calloc(project->NsubcatchResults, sizeof(REAL4)); project->NodeResults = (REAL4 *) calloc(project->NnodeResults, sizeof(REAL4)); project->LinkResults = (REAL4 *) calloc(project->NlinkResults, sizeof(REAL4)); if ( !project->SubcatchResults || !project->NodeResults || !project->LinkResults ) { report_writeErrorMsg(project,ERR_MEMORY, ""); return project->ErrorCode; } fseek(project->Fout.file, 0, SEEK_SET); k = MAGICNUMBER; fwrite(&k, sizeof(INT4), 1, project->Fout.file); // Magic number k = VERSION; fwrite(&k, sizeof(INT4), 1, project->Fout.file); // Version number k = project->FlowUnits; fwrite(&k, sizeof(INT4), 1, project->Fout.file); // Flow units k = project->NumSubcatch; fwrite(&k, sizeof(INT4), 1, project->Fout.file); // # subcatchments k = project->NumNodes; fwrite(&k, sizeof(INT4), 1, project->Fout.file); // # nodes k = project->NumLinks; fwrite(&k, sizeof(INT4), 1, project->Fout.file); // # links k = project->NumPolluts; fwrite(&k, sizeof(INT4), 1, project->Fout.file); // # pollutants // --- save ID names of subcatchments, nodes, links, & pollutants project->IDStartPos = ftell(project->Fout.file); for (j=0; j<project->Nobjects[SUBCATCH]; j++) { if ( project->Subcatch[j].rptFlag ) output_saveID(project->Subcatch[j].ID, project->Fout.file); } for (j=0; j<project->Nobjects[NODE]; j++) { if ( project->Node[j].rptFlag ) output_saveID(project->Node[j].ID, project->Fout.file); } for (j=0; j<project->Nobjects[LINK]; j++) { if ( project->Link[j].rptFlag ) output_saveID(project->Link[j].ID, project->Fout.file); } for (j=0; j<project->NumPolluts; j++) output_saveID(project->Pollut[j].ID, project->Fout.file); // --- save codes of pollutant concentration units for (j=0; j<project->NumPolluts; j++) { k = project->Pollut[j].units; fwrite(&k, sizeof(INT4), 1, project->Fout.file); } project->InputStartPos = ftell(project->Fout.file); // --- save subcatchment area k = 1; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = INPUT_AREA; fwrite(&k, sizeof(INT4), 1, project->Fout.file); for (j=0; j<project->Nobjects[SUBCATCH]; j++) { if ( !project->Subcatch[j].rptFlag ) continue; project->SubcatchResults[0] = (REAL4)(project->Subcatch[j].area * UCF(project,LANDAREA)); fwrite(&project->SubcatchResults[0], sizeof(REAL4), 1, project->Fout.file); } // --- save node type, invert, & max. depth k = 3; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = INPUT_TYPE_CODE; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = INPUT_INVERT; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = INPUT_MAX_DEPTH; fwrite(&k, sizeof(INT4), 1, project->Fout.file); for (j=0; j<project->Nobjects[NODE]; j++) { if ( !project->Node[j].rptFlag ) continue; k = project->Node[j].type; project->NodeResults[0] = (REAL4)(project->Node[j].invertElev * UCF(project,LENGTH)); project->NodeResults[1] = (REAL4)(project->Node[j].fullDepth * UCF(project,LENGTH)); fwrite(&k, sizeof(INT4), 1, project->Fout.file); fwrite(project->NodeResults, sizeof(REAL4), 2, project->Fout.file); } // --- save link type, offsets, max. depth, & length k = 5; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = INPUT_TYPE_CODE; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = INPUT_OFFSET; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = INPUT_OFFSET; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = INPUT_MAX_DEPTH; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = INPUT_LENGTH; fwrite(&k, sizeof(INT4), 1, project->Fout.file); for (j=0; j<project->Nobjects[LINK]; j++) { if ( !project->Link[j].rptFlag ) continue; k = project->Link[j].type; if ( k == PUMP ) { for (m=0; m<4; m++) project->LinkResults[m] = 0.0f; } else { project->LinkResults[0] = (REAL4)(project->Link[j].offset1 * UCF(project,LENGTH)); project->LinkResults[1] = (REAL4)(project->Link[j].offset2 * UCF(project,LENGTH)); if ( project->Link[j].direction < 0 ) { x = project->LinkResults[0]; project->LinkResults[0] = project->LinkResults[1]; project->LinkResults[1] = x; } if ( k == OUTLET ) project->LinkResults[2] = 0.0f; else project->LinkResults[2] = (REAL4)(project->Link[j].xsect.yFull * UCF(project,LENGTH)); if ( k == CONDUIT ) { m = project->Link[j].subIndex; project->LinkResults[3] = (REAL4)(project->Conduit[m].length * UCF(project,LENGTH)); } else project->LinkResults[3] = 0.0f; } fwrite(&k, sizeof(INT4), 1, project->Fout.file); fwrite(project->LinkResults, sizeof(REAL4), 4, project->Fout.file); } // --- save number & codes of subcatchment result variables k = project->NsubcatchResults; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = SUBCATCH_RAINFALL; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = SUBCATCH_SNOWDEPTH; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = SUBCATCH_EVAP; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = SUBCATCH_INFIL; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = SUBCATCH_RUNOFF; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = SUBCATCH_GW_FLOW; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = SUBCATCH_GW_ELEV; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = SUBCATCH_SOIL_MOIST; fwrite(&k, sizeof(INT4), 1, project->Fout.file); for (j=0; j<project->NumPolluts; j++) { k = SUBCATCH_WASHOFF + j; fwrite(&k, sizeof(INT4), 1, project->Fout.file); } // --- save number & codes of node result variables k = project->NnodeResults; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = NODE_DEPTH; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = NODE_HEAD; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = NODE_VOLUME; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = NODE_LATFLOW; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = NODE_INFLOW; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = NODE_OVERFLOW; fwrite(&k, sizeof(INT4), 1, project->Fout.file); for (j=0; j<project->NumPolluts; j++) { k = NODE_QUAL + j; fwrite(&k, sizeof(INT4), 1, project->Fout.file); } // --- save number & codes of link result variables k = project->NlinkResults; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = LINK_FLOW; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = LINK_DEPTH; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = LINK_VELOCITY; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = LINK_VOLUME; fwrite(&k, sizeof(INT4), 1, project->Fout.file); k = LINK_CAPACITY; fwrite(&k, sizeof(INT4), 1, project->Fout.file); for (j=0; j<project->NumPolluts; j++) { k = LINK_QUAL + j; fwrite(&k, sizeof(INT4), 1, project->Fout.file); } // --- save number & codes of system result variables k = MAX_SYS_RESULTS; fwrite(&k, sizeof(INT4), 1, project->Fout.file); for (k=0; k<MAX_SYS_RESULTS; k++) fwrite(&k, sizeof(INT4), 1, project->Fout.file); // --- save starting report date & report step // (if reporting start date > simulation start date then // make saved starting report date one reporting period // prior to the date of the first reported result) z = (double)project->ReportStep/86400.0; if ( project->StartDateTime + z > project->ReportStart ) z = project->StartDateTime; else { z = floor((project->ReportStart - project->StartDateTime)/z) - 1.0; z = project->StartDateTime + z*(double)project->ReportStep/86400.0; } fwrite(&z, sizeof(REAL8), 1, project->Fout.file); k = project->ReportStep; if ( fwrite(&k, sizeof(INT4), 1, project->Fout.file) < 1) { report_writeErrorMsg(project,ERR_OUT_WRITE, ""); return project->ErrorCode; } project->OutputStartPos = ftell(project->Fout.file); if ( project->Fout.mode == SCRATCH_FILE ) output_checkFileSize(project); return project->ErrorCode; }