double storage_getOutflow(int j, int i) // // Input: j = node index // i = link index // Output: returns flow from storage node into conduit link (cfs) // Purpose: finds outflow from a storage node into its connecting conduit link // ( non-conduit links have their own getInflow functions). // { int k; double a, y; // --- link must be a conduit if ( Link[i].type != CONDUIT ) return 0.0; // --- find depth of water in conduit y = Node[j].newDepth - Link[i].offset1; // --- return 0 if conduit empty or full flow if full if ( y <= 0.0 ) return 0.0; if ( y >= Link[i].xsect.yFull ) return Link[i].qFull; // --- if partially full, return normal flow k = Link[i].subIndex; a = xsect_getAofY(&Link[i].xsect, y); return Conduit[k].beta * xsect_getSofA(&Link[i].xsect, a); }
void evalContinuity(double a, double* f, double* df) // // Input: a = outlet normalized area // Output: f = value of continuity eqn. // df = derivative of continuity eqn. // Purpose: computes value of continuity equation (f) and its derivative (df) // w.r.t. normalized area for link with normalized outlet area 'a'. // { *f = (Beta1 * xsect_getSofA(pXsect, a*Afull)) + (C1 * a) + C2; *df = (Beta1 * Afull * xsect_getdSdA(pXsect, a*Afull)) + C1; }
int kinwave_execute(int j, double* qinflow, double* qoutflow, double tStep) // // Input: j = link index // qinflow = inflow at current time (cfs) // tStep = time step (sec) // Output: qoutflow = outflow at current time (cfs), // returns number of iterations used // Purpose: finds outflow over time step tStep given flow entering a // conduit using Kinematic Wave flow routing. // // t // | qin, ain |-------------------| qout, aout // | | Flow ---> | // |----> x q1, a1 |-------------------| q2, a2 // // { int k; int result = 1; double dxdt, dq; double ain, aout; double qin, qout; double a1, a2, q1, q2; // --- no routing for non-conduit link (*qoutflow) = (*qinflow); if ( Link[j].type != CONDUIT ) return result; // --- no routing for dummy xsection if ( Link[j].xsect.type == DUMMY ) return result; // --- assign module-level variables pXsect = &Link[j].xsect; Qfull = Link[j].qFull; Afull = Link[j].xsect.aFull; k = Link[j].subIndex; Beta1 = Conduit[k].beta / Qfull; // --- normalize flows and areas q1 = Conduit[k].q1 / Qfull; q2 = Conduit[k].q2 / Qfull; a1 = Conduit[k].a1 / Afull; a2 = Conduit[k].a2 / Afull; qin = (*qinflow) / Conduit[k].barrels / Qfull; // --- use full area when inlet flow >= full flow //(5.0.012 - LR) if ( qin >= 1.0 ) ain = 1.0; //(5.0.012 - LR) // --- get normalized inlet area corresponding to inlet flow else ain = xsect_getAofS(pXsect, qin/Beta1) / Afull; // --- check for no flow if ( qin <= TINY && q2 <= TINY ) { qout = 0.0; aout = 0.0; } // --- otherwise solve finite difference form of continuity eqn. else { // --- compute constant factors dxdt = link_getLength(j) / tStep * Afull / Qfull; dq = q2 - q1; C1 = dxdt * WT / WX; C2 = (1.0 - WT) * (ain - a1); C2 = C2 - WT * a2; C2 = C2 * dxdt / WX; C2 = C2 + (1.0 - WX) / WX * dq - qin; // --- starting guess for aout is value from previous time step aout = a2; // --- solve continuity equation for aout result = solveContinuity(qin, ain, &aout); // --- report error if continuity eqn. not solved if ( result == -1 ) { report_writeErrorMsg(ERR_KINWAVE, Link[j].ID); return 1; } if ( result <= 0 ) result = 1; // --- compute normalized outlet flow from outlet area qout = Beta1 * xsect_getSofA(pXsect, aout*Afull); if ( qin > 1.0 ) qin = 1.0; } // --- save new flows and areas Conduit[k].q1 = qin * Qfull; Conduit[k].a1 = ain * Afull; Conduit[k].q2 = qout * Qfull; Conduit[k].a2 = aout * Afull; (*qinflow) = Conduit[k].q1 * Conduit[k].barrels; (*qoutflow) = Conduit[k].q2 * Conduit[k].barrels; return result; }