void gwater_getGroundwater(int j, double evap, double infil, double tStep) // // Purpose: computes groundwater flow from subcatchment during current time step. // Input: j = subcatchment index // evap = surface evaporation volume consumed (ft3) // infil = surface infiltration volume (ft3) // tStep = time step (sec) // Output: none // { int n; // node exchanging groundwater double x[2]; // upper moisture content & lower depth double vUpper; // upper vol. available for percolation double nodeFlow; // max. possible GW flow from node double area; // total subcatchment area // --- save subcatchment's groundwater and aquifer objects to // shared variables GW = Subcatch[j].groundwater; if ( GW == NULL ) return; A = Aquifer[GW->aquifer]; // --- get fraction of total area that is pervious FracPerv = subcatch_getFracPerv(j); if ( FracPerv <= 0.0 ) return; area = Subcatch[j].area; // --- convert evap & infil volumes to rates evap = evap / (FracPerv*area) / tStep; //(5.0.021 - LR) infil = infil / (FracPerv*area) / tStep; //(5.0.021 - LR) Infil = infil; Tstep = tStep; // --- save max. and available evap rates to shared variables MaxEvap = Evap.rate; AvailEvap = MAX((MaxEvap - evap), 0.0); // --- save total depth & outlet node properties to shared variables TotalDepth = GW->surfElev - A.bottomElev; if ( TotalDepth <= 0.0 ) return; n = GW->node; // --- override node's invert if value was provided in the GW object if ( GW->nodeElev != MISSING ) Hstar = GW->nodeElev - A.bottomElev; else Hstar = Node[n].invertElev - A.bottomElev; if ( GW->fixedDepth > 0.0 ) Hsw = GW->fixedDepth + Node[n].invertElev - A.bottomElev; else Hsw = Node[n].newDepth + Node[n].invertElev - A.bottomElev; // --- store state variables in work vector x x[THETA] = GW->theta; x[LOWERDEPTH] = GW->lowerDepth; // --- set limits on upper perc vUpper = (TotalDepth - x[LOWERDEPTH]) * (x[THETA] - A.fieldCapacity); vUpper = MAX(0.0, vUpper); MaxUpperPerc = vUpper / tStep; // --- set limit on GW flow out of aquifer based on volume of lower zone MaxGWFlowPos = x[LOWERDEPTH]*A.porosity / tStep; // --- set limit on GW flow into aquifer from drainage system node // based on min. of capacity of upper zone and drainage system // inflow to the node MaxGWFlowNeg = (TotalDepth - x[LOWERDEPTH]) * (A.porosity - x[THETA]) / tStep; nodeFlow = (Node[n].inflow + Node[n].newVolume/tStep) / area; MaxGWFlowNeg = -MIN(MaxGWFlowNeg, nodeFlow); // --- integrate eqns. for d(Theta)/dt and d(LowerDepth)/dt // NOTE: ODE solver must have been initialized previously odesolve_integrate(x, 2, 0, tStep, GWTOL, tStep, getDxDt); // --- keep state variables within allowable bounds x[THETA] = MAX(x[THETA], A.wiltingPoint); if ( x[THETA] >= A.porosity ) { x[THETA] = A.porosity - XTOL; } x[LOWERDEPTH] = MAX(x[LOWERDEPTH], 0.0); if ( x[LOWERDEPTH] >= TotalDepth ) { x[LOWERDEPTH] = TotalDepth - XTOL; } // --- save new state values GW->theta = x[THETA]; GW->lowerDepth = x[LOWERDEPTH]; getFluxes(GW->theta, GW->lowerDepth); GW->oldFlow = GW->newFlow; GW->newFlow = GWFlow; //--- get limit on infiltration into upper zone GW->maxInfilVol = (TotalDepth - x[LOWERDEPTH])* (A.porosity - x[THETA])/ FracPerv; // --- update mass balance updateMassBal(area, tStep); }
void gwater_getGroundwater(Project* project, int j, double evap, double infil, double tStep) // // Purpose: computes groundwater flow from subcatchment during current time step. // Input: j = subcatchment index // evap = pervious surface evaporation volume consumed (ft3) // infil = surface infiltration volume (ft3) // tStep = time step (sec) // Output: none // // Note: local "area" variable was replaced with shared variable "project->Area". // //(5.1.008) { int n; // node exchanging groundwater double x[2]; // upper moisture content & lower depth double vUpper; // upper vol. available for percolation double nodeFlow; // max. possible project->GW flow from node // --- save subcatchment's groundwater and aquifer objects to // shared variables project->GW = project->Subcatch[j].groundwater; if ( project->GW == NULL ) return; project->LatFlowExpr = project->Subcatch[j].gwLatFlowExpr; //(5.1.007) project->DeepFlowExpr = project->Subcatch[j].gwDeepFlowExpr; //(5.1.007) project->A = project->Aquifer[project->GW->aquifer]; // --- get fraction of total area that is pervious project->FracPerv = subcatch_getFracPerv(project,j); if ( project->FracPerv <= 0.0 ) return; project->Area = project->Subcatch[j].area; // --- convert infiltration volume (ft3) to equivalent rate // over entire project->GW (subcatchment) area infil = infil / project->Area / tStep; project->Infil = infil; project->Tstep = tStep; // --- convert pervious surface evaporation already exerted (ft3) // to equivalent rate over entire project->GW (subcatchment) area evap = evap / project->Area / tStep; // --- convert max. surface evap rate (ft/sec) to a rate // that applies to project->GW evap (project->GW evap can only occur // through the pervious land surface area) project->MaxEvap = project->Evap.rate * project->FracPerv; // --- available subsurface evaporation is difference between max. // rate and pervious surface evap already exerted project->AvailEvap = MAX((project->MaxEvap - evap), 0.0); // --- save total depth & outlet node properties to shared variables project->TotalDepth = project->GW->surfElev - project->GW->bottomElev; if ( project->TotalDepth <= 0.0 ) return; n = project->GW->node; // --- establish min. water table height above aquifer bottom at which // project->GW flow can occur (override node's invert if a value was provided // in the project->GW object) if ( project->GW->nodeElev != MISSING ) project->Hstar = project->GW->nodeElev - project->GW->bottomElev; else project->Hstar = project->Node[n].invertElev - project->GW->bottomElev; // --- establish surface water height (relative to aquifer bottom) // for drainage system node connected to the project->GW aquifer if ( project->GW->fixedDepth > 0.0 ) { project->Hsw = project->GW->fixedDepth + project->Node[n].invertElev - project->GW->bottomElev; } else project->Hsw = project->Node[n].newDepth + project->Node[n].invertElev - project->GW->bottomElev; // --- store state variables (upper zone moisture content, lower zone // depth) in work vector x x[THETA] = project->GW->theta; x[LOWERDEPTH] = project->GW->lowerDepth; // --- set limit on percolation rate from upper to lower project->GW zone vUpper = (project->TotalDepth - x[LOWERDEPTH]) * (x[THETA] - project->A.fieldCapacity); vUpper = MAX(0.0, vUpper); project->MaxUpperPerc = vUpper / tStep; // --- set limit on project->GW flow out of aquifer based on volume of lower zone project->MaxGWFlowPos = x[LOWERDEPTH]*project->A.porosity / tStep; // --- set limit on project->GW flow into aquifer from drainage system node // based on min. of capacity of upper zone and drainage system // inflow to the node project->MaxGWFlowNeg = (project->TotalDepth - x[LOWERDEPTH]) * (project->A.porosity - x[THETA]) / tStep; nodeFlow = (project->Node[n].inflow + project->Node[n].newVolume/tStep) / project->Area; project->MaxGWFlowNeg = -MIN(project->MaxGWFlowNeg, nodeFlow); // --- integrate eqns. for d(project->Theta)/dt and d(LowerDepth)/dt // NOTE: ODE solver must have been initialized previously odesolve_integrate(project,x, 2, 0, tStep, GWTOL, tStep, getDxDt); // --- keep state variables within allowable bounds x[THETA] = MAX(x[THETA], project->A.wiltingPoint); if ( x[THETA] >= project->A.porosity ) { x[THETA] = project->A.porosity - XTOL; x[LOWERDEPTH] = project->TotalDepth - XTOL; } x[LOWERDEPTH] = MAX(x[LOWERDEPTH], 0.0); if ( x[LOWERDEPTH] >= project->TotalDepth ) { x[LOWERDEPTH] = project->TotalDepth - XTOL; } // --- save new values of state values project->GW->theta = x[THETA]; project->GW->lowerDepth = x[LOWERDEPTH]; getFluxes(project, project->GW->theta, project->GW->lowerDepth); project->GW->oldFlow = project->GW->newFlow; project->GW->newFlow = project->GWFlow; project->GW->evapLoss = project->UpperEvap + project->LowerEvap; //--- find max. infiltration volume (as depth over // the pervious portion of the subcatchment) // that upper zone can support in next time step project->GW->maxInfilVol = (project->TotalDepth - x[LOWERDEPTH]) * (project->A.porosity - x[THETA]) / project->FracPerv; // --- update project->GW mass balance updateMassBal(project,project->Area, tStep); // --- update project->GW statistics //(5.1.008) stats_updateGwaterStats(project, j, infil, project->GW->evapLoss, project->GWFlow, project->LowerLoss, //(5.1.008) project->GW->theta, project->GW->lowerDepth + project->GW->bottomElev, tStep); //(5.1.008) }