int steadyflow_execute(int j, float* qin, float* qout) // // Input: j = link index // qin = inflow to link (cfs) // Output: qin = adjusted inflow to link (limited by flow capacity) (cfs) // qout = link's outflow (cfs) // returns 1 if successful // Purpose: performs steady flow routing through a single link. // { int k; float s; float q; // --- use Manning eqn. to compute flow area for conduits if ( Link[j].type == CONDUIT ) { k = Link[j].subIndex; q = (*qin) / Conduit[k].barrels; if ( Link[j].xsect.type == DUMMY ) Conduit[k].a1 = 0.0; else { ////////////////////////////////////////////////////////////////////////////// // Comparison should be made against max. flow, not full flow. (LR - 3/10/06) ////////////////////////////////////////////////////////////////////////////// // if ( q > Link[j].qFull ) // { // q = Link[j].qFull; // Conduit[k].a1 = Link[j].xsect.aFull; // if ( q > Conduit[k].qMax ) { q = Conduit[k].qMax; Conduit[k].a1 = xsect_getAmax(&Link[j].xsect); (*qin) = q * Conduit[k].barrels; } else { s = q / Conduit[k].beta; Conduit[k].a1 = xsect_getAofS(&Link[j].xsect, s); } } Conduit[k].a2 = Conduit[k].a1; Conduit[k].q1 = q; Conduit[k].q2 = q; (*qout) = q * Conduit[k].barrels; } else (*qout) = (*qin); return 1; }
int solveContinuity(double qin, double ain, double* aout) // // Input: qin = upstream normalized flow // ain = upstream normalized area // aout = downstream normalized area // Output: new value for aout; returns an error code // Purpose: solves continuity equation f(a) = Beta1*S(a) + C1*a + C2 = 0 // for 'a' using the Newton-Raphson root finder function. // Return code has the following meanings: // >= 0 number of function evaluations used // -1 Newton function failed // -2 flow always above max. flow // -3 flow always below zero // // Note: pXsect (pointer to conduit's cross-section), and constants Beta1, // C1, and C2 are module-level shared variables assigned values in // kinwave_execute(). // { int n; // # evaluations or error code double aLo, aHi, aTmp; // lower/upper bounds on a double fLo, fHi; // lower/upper bounds on f double tol = EPSIL; // absolute convergence tol. // --- first determine bounds on 'a' so that f(a) passes through 0. // --- set upper bound to area at full flow aHi = 1.0; fHi = 1.0 + C1 + C2; // --- try setting lower bound to area where section factor is maximum aLo = xsect_getAmax(pXsect) / Afull; if ( aLo < aHi ) { fLo = ( Beta1 * pXsect->sMax ) + (C1 * aLo) + C2; } else fLo = fHi; // --- if fLo and fHi have same sign then set lower bound to 0 if ( fHi*fLo > 0.0 ) { aHi = aLo; fHi = fLo; aLo = 0.0; fLo = C2; } // --- proceed with search for root if fLo and fHi have different signs if ( fHi*fLo <= 0.0 ) { // --- start search at midpoint of lower/upper bounds // if initial value outside of these bounds if ( *aout < aLo || *aout > aHi ) *aout = 0.5*(aLo + aHi); // --- if fLo > fHi then switch aLo and aHi if ( fLo > fHi ) { aTmp = aLo; aLo = aHi; aHi = aTmp; } // --- call the Newton root finder method passing it the // evalContinuity function to evaluate the function // and its derivatives n = findroot_Newton(aLo, aHi, aout, tol, evalContinuity); // --- check if root finder succeeded if ( n <= 0 ) n = -1; } // --- if lower/upper bound functions both negative then use full flow else if ( fLo < 0.0 ) { if ( qin > 1.0 ) *aout = ain; else *aout = 1.0; n = -2; } // --- if lower/upper bound functions both positive then use no flow else if ( fLo > 0 ) { *aout = 0.0; n = -3; } else n = -1; return n; }