Saturday, January 21, 2023

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);
}

SWMM 5.2.2 Code for LID Function greenRoofFluxRates

This code is a function called "greenRoofFluxRates" that calculates flux rates from the layers of a green roof. It takes in two input arrays, "x" and "f", which represent the vector of storage levels and the vector of flux rates, respectively. The function uses several intermediate variables, including "availVolume" and "maxRate". It also makes use of several properties of the green roof, such as "soilThickness", "storageThickness", "soilPorosity", "storageVoidFrac", "soilFieldCap", and "soilWiltPoint".

The code first retrieves the moisture levels from the input vector "x" and converts them to volumes. It then calculates the ET rates, soil layer perc rate, and storage (drain mat) outflow rate. The code also checks for the case where the unit is full and limits the rates accordingly. The Surface infil is adjusted so that the soil porosity is not exceeded. The code also finds the surface outflow rate and computes overall layer flux rates.

A table of the variables used in this function and their descriptions is as follows:

Variable NameDescription
x[SURF], x[SOIL], x[STOR]Input vector of storage levels
f[SURF], f[SOIL], f[STOR]Output vector of flux rates
surfaceDepthMoisture level variable for the surface layer
soilThetaMoisture level variable for the soil layer
storageDepthMoisture level variable for the storage layer
availVolumeIntermediate variable for available volume
maxRateIntermediate variable for maximum rate
soilThicknessProperty of the soil layer representing its thickness
storageThicknessProperty of the storage layer representing its thickness
soilPorosityProperty of the soil layer representing its porosity

Variable NameDescription
storageVoidFracProperty of the storage layer representing its void fraction
soilFieldCapProperty of the soil layer representing its field capacity
soilWiltPointProperty of the soil layer representing its wilting point
SurfaceVolumeVolume of the surface layer
SoilVolumeVolume of the soil layer
StorageVolumeVolume of the storage layer
SurfaceInflowInflow rate to the surface layer
SurfaceEvapEvaporation rate from the surface layer
SoilPercPercolation rate out of the soil layer
SoilEvapEvaporation rate from the soil layer
StorageExfilExfiltration rate out of the storage layer
StorageDrainDrain flow rate out of the storage layer
SurfaceInfilInfiltration rate into the soil layer
SurfaceOutflowOutflow rate from the surface layer

The code uses several helper functions:

  • getEvapRates(SurfaceVolume, 0.0, availVolume, StorageVolume, 1.0) : to calculate evaporation rate
  • getSoilPercRate(soilTheta) : to calculate soil percolation rate
  • getDrainMatOutflow(storageDepth) : to calculate storage (drain mat) outflow rate
  • getSurfaceOutflowRate(surfaceDepth) : to calculate surface outflow rate

The final output of the function is the overall flux rate for each of the three layers: surface, soil, and storage.


void greenRoofFluxRates(double x[], double f[])
//
//  Purpose: computes flux rates from the layers of a green roof.
//  Input:   x = vector of storage levels
//  Output:  f = vector of flux rates
//
{
    // Moisture level variables
    double surfaceDepth;
    double soilTheta;
    double storageDepth;

    // Intermediate variables
    double availVolume;
    double maxRate;

    // Green roof properties
    double soilThickness    = theLidProc->soil.thickness;
    double storageThickness = theLidProc->storage.thickness;
    double soilPorosity     = theLidProc->soil.porosity;
    double storageVoidFrac  = theLidProc->storage.voidFrac;
    double soilFieldCap     = theLidProc->soil.fieldCap;
    double soilWiltPoint    = theLidProc->soil.wiltPoint;

    //... retrieve moisture levels from input vector
    surfaceDepth = x[SURF];
    soilTheta    = x[SOIL];
    storageDepth = x[STOR];

    //... convert moisture levels to volumes
    SurfaceVolume = surfaceDepth * theLidProc->surface.voidFrac;
    SoilVolume = soilTheta * soilThickness;
    StorageVolume = storageDepth * storageVoidFrac;

    //... get ET rates
    availVolume = SoilVolume - soilWiltPoint * soilThickness;
    getEvapRates(SurfaceVolume, 0.0, availVolume, StorageVolume, 1.0);
    if ( soilTheta >= soilPorosity ) StorageEvap = 0.0;

    //... soil layer perc rate
    SoilPerc = getSoilPercRate(soilTheta);

    //... limit perc rate by available water
    availVolume = (soilTheta - soilFieldCap) * soilThickness;
    maxRate = MAX(availVolume, 0.0) / Tstep - SoilEvap;
    SoilPerc = MIN(SoilPerc, maxRate);
    SoilPerc = MAX(SoilPerc, 0.0);

    //... storage (drain mat) outflow rate
    StorageExfil = 0.0;
    StorageDrain = getDrainMatOutflow(storageDepth);

    //... unit is full
    if ( soilTheta >= soilPorosity && storageDepth >= storageThickness )
    {
        //... outflow from both layers equals limiting rate
        maxRate = MIN(SoilPerc, StorageDrain);
        SoilPerc = maxRate;
        StorageDrain = maxRate;

        //... adjust inflow rate to soil layer
        SurfaceInfil = MIN(SurfaceInfil, maxRate);
    }

    //... unit not full
    else
    {
        //... limit drainmat outflow by available storage volume
        maxRate = storageDepth * storageVoidFrac / Tstep - StorageEvap;
        if ( storageDepth >= storageThickness ) maxRate += SoilPerc;
        maxRate = MAX(maxRate, 0.0);
        StorageDrain = MIN(StorageDrain, maxRate);

        //... limit soil perc inflow by unused storage volume
        maxRate = (storageThickness - storageDepth) * storageVoidFrac / Tstep +
                  StorageDrain + StorageEvap;
        SoilPerc = MIN(SoilPerc, maxRate);
                
        //... adjust surface infil. so soil porosity not exceeded
        maxRate = (soilPorosity - soilTheta) * soilThickness / Tstep +
                  SoilPerc + SoilEvap;
        SurfaceInfil = MIN(SurfaceInfil, maxRate);
    }

    // ... find surface outflow rate
    SurfaceOutflow = getSurfaceOutflowRate(surfaceDepth);

    // ... compute overall layer flux rates
    f[SURF] = (SurfaceInflow - SurfaceEvap - SurfaceInfil - SurfaceOutflow) /
              theLidProc->surface.voidFrac;
    f[SOIL] = (SurfaceInfil - SoilEvap - SoilPerc) /
              theLidProc->soil.thickness;
    f[STOR] = (SoilPerc - StorageEvap - StorageDrain) /
              theLidProc->storage.voidFrac;
}

AI Rivers of Wisdom about ICM SWMM

Here's the text "Rivers of Wisdom" formatted with one sentence per line: [Verse 1] 🌊 Beneath the ancient oak, where shadows p...