Saturday, January 21, 2023

SWMM 5.2.2 Code for LID Function lidproc_getOutflow

 This code is part of a function called "lidproc_getOutflow" that computes the runoff outflow from a single LID (Low Impact Development) unit.

The function takes in multiple inputs: a pointer to a specific LID unit, a pointer to a generic LID process, the runoff rate captured by the LID unit, potential evaporation rate, infiltration rate to native soil, maximum infiltration rate to native soil, and time step. It returns surface runoff rate from the LID unit, and sets the values of lidEvap, lidInfil, and lidDrain.

The function uses several arrays and variables to store values such as layer moisture levels, previously and newly computed flux rates, and layer moisture limits. It also defines a pointer to a function that computes flux rates through the LID. It initializes various values such as layer moisture volumes, flux rates, and moisture limits. Then it finds Green-Ampt infiltration from the surface layer and calls the appropriate flux rate function for the LID type.

Input VariablesTypeDescriptionUnits
lidUnitpointerPointer to specific LID unit being analyzed
lidProcpointerPointer to generic LID process of the LID unit
inflowdoubleRunoff rate captured by LID unitft/s
evapdoublePotential evaporation rateft/s
infildoubleInfiltration rate to native soilft/s
maxInfildoubleMaximum infiltration rate to native soilft/s
tStepdoubleTime stepsec
Output VariablesTypeDescriptionUnits
lidEvapdouble pointerEvaporation rate for LID unitft/s
lidInfildouble pointerInfiltration rate for LID unitft/s
lidDraindouble pointerDrain flow for LID unitft/s
returnsdoubleSurface runoff rate from the LID unitft/s

Note: The table only contains the input/output variables defined in the function signature and the purpose of the function.

double lidproc_getOutflow(TLidUnit* lidUnit, TLidProc* lidProc, double inflow,
                          double evap, double infil, double maxInfil,
                          double tStep, double* lidEvap,
                          double* lidInfil, double* lidDrain)
//
//  Purpose: computes runoff outflow from a single LID unit.
//  Input:   lidUnit  = ptr. to specific LID unit being analyzed
//           lidProc  = ptr. to generic LID process of the LID unit
//           inflow   = runoff rate captured by LID unit (ft/s)
//           evap     = potential evaporation rate (ft/s)
//           infil    = infiltration rate to native soil (ft/s)
//           maxInfil = max. infiltration rate to native soil (ft/s)
//           tStep    = time step (sec)
//  Output:  lidEvap  = evaporation rate for LID unit (ft/s)
//           lidInfil = infiltration rate for LID unit (ft/s)
//           lidDrain = drain flow for LID unit (ft/s)
//           returns surface runoff rate from the LID unit (ft/s)
//
{
    int    i;
    double x[MAX_LAYERS];        // layer moisture levels
    double xOld[MAX_LAYERS];     // work vector
    double xPrev[MAX_LAYERS];    // work vector
    double xMin[MAX_LAYERS];     // lower limit on moisture levels
    double xMax[MAX_LAYERS];     // upper limit on moisture levels
    double fOld[MAX_LAYERS];     // previously computed flux rates
    double f[MAX_LAYERS];        // newly computed flux rates

    // convergence tolerance on moisture levels (ft, moisture fraction , ft)
    double xTol[MAX_LAYERS] = {STOPTOL, STOPTOL, STOPTOL, STOPTOL};

    double omega = 0.0;          // integration time weighting

    //... define a pointer to function that computes flux rates through the LID
    void (*fluxRates) (double *, double *) = NULL;

    //... save references to the LID process and LID unit
    theLidProc = lidProc;
    theLidUnit = lidUnit;

    //... save evap, max. infil. & time step to shared variables
    EvapRate = evap;
    MaxNativeInfil = maxInfil;
    Tstep = tStep;

    //... store current moisture levels in vector x
    x[SURF] = theLidUnit->surfaceDepth;
    x[SOIL] = theLidUnit->soilMoisture;
    x[STOR] = theLidUnit->storageDepth;
    x[PAVE] = theLidUnit->paveDepth;

    //... initialize layer moisture volumes, flux rates and moisture limits
    SurfaceVolume  = 0.0;
    PaveVolume     = 0.0;
    SoilVolume     = 0.0;
    StorageVolume  = 0.0;
    SurfaceInflow  = inflow;
    SurfaceInfil   = 0.0;
    SurfaceEvap    = 0.0;
    SurfaceOutflow = 0.0;
    PaveEvap       = 0.0;
    PavePerc       = 0.0;
    SoilEvap       = 0.0;
    SoilPerc       = 0.0;
    StorageInflow  = 0.0;
    StorageExfil   = 0.0;
    StorageEvap    = 0.0;
    StorageDrain   = 0.0;
    for (i = 0; i < MAX_LAYERS; i++)
    {
        f[i] = 0.0;
        fOld[i] = theLidUnit->oldFluxRates[i];
        xMin[i] = 0.0;
        xMax[i] = BIG;
        Xold[i] = x[i];
    }

    //... find Green-Ampt infiltration from surface layer
    if ( theLidProc->lidType == POROUS_PAVEMENT ) SurfaceInfil = 0.0;
    else if ( theLidUnit->soilInfil.Ks > 0.0 )
    {
        SurfaceInfil =
            grnampt_getInfil(&theLidUnit->soilInfil, Tstep,
                             SurfaceInflow, theLidUnit->surfaceDepth,
                             MOD_GREEN_AMPT);
    }
    else SurfaceInfil = infil;

    //... set moisture limits for soil & storage layers
    if ( theLidProc->soil.thickness > 0.0 )
    {
        xMin[SOIL] = theLidProc->soil.wiltPoint;
        xMax[SOIL] = theLidProc->soil.porosity;
    }
    if ( theLidProc->pavement.thickness > 0.0 )
    {
        xMax[PAVE] = theLidProc->pavement.thickness;
    }
    if ( theLidProc->storage.thickness > 0.0 )
    {
        xMax[STOR] = theLidProc->storage.thickness;
    }
    if ( theLidProc->lidType == GREEN_ROOF )
    {
        xMax[STOR] = theLidProc->drainMat.thickness;
    }

    //... determine which flux rate function to use
    switch (theLidProc->lidType)
    {
    case BIO_CELL:
    case RAIN_GARDEN:     fluxRates = &biocellFluxRates;   break;
    case GREEN_ROOF:      fluxRates = &greenRoofFluxRates; break;
    case INFIL_TRENCH:    fluxRates = &trenchFluxRates;    break;
    case POROUS_PAVEMENT: fluxRates = &pavementFluxRates;  break;
    case RAIN_BARREL:     fluxRates = &barrelFluxRates;    break;
    case ROOF_DISCON:     fluxRates = &roofFluxRates;      break;
    case VEG_SWALE:       fluxRates = &swaleFluxRates;
                          omega = 0.5;
                          break;
    default:              return 0.0;
    }

    //... update moisture levels and flux rates over the time step
    i = modpuls_solve(MAX_LAYERS, x, xOld, xPrev, xMin, xMax, xTol,
                     fOld, f, tStep, omega, fluxRates);

/** For debugging only ********************************************
    if  (i == 0)
    {
        fprintf(Frpt.file,
        "\n  WARNING 09: integration failed to converge at %s %s",
            theDate, theTime);
        fprintf(Frpt.file,
        "\n              for LID %s placed in subcatchment %s.",
            theLidProc->ID, theSubcatch->ID);
    }
*******************************************************************/

    //... add any surface overflow to surface outflow
    if ( theLidProc->surface.canOverflow || theLidUnit->fullWidth == 0.0 )
    {
        SurfaceOutflow += getSurfaceOverflowRate(&x[SURF]);
    }

    //... save updated results
    theLidUnit->surfaceDepth = x[SURF];
    theLidUnit->paveDepth    = x[PAVE];
    theLidUnit->soilMoisture = x[SOIL];
    theLidUnit->storageDepth = x[STOR];
    for (i = 0; i < MAX_LAYERS; i++) theLidUnit->oldFluxRates[i] = f[i];

    //... assign values to LID unit evaporation, infiltration & drain flow
    *lidEvap = SurfaceEvap + PaveEvap + SoilEvap + StorageEvap;
    *lidInfil = StorageExfil;
    *lidDrain = StorageDrain;

    //... return surface outflow (per unit area) from unit
    return SurfaceOutflow;
}

SWMM 5.2.2 Code for LID Function lidproc_saveResults


This code is part of a function called "lidproc_saveResults" that updates the mass balance for an LID (Low Impact Development) unit and saves the current flux rates to a LID report file.

The function takes in two inputs: a pointer to the LID unit and two units conversion factors for rainfall rate and rainfall depth. It does not return any output.

First, the function calculates the total evaporation rate and total volume stored in the LID unit. Then, it updates the mass balance totals using the updateWaterBalance function, passing in various inflow, outflow, and storage parameters.

Next, the function checks if the LID unit is in a dry state by comparing the values of these parameters to a minimum flow threshold (MINFLOW). If it is in a dry state, it sets the variable "isDry" to true. If the LID unit is not in a dry state, it sets the global variable "HasWetLids" to true.

Then, if the LID unit has a report file, the function converts the rate results to the original units (in/hr or mm/hr) and storage results to the original units (in or mm) using the conversion factors passed in. It then writes the current results to a string, which is saved between reporting periods.

If the current LID state is wet but the previous state was dry for more than one period, the function writes the saved previous results to the report file, marking the end of a dry period.

Variable NameOriginal UnitsucfCalculation
SURF_INFLOWin/hr or mm/hrucfRainfallSurfaceInflow*ucf
TOTAL_EVAPin/hr or mm/hrucfRainfalltotalEvap*ucf
SURF_INFILin/hr or mm/hrucfRainfallSurfaceInfil*ucf
PAVE_PERCin/hr or mm/hrucfRainfallPavePerc*ucf
SOIL_PERCin/hr or mm/hrucfRainfallSoilPerc*ucf
STOR_EXFILin/hr or mm/hrucfRainfallStorageExfil*ucf
SURF_OUTFLOWin/hr or mm/hrucfRainfallSurfaceOutflow*ucf
STOR_DRAINin/hr or mm/hrucfRainfallStorageDrain*ucf
SURF_DEPTHin or mmucfRainDepththeLidUnit->surfaceDepth*ucf
PAVE_DEPTHin or mmucfRainDepththeLidUnit->paveDepth*ucf
SOIL_MOISTtheLidUnit->soilMoisture
STOR_DEPTHin or mmucfRainDepththeLidUnit->storageDepth*ucf

Note: ucf is the units conversion factor variable. The original units are assumed to be in/hr or mm/hr for rate results, and in or mm for storage results.



void lidproc_saveResults(TLidUnit* lidUnit, double ucfRainfall, double ucfRainDepth)
//
//  Purpose: updates the mass balance for an LID unit and saves
//           current flux rates to the LID report file.
//  Input:   lidUnit = ptr. to LID unit
//           ucfRainfall = units conversion factor for rainfall rate
//           ucfDepth = units conversion factor for rainfall depth
//  Output:  none
//
{
    double ucf;                        // units conversion factor
    double totalEvap;                  // total evaporation rate (ft/s)
    double totalVolume;                // total volume stored in LID (ft)
    double rptVars[MAX_RPT_VARS];      // array of reporting variables
    int    isDry = FALSE;              // true if current state of LID is dry
    char   timeStamp[TIME_STAMP_SIZE + 1]; // date/time stamp
    double elapsedHrs;                 // elapsed hours

    //... find total evap. rate and stored volume
    totalEvap = SurfaceEvap + PaveEvap + SoilEvap + StorageEvap; 
    totalVolume = SurfaceVolume + PaveVolume + SoilVolume + StorageVolume;

    //... update mass balance totals
    updateWaterBalance(theLidUnit, SurfaceInflow, totalEvap, StorageExfil,
                       SurfaceOutflow, StorageDrain, totalVolume);

    //... check if dry-weather conditions hold
    if ( SurfaceInflow  < MINFLOW &&
         SurfaceOutflow < MINFLOW &&
         StorageDrain   < MINFLOW &&
         StorageExfil   < MINFLOW &&
         totalEvap      < MINFLOW
       ) isDry = TRUE;

    //... update status of HasWetLids
    if ( !isDry ) HasWetLids = TRUE;

    //... write results to LID report file
    if ( lidUnit->rptFile )
    {
        //... convert rate results to original units (in/hr or mm/hr)
        ucf = ucfRainfall;
        rptVars[SURF_INFLOW]  = SurfaceInflow*ucf;
        rptVars[TOTAL_EVAP]   = totalEvap*ucf;
        rptVars[SURF_INFIL]   = SurfaceInfil*ucf;
        rptVars[PAVE_PERC]    = PavePerc*ucf;
        rptVars[SOIL_PERC]    = SoilPerc*ucf;
        rptVars[STOR_EXFIL]   = StorageExfil*ucf;
        rptVars[SURF_OUTFLOW] = SurfaceOutflow*ucf;
        rptVars[STOR_DRAIN]   = StorageDrain*ucf;

        //... convert storage results to original units (in or mm)
        ucf = ucfRainDepth;
        rptVars[SURF_DEPTH] = theLidUnit->surfaceDepth*ucf;
        rptVars[PAVE_DEPTH] = theLidUnit->paveDepth*ucf;
        rptVars[SOIL_MOIST] = theLidUnit->soilMoisture;
        rptVars[STOR_DEPTH] = theLidUnit->storageDepth*ucf;

        //... if the current LID state is wet but the previous state was dry
        //    for more than one period then write the saved previous results
        //    to the report file thus marking the end of a dry period
        if ( !isDry && theLidUnit->rptFile->wasDry > 1)
        {
            fprintf(theLidUnit->rptFile->file, "%s",
                theLidUnit->rptFile->results);
        }

        //... write the current results to a string which is saved between
        //    reporting periods
        elapsedHrs = NewRunoffTime / 1000.0 / 3600.0;
        datetime_getTimeStamp(
            M_D_Y, getDateTime(NewRunoffTime), TIME_STAMP_SIZE, timeStamp);
        snprintf(theLidUnit->rptFile->results, sizeof(theLidUnit->rptFile->results),
             "\n%20s\t %8.3f\t %8.3f\t %8.4f\t %8.3f\t %8.3f\t %8.3f\t %8.3f\t"
             "%8.3f\t %8.3f\t %8.3f\t %8.3f\t %8.3f\t %8.3f",
             timeStamp, elapsedHrs, rptVars[0], rptVars[1], rptVars[2],
             rptVars[3], rptVars[4], rptVars[5], rptVars[6], rptVars[7],
             rptVars[8], rptVars[9], rptVars[10], rptVars[11]);

        //... if the current LID state is dry
        if ( isDry )
        {
            //... if the previous state was wet then write the current
            //    results to file marking the start of a dry period
            if ( theLidUnit->rptFile->wasDry == 0 )
            {
                fprintf(theLidUnit->rptFile->file, "%s",
                    theLidUnit->rptFile->results);
            }

            //... increment the number of successive dry periods
            theLidUnit->rptFile->wasDry++;
        }

        //... if the current LID state is wet
        else
        {
            //... write the current results to the report file
            fprintf(theLidUnit->rptFile->file, "%s",
                theLidUnit->rptFile->results);

            //... re-set the number of successive dry periods to 0
            theLidUnit->rptFile->wasDry = 0; 
        }
    }

SWMM 5.2.2 Code for LID Function roofFluxRates

The function "roofFluxRates" computes the flux rates for a roof disconnection system. The input to the function is a vector of storage levels, and the output is a vector of flux rates.

The function starts by initializing a variable "surfaceDepth" with the value of the first element of the input vector "x". Then, it calls the function "getEvapRates" with the value of "surfaceDepth" and assigns the returned value to the variable "SurfaceVolume".

The function then sets the variable "SurfaceInfil" to 0.0, and checks the value of "theLidProc->surface.alpha". If the value is greater than 0.0, the function calls "getSurfaceOutflowRate" with the "surfaceDepth" as an argument, and assigns the returned value to the variable "SurfaceOutflow". Otherwise, it calls "getSurfaceOverflowRate" with "surfaceDepth" as an argument.

After that, the function calculates the "StorageDrain" by using the minimum value of "theLidProc->drain.coeff/UCF(RAINFALL)" and "SurfaceOutflow". Then, it subtracts the "StorageDrain" from "SurfaceOutflow" and assigns the result to the first element of the output vector "f".



void roofFluxRates(double x[], double f[])
//
//  Purpose: computes flux rates for roof disconnection.
//  Input:   x = vector of storage levels
//  Output:  f = vector of flux rates
//
{
    double surfaceDepth = x[SURF];

    getEvapRates(surfaceDepth, 0.0, 0.0, 0.0, 1.0);
    SurfaceVolume = surfaceDepth;
    SurfaceInfil = 0.0;
    if ( theLidProc->surface.alpha > 0.0 )
      SurfaceOutflow = getSurfaceOutflowRate(surfaceDepth);
    else getSurfaceOverflowRate(&surfaceDepth);
    StorageDrain = MIN(theLidProc->drain.coeff/UCF(RAINFALL), SurfaceOutflow);
    SurfaceOutflow -= StorageDrain;
    f[SURF] = (SurfaceInflow - SurfaceEvap - StorageDrain - SurfaceOutflow);
}

InfoSWMM: A 2030 AI-Assisted Study Guide

  InfoSWMM: A 2030 AI-Assisted Study Guide delete   InfoSWMM: A 2030 AI-Assisted Study Guide A comprehensive study guide for someone in 2030...