void setNewNodeState(int j, float dt) // // Input: j = node index // dt = time step (sec) // Output: none // Purpose: updates state of node after current time step // for Steady Flow or Kinematic Wave flow routing. // { int canPond; // TRUE if ponding can occur at node float newNetInflow; // inflow - outflow at node (cfs) // --- update stored volume using mid-point integration newNetInflow = Node[j].inflow - Node[j].outflow; Node[j].newVolume = Node[j].oldVolume + 0.5 * (Node[j].oldNetInflow + newNetInflow) * dt; if ( Node[j].newVolume < 0.0 ) Node[j].newVolume = 0.0; // --- determine any overflow lost from system Node[j].overflow = 0.0; canPond = (AllowPonding && Node[j].pondedArea > 0.0); if ( Node[j].newVolume > Node[j].fullVolume ) { if ( !canPond ) { Node[j].overflow = (Node[j].newVolume - Node[j].fullVolume) / dt; Node[j].newVolume = Node[j].fullVolume; // --- ignore any negligible overflow if ( Node[j].overflow <= FUDGE ) Node[j].overflow = 0.0; } } // --- compute a depth from volume // (depths at upstream nodes are subsequently adjusted in // setNewLinkState to reflect depths in connected conduit) if ( canPond ) { Node[j].newDepth = node_getPondedDepth(j, Node[j].newVolume); } else { Node[j].newDepth = node_getDepth(j, Node[j].newVolume); } }
double node_getPondedDepth(int j, double v) // // Input: j = node index // v = water volume (ft3) // Output: returns depth of water at a node (ft) // Purpose: computes depth of water at a node based on volume. // { double y; // --- if volume below full volume, use normal getDepth function if ( v <= Node[j].fullVolume ) return node_getDepth(j, v); // --- find ponded volume v = v - Node[j].fullVolume; // --- depth equals full depth + ponded volume / ponded area y = Node[j].fullDepth; if ( Node[j].pondedArea > 0.0 ) y += v / Node[j].pondedArea; return y; }
void setNewNodeState(int j, double dt) // // Input: j = node index // dt = time step (sec) // Output: none // Purpose: updates state of node after current time step // for Steady Flow or Kinematic Wave flow routing. // { int canPond; // TRUE if ponding can occur at node double newNetInflow; // inflow - outflow at node (cfs) // --- storage nodes have already been updated if ( Node[j].type == STORAGE ) return; // --- update stored volume using mid-point integration newNetInflow = Node[j].inflow - Node[j].outflow; Node[j].newVolume = Node[j].oldVolume + 0.5 * (Node[j].oldNetInflow + newNetInflow) * dt; if ( Node[j].newVolume < FUDGE ) Node[j].newVolume = 0.0; // --- determine any overflow lost from system Node[j].overflow = 0.0; canPond = (AllowPonding && Node[j].pondedArea > 0.0); if ( Node[j].newVolume > Node[j].fullVolume ) { Node[j].overflow = (Node[j].newVolume - MAX(Node[j].oldVolume, Node[j].fullVolume)) / dt; if ( Node[j].overflow < FUDGE ) Node[j].overflow = 0.0; if ( !canPond ) Node[j].newVolume = Node[j].fullVolume; } // --- compute a depth from volume // (depths at upstream nodes are subsequently adjusted in // setNewLinkState to reflect depths in connected conduit) Node[j].newDepth = node_getDepth(j, Node[j].newVolume); }
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; }