Saturday, December 28, 2024

SWMM5 hotstart.c Summary

 Below is a step‐by‐step explanation of hotstart.c, which handles saving and reading SWMM’s hot start files. A hot start file captures the internal state of an ongoing SWMM simulation (runoff and routing) at the end of a run, so that a subsequent run can begin from those exact conditions.


1. General Context

Hot start files help avoid spinning up from initial conditions of zero depth, flow, etc. Instead, a new simulation picks up at the state of the system (subcatchment infiltration, groundwater, node depths, link flows, water quality) at the end of a previous run.

SWMM can produce two types (or versions) of hot start files:

  1. Version 1 (original format): Everything about nodes, links, subcatchments including infiltration states, but not the “abridged” version items.
  2. Version 2/3/4: A more abridged version. For example, version 2 includes only variables that appear in the binary output file (groundwater, node & link states, etc.). Versions 3 & 4 add more items (like subcatchment states, infiltration states, stored water quality).

2. Global File Variables

Fhotstart1 is the input hotstart file (the file we read from).
Fhotstart2 is the output hotstart file (the file we write to).


3. Opening and Closing Hot Start Files

3.1 hotstart_open()

int hotstart_open()
{
    if ( !openHotstartFile1() ) return FALSE;  // open input hotstart
    if ( !openHotstartFile2() ) return FALSE;  // open output hotstart
    return TRUE;
}
  1. openHotstartFile1(): open the (optional) input hotstart file to read states into the current simulation.
  2. openHotstartFile2(): open the (optional) output hotstart file to save states at simulation’s end.

If these steps fail, returns FALSE.

3.2 hotstart_close()

void hotstart_close()
{
    if ( Fhotstart2.file )
    {
        saveRunoff();
        saveRouting();
        fclose(Fhotstart2.file);
    }
}
  1. Called after a simulation ends.
  2. If we have an output hotstart file open, it calls:
    • saveRunoff(): store subcatchment states (ponded depth, infiltration, groundwater, snowpack, etc.).
    • saveRouting(): store node & link states (depth, flow, quality).
  3. Then closes Fhotstart2.file.

4. Opening an Input Hot Start File (openHotstartFile1())

int openHotstartFile1()
{
    // skip if not using an input hotstart
    if (Fhotstart1.mode != USE_FILE) return TRUE;

    // open the file
    ...
    // read a "file stamp" indicating SWMM hotstart format
    // read file version, object counts
    // check that they match the current SWMM project
    // read states with readRunoff(), readRouting()
    // close file
}
  • The file has a header that starts with "SWMM5-HOTSTART" plus possibly version numbers.
  • We read integer counts of subcatchments, landuses, nodes, links, pollutants, plus flow units.
  • We verify that they match the current SWMM project.
  • If a mismatch occurs, we raise an error.
  • If version >= 3, we call readRunoff() to read subcatchment states. Then we always call readRouting() to load node and link states.

fileVersion is stored locally to know how many data items to read for each object.


5. Opening an Output Hot Start File (openHotstartFile2())

int openHotstartFile2()
{
    if ( Fhotstart2.mode != SAVE_FILE ) return TRUE;
    // open the file
    // write a file stamp "SWMM5-HOTSTART4"
    // write #subcatch, #landuse, #node, #link, #pollut, flowUnits
    return TRUE;
}
  • The file gets stamped with "SWMM5-HOTSTART4" for the latest version.
  • We store the object counts and flow units so that a subsequent run can verify matching data.

6. Saving and Reading Runoff States

6.1 saveRunoff()

void saveRunoff(void)
{
    for (i in subcatchments)
    {
        // ponded depths in subareas & newRunoff
        fwrite(...) 4 doubles

        // infiltration state
        infil_getState(i, x) => up to 6 doubles
        fwrite(..., 6, ...)

        // groundwater state (4 doubles)
        gwater_getState(i, x) => { upperMoisture, waterTable, flow, infiltrationVol? }
        fwrite(..., 4, ...)

        // snowpack state (5 doubles) for up to 3 surfaces
        snow_getState(i, j, x)
        fwrite(..., 5, ...)

        // water quality: runoffQual, pondedQual, then buildup info
    }
}

For each subcatchment we save:

  1. Depth in up to 3 subareas and the final runoff rate.
  2. Infiltration states for whichever infiltration method is used.
  3. GW states: upper zone moisture content, water table depth, etc.
  4. Snowpack states: e.g., snow depth, temperature, etc. for each subarea.
  5. Water quality in runoff, ponding, land buildup, etc.

6.2 readRunoff()

void readRunoff()
{
    for (i in subcatchments)
    {
        // read 4 doubles for subarea depths & newRunoff
        // read 6 doubles for infiltration
        // read 4 doubles for GW if present
        // read 5 doubles for each snow surface if present
        // read water quality arrays
    }
}
  • Populates subarea depths, infiltration states, groundwater states, snow states, and quality states.
  • Calls e.g. snow_setState() to restore snowpack states, gwater_setState() for groundwater, etc.

7. Saving and Reading Routing States

7.1 saveRouting()

void saveRouting()
{
    // For each node:
    //   write depth, newLatFlow
    //   if node is STORAGE, write storage residence time
    //   write node pollutant concentrations

    // For each link:
    //   write flow, depth, setting
    //   write link pollutant concentrations
}
  • Node depth = Node[i].newDepth
  • Node lateral inflow = Node[i].newLatFlow
  • Storage node’s hrt (hydraulic residence time).
  • Link flow, depth, control setting, plus each pollutant’s newQual.

7.2 readRouting()

void readRouting()
{
    // if fileVersion == 2 => read subcatch GW states
    // For each node: read newDepth, newLatFlow, (storage hrt), nodeQuality
    // For each link: read newFlow, newDepth, newSetting => also set link->targetSetting
    //                read linkQuality
}
  • If fileVersion == 2, we read just subcatchment’s groundwater moisture/water table.
  • Then read each node’s depth, lateral flow, possibly storage hrt, pollutants.
  • Then each link’s flow, depth, setting, and pollutants.
  • We also set the link’s targetSetting to the read setting so any control or orifice/pump adjusts accordingly.

8. Low-Level Reading and Writing

8.1 readFloat(float* x, FILE* f) / readDouble(double* x, FILE* f)

  • Pulls 1 float or double from the file.
  • Checks for end‐of‐file or if the read value is NaN => signals an error.

8.2 Byte Ordering

  • SWMM writes/reads binary floating values. If the environment using it has the same endianness, it works. Otherwise, there might be issues across different platforms or compilers.

9. Final Observations

  1. The hotstart system is optional. If not used, openHotstartFile1() or openHotstartFile2() does nothing.
  2. The file version determines which items get read/written. The newest version 4 includes the most complete set.
  3. On reading, it verifies that the file’s subcatch/node/link/pollut counts match the current model. No verification of shape or structure is done beyond that.

Hence, hotstart.c allows SWMM to persist simulation states to disk, then reload them for a continuation or subsequent scenario run—saving the time and inaccuracy from starting at zero.

No comments:

A comprehensive explanation of how minimum travel distance relates to link length in InfoSewer

In hydraulic modeling of sewer networks, the minimum travel distance is a fundamental parameter that affects how accurately the model can si...