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); } }
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; }