void node_initState(int j) // // Input: j = node index // Output: none // Purpose: initializes a node's state variables at start of simulation. // { int p; // --- initialize depth Node[j].oldDepth = Node[j].initDepth; Node[j].newDepth = Node[j].oldDepth; Node[j].crownElev = Node[j].invertElev; Node[j].fullVolume = node_getVolume(j, Node[j].fullDepth); Node[j].oldVolume = node_getVolume(j, Node[j].oldDepth); Node[j].newVolume = Node[j].oldVolume; // --- initialize water quality state for (p = 0; p < Nobjects[POLLUT]; p++) { Node[j].oldQual[p] = 0.0; Node[j].newQual[p] = 0.0; } // --- initialize any inflow Node[j].oldLatFlow = 0.0; Node[j].newLatFlow = 0.0; // --- initialize HRT in storage nodes if ( Node[j].type == STORAGE ) { Storage[Node[j].subIndex].hrt = 0.0; } }
void node_initState(int j) // // Input: j = node index // Output: none // Purpose: initializes a node's state variables at start of simulation. // { int p, k; //(5.1.007) // --- initialize depth Node[j].oldDepth = Node[j].initDepth; Node[j].newDepth = Node[j].oldDepth; Node[j].crownElev = Node[j].invertElev; Node[j].fullVolume = node_getVolume(j, Node[j].fullDepth); Node[j].oldVolume = node_getVolume(j, Node[j].oldDepth); Node[j].newVolume = Node[j].oldVolume; // --- initialize water quality state for (p = 0; p < Nobjects[POLLUT]; p++) { Node[j].oldQual[p] = 0.0; Node[j].newQual[p] = 0.0; } // --- initialize any inflow Node[j].oldLatFlow = 0.0; Node[j].newLatFlow = 0.0; Node[j].losses = 0.0; //(5.1.007) //// Following code section added to release 5.1.007. //// //(5.1.007) // --- initialize storage nodes if ( Node[j].type == STORAGE ) { // --- set hydraulic residence time to 0 k = Node[j].subIndex; Storage[k].hrt = 0.0; // --- initialize exfiltration properties if ( Storage[k].exfil ) exfil_initState(k); } //// //// Following code section added to release 5.1.008. //// //(5.1.008) // --- initialize flow stream routed from outfall onto a subcatchment if ( Node[j].type == OUTFALL ) { k = Node[j].subIndex; if ( Outfall[k].routeTo >= 0 ) { Outfall[k].vRouted = 0.0; for (p = 0; p < Nobjects[POLLUT]; p++) Outfall[k].wRouted[p] = 0.0; } } //// }
void initNodes() // // Input: none // Output: none // Purpose: sets initial inflow/outflow and volume for each node // { int i; for ( i = 0; i < Nobjects[NODE]; i++ ) { // --- set default crown elevations here Node[i].crownElev = Node[i].invertElev; // --- initialize node inflow and outflow Node[i].inflow = Node[i].newLatFlow; Node[i].outflow = 0.0; // --- initialize node volume Node[i].newVolume = 0.0; if ( AllowPonding && Node[i].pondedArea > 0.0 && Node[i].newDepth > Node[i].fullDepth ) { Node[i].newVolume = Node[i].fullVolume + (Node[i].newDepth - Node[i].fullDepth) * Node[i].pondedArea; } else Node[i].newVolume = node_getVolume(i, Node[i].newDepth); } // --- update nodal inflow/outflow at ends of each link // (needed for Steady Flow & Kin. Wave routing) for ( i = 0; i < Nobjects[LINK]; i++ ) { if ( Link[i].newFlow >= 0.0 ) { Node[Link[i].node1].outflow += Link[i].newFlow; Node[Link[i].node2].inflow += Link[i].newFlow; } else { Node[Link[i].node1].inflow -= Link[i].newFlow; Node[Link[i].node2].outflow -= Link[i].newFlow; } } }
void initNodes(Project* project) // // Input: none // Output: none // Purpose: sets initial inflow/outflow and volume for each node // { int i; for ( i = 0; i < project->Nobjects[NODE]; i++ ) { // --- initialize node inflow and outflow project->Node[i].inflow = project->Node[i].newLatFlow; project->Node[i].outflow = 0.0; // --- initialize node volume project->Node[i].newVolume = 0.0; if ( project->AllowPonding && project->Node[i].pondedArea > 0.0 && project->Node[i].newDepth > project->Node[i].fullDepth ) { project->Node[i].newVolume = project->Node[i].fullVolume + (project->Node[i].newDepth - project->Node[i].fullDepth) * project->Node[i].pondedArea; } else project->Node[i].newVolume = node_getVolume(project, i, project->Node[i].newDepth); } // --- update nodal inflow/outflow at ends of each link // (needed for Steady Flow & Kin. Wave routing) for ( i = 0; i < project->Nobjects[LINK]; i++ ) { if ( project->Link[i].newFlow >= 0.0 ) { project->Node[project->Link[i].node1].outflow += project->Link[i].newFlow; project->Node[project->Link[i].node2].inflow += project->Link[i].newFlow; } else { project->Node[project->Link[i].node1].inflow -= project->Link[i].newFlow; project->Node[project->Link[i].node2].outflow -= project->Link[i].newFlow; } } }
void setNodeDepth(int i, double dt) // // Input: i = node index // dt = time step (sec) // Output: none // Purpose: sets depth at non-outfall node after current time step. // { int canPond; // TRUE if node can pond overflows int isPonded; // TRUE if node is currently ponded double dQ; // inflow minus outflow at node (cfs) double dV; // change in node volume (ft3) double dy; // change in node depth (ft) double yMax; // max. depth at node (ft) double yOld; // node depth at previous time step (ft) double yLast; // previous node depth (ft) double yNew; // new node depth (ft) double yCrown; // depth to node crown (ft) double surfArea; // node surface area (ft2) double denom; // denominator term double corr; // correction factor double f; // relative surcharge depth // --- see if node can pond water above it canPond = (AllowPonding && Node[i].pondedArea > 0.0); isPonded = (canPond && Node[i].newDepth > Node[i].fullDepth); // --- initialize values yCrown = Node[i].crownElev - Node[i].invertElev; yOld = Node[i].oldDepth; yLast = Node[i].newDepth; Node[i].overflow = 0.0; surfArea = Xnode[i].newSurfArea; // --- determine average net flow volume into node over the time step dQ = Node[i].inflow - Node[i].outflow; dV = 0.5 * (Node[i].oldNetInflow + dQ) * dt; // --- if node not surcharged, base depth change on surface area if ( yLast <= yCrown || Node[i].type == STORAGE || isPonded ) { dy = dV / surfArea; yNew = yOld + dy; // --- save non-ponded surface area for use in surcharge algorithm //(5.1.002) if ( !isPonded ) Xnode[i].oldSurfArea = surfArea; //(5.1.002) // --- apply under-relaxation to new depth estimate if ( Steps > 0 ) { yNew = (1.0 - Omega) * yLast + Omega * yNew; } // --- don't allow a ponded node to drop much below full depth if ( isPonded && yNew < Node[i].fullDepth ) yNew = Node[i].fullDepth - FUDGE; } // --- if node surcharged, base depth change on dqdh // NOTE: depth change is w.r.t depth from previous // iteration; also, do not apply under-relaxation. else { // --- apply correction factor for upstream terminal nodes corr = 1.0; if ( Node[i].degree < 0 ) corr = 0.6; // --- allow surface area from last non-surcharged condition // to influence dqdh if depth close to crown depth denom = Xnode[i].sumdqdh; if ( yLast < 1.25 * yCrown ) { f = (yLast - yCrown) / yCrown; denom += (Xnode[i].oldSurfArea/dt - Xnode[i].sumdqdh) * exp(-15.0 * f); } // --- compute new estimate of node depth if ( denom == 0.0 ) dy = 0.0; else dy = corr * dQ / denom; yNew = yLast + dy; if ( yNew < yCrown ) yNew = yCrown - FUDGE; // --- don't allow a newly ponded node to rise much above full depth if ( canPond && yNew > Node[i].fullDepth ) yNew = Node[i].fullDepth + FUDGE; } // --- depth cannot be negative if ( yNew < 0 ) yNew = 0.0; // --- determine max. non-flooded depth yMax = Node[i].fullDepth; if ( canPond == FALSE ) yMax += Node[i].surDepth; // --- find flooded depth & volume if ( yNew > yMax ) { yNew = getFloodedDepth(i, canPond, dV, yNew, yMax, dt); } else Node[i].newVolume = node_getVolume(i, yNew); // --- compute change in depth w.r.t. time Xnode[i].dYdT = fabs(yNew - yOld) / dt; // --- save new depth for node Node[i].newDepth = yNew; }