void routing_execute(int routingModel, double routingStep)
//
//  Input:   routingModel = routing method code
//           routingStep = routing time step (sec)
//  Output:  none
//  Purpose: executes the routing process at the current time period.
//
{
    int      j;
    int      stepCount = 1;
    int      actionCount = 0;
    int      inSteadyState = FALSE;
    DateTime currentDate;
    double   stepFlowError;

    // --- update continuity with current state
    //     applied over 1/2 of time step
    if ( ErrorCode ) return;
    massbal_updateRoutingTotals(routingStep/2.);

    // --- evaluate control rules at current date and elapsed time
    currentDate = getDateTime(NewRoutingTime);
    for (j=0; j<Nobjects[LINK]; j++) link_setTargetSetting(j);
    controls_evaluate(currentDate, currentDate - StartDateTime,
                      routingStep/SECperDAY);
    for (j=0; j<Nobjects[LINK]; j++)
    {
        if ( Link[j].targetSetting != Link[j].setting )
        {
            Link[j].timeLastSet = currentDate;                                 //(5.1.010)
            link_setSetting(j, routingStep);
            actionCount++;
        } 
    }

    // --- update value of elapsed routing time (in milliseconds)
    OldRoutingTime = NewRoutingTime;
    NewRoutingTime = NewRoutingTime + 1000.0 * routingStep;
//    currentDate = getDateTime(NewRoutingTime);   //Deleted                   //(5.1.008)             

    // --- initialize mass balance totals for time step
    stepFlowError = massbal_getStepFlowError();
    massbal_initTimeStepTotals();

    // --- replace old water quality state with new state
    if ( Nobjects[POLLUT] > 0 )
    {
        for (j=0; j<Nobjects[NODE]; j++) node_setOldQualState(j);
        for (j=0; j<Nobjects[LINK]; j++) link_setOldQualState(j);
    }

    // --- add lateral inflows and evap/seepage losses at nodes                //(5.1.007)
    for (j = 0; j < Nobjects[NODE]; j++)
    {
        Node[j].oldLatFlow  = Node[j].newLatFlow;
        Node[j].newLatFlow  = 0.0;
        Node[j].losses      = node_getLosses(j, routingStep);                  //(5.1.007)
    }
    addExternalInflows(currentDate);
    addDryWeatherInflows(currentDate);
    addWetWeatherInflows(OldRoutingTime);                                      //(5.1.008)
    addGroundwaterInflows(OldRoutingTime);                                     //(5.1.008)
    addLidDrainInflows(OldRoutingTime);                                        //(5.1.008)
    addRdiiInflows(currentDate);
    addIfaceInflows(currentDate);

    // --- check if can skip steady state periods
    if ( SkipSteadyState )
    {
        if ( OldRoutingTime == 0.0
        ||   actionCount > 0
        ||   fabs(stepFlowError) > SysFlowTol
        ||   inflowHasChanged() ) inSteadyState = FALSE;
        else inSteadyState = TRUE;
    }

    // --- find new hydraulic state if system has changed
    if ( inSteadyState == FALSE )
    {
        // --- replace old hydraulic state values with current ones
        for (j = 0; j < Nobjects[LINK]; j++) link_setOldHydState(j);
        for (j = 0; j < Nobjects[NODE]; j++)
        {
            node_setOldHydState(j);
            node_initInflow(j, routingStep);
        }

        // --- route flow through the drainage network
        if ( Nobjects[LINK] > 0 )
        {
            stepCount = flowrout_execute(SortedLinks, routingModel, routingStep);
        }
    }

    // --- route quality through the drainage network
    if ( Nobjects[POLLUT] > 0 && !IgnoreQuality ) 
    {
        qualrout_execute(routingStep);
    }

    // --- remove evaporation, infiltration & outflows from system
    removeStorageLosses(routingStep);
    removeConduitLosses();
    removeOutflows(routingStep);                                               //(5.1.008)
	
    // --- update continuity with new totals
    //     applied over 1/2 of routing step
    massbal_updateRoutingTotals(routingStep/2.);

    // --- update summary statistics
    if ( RptFlags.flowStats && Nobjects[LINK] > 0 )
    {
        stats_updateFlowStats(routingStep, getDateTime(NewRoutingTime),        //(5.1.008)
                              stepCount, inSteadyState);
    }
}
Example #2
0
void updateStorageState(int i, int j, int links[], double dt)
//
//  Input:   i = index of storage node
//           j = current position in links array
//           links = array of topo-sorted link indexes
//           dt = routing time step (sec)
//  Output:  none
//  Purpose: updates depth and volume of a storage node using successive
//           approximation with under-relaxation for Steady or Kin. Wave
//           routing.
//
{
    int    iter;                       // iteration counter
    int    stopped;                    // TRUE when iterations stop
    double vFixed;                     // fixed terms of flow balance eqn.
    double v2;                         // new volume estimate (ft3)
    double d1;                         // initial value of storage depth (ft)
    double d2;                         // updated value of storage depth (ft)
    double outflow;                    // outflow rate from storage (cfs)

    // --- see if storage node needs updating
    if ( Node[i].type != STORAGE ) return;
    if ( Node[i].updated ) return;

    // --- compute terms of flow balance eqn.
    //       v2 = v1 + (inflow - outflow)*dt
    //     that do not depend on storage depth at end of time step
    vFixed = Node[i].oldVolume + 
             0.5 * (Node[i].oldNetInflow + Node[i].inflow) * dt;
    d1 = Node[i].newDepth;

    // --- iterate finding outflow (which depends on depth) and subsequent
    //     new volume and depth until negligible depth change occurs
    iter = 1;
    stopped = FALSE;
    while ( iter < MAXITER && !stopped )
    {
        // --- find total flow in all outflow links
        outflow = getStorageOutflow(i, j, links, dt);

        // --- find new volume from flow balance eqn.
        v2 = vFixed - 0.5 * outflow * dt - node_getLosses(i, dt);

        // --- limit volume to full volume if no ponding
        //     and compute overflow rate
        v2 = MAX(0.0, v2);
        Node[i].overflow = 0.0;
        if ( v2 > Node[i].fullVolume )
        {
            Node[i].overflow = (v2 - MAX(Node[i].oldVolume,
                                         Node[i].fullVolume)) / dt;
            if ( !AllowPonding || Node[i].pondedArea == 0.0 )
                v2 = Node[i].fullVolume;
        }

        // --- update node's volume & depth 
        Node[i].newVolume = v2;
        if ( v2 > Node[i].fullVolume ) d2 = node_getPondedDepth(i, v2);
        else d2 = node_getDepth(i, v2);
        Node[i].newDepth = d2;

        // --- use under-relaxation to estimate new depth value
        //     and stop if close enough to previous value
        d2 = (1.0 - OMEGA)*d1 + OMEGA*d2;
        if ( fabs(d2 - d1) <= STOPTOL ) stopped = TRUE;

        // --- update old depth with new value and continue to iterate
        Node[i].newDepth = d2;
        d1 = d2;
        iter++;
    }

    // --- mark node as being updated
    Node[i].updated = TRUE;
}