void updatePondedQual(int j, double wRunon[], double pondedQual[], double tStep) { int p; double c; double vIn; double wPpt, wInfil, w1; double bmpRemoval; int isDry; // --- total inflow volume vIn = Vrain + Vrunon; // --- for dry conditions if ( Vponded + vIn == 0.0 ) isDry = 1; else isDry = 0; // --- analyze each pollutant for (p = 0; p < Nobjects[POLLUT]; p++) { // --- update mass balance for direct deposition wPpt = Pollut[p].pptConcen * LperFT3 * Vrain; //(5.1.006 - MT) massbal_updateLoadingTotals(DEPOSITION_LOAD, p, wPpt * Pollut[p].mcf); // --- surface is dry and has no inflow -- add any remaining mass // to overall mass balance's FINAL_LOAD category if ( isDry ) { massbal_updateLoadingTotals(FINAL_LOAD, p, pondedQual[p] * Pollut[p].mcf); pondedQual[p] = 0.0; OutflowLoad[p] = 0.0; } else { // --- find concen. of ponded water w1 = pondedQual[p] + wPpt + wRunon[p]*tStep; c = w1 / (Vponded + vIn); // --- mass lost to infiltration wInfil = c * Vinfil; wInfil = MIN(wInfil, w1); massbal_updateLoadingTotals(INFIL_LOAD, p, wInfil * Pollut[p].mcf); w1 -= wInfil; // --- mass lost to outflow OutflowLoad[p] = MIN(w1, (c*Voutflow)); w1 -= OutflowLoad[p]; // --- reduce outflow load by average BMP removal bmpRemoval = landuse_getAvgBmpEffic(j, p) * OutflowLoad[p]; massbal_updateLoadingTotals(BMP_REMOVAL_LOAD, p, bmpRemoval*Pollut[p].mcf); OutflowLoad[p] -= bmpRemoval; // --- update ponded mass pondedQual[p] = c * subcatch_getDepth(j) * Subcatch[j].area; //(5.1.006) } } }
double massbal_getBuildup(int p) // // Input: p = pollutant index // Output: returns total pollutant buildup (lbs or kg) // Purpose: computes current total buildup of a pollutant over study area. // { int i, j; double load = 0.0; for (j=0; j<Nobjects[SUBCATCH]; j++) { for (i = 0; i < Nobjects[LANDUSE]; i++) { load += Subcatch[j].landFactor[i].buildup[p]; } load += Subcatch[j].pondedQual[p] * subcatch_getDepth(j) * Subcatch[j].area * Pollut[p].mcf; } return load; }
double subcatch_getRunoff(int j, double tStep) // // Input: j = subcatchment index // tStep = time step (sec) // Output: returns total runoff produced by subcatchment (ft/sec) // Purpose: Computes runoff & new storage depth for subcatchment. // // The 'runoff' value returned by this function is the total runoff // generated (in ft/sec) by the subcatchment before any internal // re-routing is applied. It is used to compute pollutant washoff. // // The 'outflow' value computed here (in cfs) is the surface runoff // that actually leaves the subcatchment after any LID controls are // applied and is saved to Subcatch[j].newRunoff. // { int i; // subarea index double nonLidArea; // non-LID portion of subcatch area (ft2) double area; // sub-area or subcatchment area (ft2) double netPrecip[3]; // subarea net precipitation (ft/sec) double vRain; // rainfall (+ snowfall) volume (ft3) double vRunon = 0.0; // runon volume from other areas (ft3) double vOutflow = 0.0; // runoff volume leaving subcatch (ft3) double runoff = 0.0; // total runoff flow on subcatch (cfs) double evapRate = 0.0; // potential evaporation rate (ft/sec) // --- initialize shared water balance variables Vevap = 0.0; Vpevap = 0.0; Vinfil = 0.0; Voutflow = 0.0; VlidIn = 0.0; VlidInfil = 0.0; VlidOut = 0.0; VlidDrain = 0.0; VlidReturn = 0.0; // --- find volume of inflow to non-LID portion of subcatchment as existing // ponded water + any runon volume from upstream areas; // rainfall and snowmelt will be added as each sub-area is analyzed nonLidArea = Subcatch[j].area - Subcatch[j].lidArea; vRunon = Subcatch[j].runon * tStep * nonLidArea; Vinflow = vRunon + subcatch_getDepth(j) * nonLidArea; //// Added to release 5.1.009. //// //(5.1.009) // --- find LID runon only if LID occupies full subcatchment if ( nonLidArea == 0.0 ) vRunon = Subcatch[j].runon * tStep * Subcatch[j].area; //// // --- get net precip. (rainfall + snowfall + snowmelt) on the 3 types // of subcatchment sub-areas and update Vinflow with it getNetPrecip(j, netPrecip, tStep); // --- find potential evaporation rate if ( Evap.dryOnly && Subcatch[j].rainfall > 0.0 ) evapRate = 0.0; else evapRate = Evap.rate; // --- examine each type of sub-area (impervious w/o depression storage, // impervious w/ depression storage, and pervious) if ( nonLidArea > 0.0 ) for (i = IMPERV0; i <= PERV; i++) { // --- get runoff from sub-area updating Vevap, Vpevap, // Vinfil & Voutflow) area = nonLidArea * Subcatch[j].subArea[i].fArea; Subcatch[j].subArea[i].runoff = getSubareaRunoff(j, i, area, netPrecip[i], evapRate, tStep); runoff += Subcatch[j].subArea[i].runoff * area; } // --- evaluate any LID treatment provided (updating Vevap, // Vpevap, VlidInfil, VlidIn, VlidOut, & VlidDrain) if ( Subcatch[j].lidArea > 0.0 ) { lid_getRunoff(j, tStep); } // --- update groundwater levels & flows if applicable if ( !IgnoreGwater && Subcatch[j].groundwater ) { gwater_getGroundwater(j, Vpevap, Vinfil, tStep); } // --- save subcatchment's total loss rates (ft/s) area = Subcatch[j].area; Subcatch[j].evapLoss = Vevap / tStep / area; Subcatch[j].infilLoss = (Vinfil + VlidInfil) / tStep / area; // --- find net surface runoff volume // (VlidDrain accounts for LID drain flows) vOutflow = Voutflow // runoff from all non-LID areas - VlidIn // runoff treated by LID units + VlidOut; // runoff from LID units Subcatch[j].newRunoff = vOutflow / tStep; // --- obtain external precip. volume (without any snowmelt) vRain = Subcatch[j].rainfall * tStep * area; // --- update the cumulative stats for this subcatchment stats_updateSubcatchStats(j, vRain, vRunon, Vevap, Vinfil + VlidInfil, vOutflow + VlidDrain, Subcatch[j].newRunoff + VlidDrain/tStep); // --- include this subcatchment's contribution to overall flow balance // only if its outlet is a drainage system node if ( Subcatch[j].outNode == -1 && Subcatch[j].outSubcatch != j ) { vOutflow = 0.0; } // --- update mass balances massbal_updateRunoffTotals(RUNOFF_RAINFALL, vRain); massbal_updateRunoffTotals(RUNOFF_EVAP, Vevap); massbal_updateRunoffTotals(RUNOFF_INFIL, Vinfil+VlidInfil); massbal_updateRunoffTotals(RUNOFF_RUNOFF, vOutflow); // --- return area-averaged runoff (ft/s) return runoff / area; }
double subcatch_getRunoff(int j, double tStep) // // Input: j = subcatchment index // tStep = time step (sec) // Output: returns total runoff produced by subcatchment (ft/sec) // Purpose: Computes runoff & new storage depth for subcatchment. // { int i; // subarea index double area; // portion of subcatchment area (ft2) double netPrecip[3]; // subarea net precipitation (ft/sec) double rainVol = 0.0; // rain volume (ft3) double evapVol = 0.0; // evaporation volume (ft3) double infilVol = 0.0; // infiltration volume (ft3) double outflowVol = 0.0; // runoff volume leaving subcatch (ft3) double outflow = 0.0; // runoff rate leaving subcatch (cfs) double runoff = 0.0; // total runoff rate on subcatch (ft/sec) double pervEvapVol = 0.0; // evaporation over pervious area (ft3) double evapRate = 0.0; // max. evaporation rate (ft/sec) // NOTE: The 'runoff' value returned by this function is the total runoff // generated (in ft/sec) by the subcatchment before any internal // re-routing is applied. It is used in the Exponential Washoff // function to compute pollutant washoff. The 'outflow' value // computed here (in cfs) is the runoff that actually leaves the // subcatchment (which can be reduced by internal re-routing and // LID controls) and is saved to Subcatch[j].newRunoff. // --- save current depth of ponded water over entire subcatchment Vponded = subcatch_getDepth(j) * Subcatch[j].area; // --- get net precipitation (rainfall + snowmelt) on subcatchment getNetPrecip(j, netPrecip, tStep); if ( Evap.dryOnly && Subcatch[j].rainfall > 0.0 ) evapRate = 0.0; else evapRate = Evap.rate; // --- initialize runoff rates outflow = 0.0; runoff = 0.0; // --- examine each type of sub-area for (i = IMPERV0; i <= PERV; i++) { // --- check that sub-area type exists area = (Subcatch[j].area - Subcatch[j].lidArea) * Subcatch[j].subArea[i].fArea; if ( area > 0.0 ) { // --- get runoff rate from sub-area getSubareaRunoff(j, i, netPrecip[i], evapRate, tStep); runoff += Subcatch[j].subArea[i].runoff * area; // --- update components of volumetric water balance (in ft3) //Subcatch[j].losses += Losses * area; rainVol += netPrecip[i] * tStep * area; outflow += Outflow * area; evapVol += Vevap * area; infilVol += Vinfil * area; // --- save evap losses from pervious area // (needed for groundwater modeling) if ( i == PERV ) pervEvapVol += Vevap * area; } } // --- evaluate LID treatment as if it were another type of sub-area // while updating outflow, evap volumes, & infil volumes if ( Subcatch[j].lidArea > 0.0 ) runoff += lid_getRunoff(j, &outflow, &evapVol, &pervEvapVol, &infilVol, tStep); // --- update groundwater levels & flows if applicable if (!IgnoreGwater && Subcatch[j].groundwater ) gwater_getGroundwater(j, pervEvapVol, infilVol, tStep); // --- save subcatchment's outflow (cfs) & total loss rates (ft/s) area = Subcatch[j].area; Subcatch[j].newRunoff = outflow; Subcatch[j].evapLoss = evapVol / tStep / area; Subcatch[j].infilLoss = infilVol / tStep / area; // --- save volumes (ft3) for use in pollutant washoff calculation Vrain = rainVol; Vevap = evapVol; Vinfil = infilVol; Voutflow = outflow * tStep; Vrunon = Subcatch[j].runon * tStep * area; // --- compute water flux volumes over the time step rainVol = Subcatch[j].rainfall * tStep * area; stats_updateSubcatchStats(j, rainVol, Vrunon, Vevap, Vinfil, Voutflow, outflow); // --- update system flow balance // (system outflow is 0 if outlet is another subcatch) outflowVol = Voutflow; if ( Subcatch[j].outNode == -1 && Subcatch[j].outSubcatch != j ) { outflowVol = 0.0; } massbal_updateRunoffTotals(rainVol, evapVol, infilVol, outflowVol); // --- return area-averaged runoff (ft/s) return runoff / area; }