Пример #1
0
void updatePondedDepth(TSubarea* subarea, double* dt)
//
//  Input:   subarea = ptr. to a subarea,
//           dt = time step (sec)
//  Output:  dt = time ponded depth is above depression storage (sec)
//  Purpose: computes new ponded depth over subarea after current time step.
//
{
    double ix;                         // excess inflow to subarea (ft/sec)
    double dx;                         // depth above depression storage (ft)
    double tx = *dt;                   // time over which dx > 0 (sec)

    // --- excess inflow = total inflow - losses
    ix = subarea->inflow - Losses;

    // --- see if not enough inflow to fill depression storage (dStore)
    if ( subarea->depth + ix*tx <= subarea->dStore )
    {
        subarea->depth += ix * tx;
    }

    // --- otherwise use the ODE solver to integrate flow depth
    else
    {
        // --- if depth < dStore then fill up dStore & reduce time step
        dx = subarea->dStore - subarea->depth;
        if ( dx > 0.0 && ix > 0.0 )
        {
            tx -= dx / ix;
            subarea->depth = subarea->dStore;
        }

        // --- now integrate depth over remaining time step tx
        if ( subarea->alpha > 0.0 && tx > 0.0 )
        {
            theSubarea = subarea;
            odesolve_integrate(&(subarea->depth), 1, 0, tx, ODETOL, tx,
                               getDdDt);
        }
        else
        {
            if ( tx < 0.0 ) tx = 0.0;
            subarea->depth += ix * tx;
        }
    }

    // --- do not allow ponded depth to go negative
    if ( subarea->depth < 0.0 ) subarea->depth = 0.0;

    // --- replace original time step with time ponded depth
    //     is above depression storage
    *dt = tx;
}
Пример #2
0
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);
}
Пример #3
0
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)
}