Repository: pyswmm/Stormwater-Management-Model (language: python)

Issue:
API Version Tracker
Closes #98 

I am supportive of a community of people that are very 'used' to SWMM's versioning strategy.  I am confident that the community will move toward adopting proper semantic versioning... but in the mean time, since the API is going to be rapidly growing, @michaeltryby and I think it would be a good idea to start tracking the API version, separately.   Arguably, I'm imagining that not everyone will agree with this versioning philosophy. However, instead of bumping up SWMM's minor version number each time we add a few API functions, this will hopefully keep the community from wondering why SWMM's minor version keeps increasing, but the normal user doesn't get to leverage such functions. 

Instead of having a full semantic number for the API, I just have a major and minor number.  The major number will be bumped up each time a new set of functions are introduced to the API and the minor will consist of patches and bug fixes to the API. 

So currently we are sitting on: `v2.0.dev0`

API `v1.0` can be considered the original collection of API functions in `swmm.h`.

This pull request introduces two functions to fetch the API version.

In addition, we have some housekeeping (converting my dreaded tabs to spaces........)
Add Building page to Wiki



Discussion / hints:
@CHI-Rob - feel free to weigh in here too if you'd like!
Are you suggesting that the API and Engine have different versioning? I've seen this in practice for other software, but I'm not sure the scheme makes that much sense for SWMM. [SemVer](http://semver.org) is really designed for things that have an API - it's really the whole purpose.

What problem are you trying to solve in this PR? If the problem you are trying to solve is a too-rapidly changing minor version, then another solution could be to "release" less frequently. The postfixed "-devXX" on the patch can be used to denote the fluidity you describe in adding API functions. You choose when to tag a release, and at that point the minor gets a bump.

Do you have examples of people asking about the minor version bumps with no engine improvements? 
@samhatchett, your point is the same one that @michaeltryby has - unless we are going to maintain an API that we could plug directly into past and future versions of SWMM, we might as well continue to bump up the post-fixed number.  So at this point, I think it will be best to keep bumping the post-fix up as we make changes to the API on top of this current version of SWMM.  I can't imagine maintaining an API version to be compatible with into any previous version of SWMM.  
@bemcdonnell maybe a BUILD.md file on the the repo root?

Fix patch:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d73d30e59..ae4b46e40 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,7 @@
 # CMakeLists.txt - CMake configuration file for swmm-solver
 #
 # Created: July 11, 2019
-# Updated: May 19, 2021
+# Modified: Aug 16, 2022
 #
 # Authors: Michael E. Tryby
 #          US EPA ORD/CESER
@@ -22,7 +22,7 @@ endif()
 
 
 project(swmm-solver
-    VERSION 5.2.1
+    VERSION 5.2.2
     LANGUAGES C CXX
 )
 
diff --git a/README.md b/README.md
index e5c747a1b..8ec778bbd 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # Stormwater-Management-Model
 
-ORD Stormwater Management Model (aka "SWMM")
+Stormwater Management Model (aka "SWMM") solver only
 
 ## Introduction
 This is the open source SWMM source code repository maintained by the Open
diff --git a/src/solver/consts.h b/src/solver/consts.h
index 23000bbdb..ec465336d 100644
--- a/src/solver/consts.h
+++ b/src/solver/consts.h
@@ -3,7 +3,7 @@
 //
 //   Project: EPA SWMM5
 //   Version: 5.2
-//   Date:    06/01/22  (Build 5.2.1)
+//   Date:    10/18/22  (Build 5.2.2)
 //   Author:  L. Rossman
 //
 //   Various Constants
@@ -17,7 +17,7 @@
 //------------------
 
 // OWA Version string stored in version.h
-// #define   VERSION            52001
+// #define   VERSION            52002
 #define   MAGICNUMBER        516114522
 #define   EOFMARK            0x1A           // Use 0x04 for UNIX systems
 #define   MAXTITLE           3              // Max. # title lines
diff --git a/src/solver/controls.c b/src/solver/controls.c
index 34e3612cc..b46054006 100644
--- a/src/solver/controls.c
+++ b/src/solver/controls.c
@@ -1198,8 +1198,8 @@ void updateActionList(struct TAction* a)
         listItem->next = ActionList;
         ActionList = listItem;
     }
-        listItem->action = a;
-    }
+    listItem->action = a;
+}
 
 //=============================================================================
 
diff --git a/src/solver/enums.h b/src/solver/enums.h
index 22b514274..b1946778c 100644
--- a/src/solver/enums.h
+++ b/src/solver/enums.h
@@ -116,18 +116,18 @@
 // Cross section shape types
 //-------------------------------------
  enum XsectType {
-      DUMMY,                           // 0
+      DUMMY,                           // 0      
       CIRCULAR,                        // 1      closed
       FILLED_CIRCULAR,                 // 2      closed
       RECT_CLOSED,                     // 3      closed
-      RECT_OPEN,                       // 4
-      TRAPEZOIDAL,                     // 5
-      TRIANGULAR,                      // 6
+      RECT_OPEN,                       // 4       
+      TRAPEZOIDAL,                     // 5       
+      TRIANGULAR,                      // 6       
       PARABOLIC,                       // 7
-      POWERFUNC,                       // 8
-      RECT_TRIANG,                     // 9
+      POWERFUNC,                       // 8      
+      RECT_TRIANG,                     // 9       
       RECT_ROUND,                      // 10
-      MOD_BASKET,                      // 11
+      MOD_BASKET,                      // 11      
       HORIZ_ELLIPSE,                   // 12     closed
       VERT_ELLIPSE,                    // 13     closed
       ARCH,                            // 14     closed
@@ -197,7 +197,7 @@
 //-------------------------------------
 // Computed node quantities
 //-------------------------------------
- #define MAX_NODE_RESULTS 7
+ #define MAX_NODE_RESULTS 7 
  enum NodeResultType {
       NODE_DEPTH,                      // water depth above invert
       NODE_HEAD,                       // hydraulic head
@@ -418,7 +418,7 @@ enum  CompatibilityType {
 
  enum PumpCurveType {
       TYPE1_PUMP,                      // flow varies stepwise with wet well volume
-      TYPE2_PUMP,                      // flow varies stepwise with inlet depth
+      TYPE2_PUMP,                      // flow varies stepwise with inlet depth 
       TYPE3_PUMP,                      // flow varies with head delivered
       TYPE4_PUMP,                      // flow varies with inlet depth
       TYPE5_PUMP,                      // variable speed version of TYPE3 pump 
diff --git a/src/solver/funcs.h b/src/solver/funcs.h
index aad84fc04..15f272ffa 100644
--- a/src/solver/funcs.h
+++ b/src/solver/funcs.h
@@ -93,7 +93,7 @@ void    report_writeTimeStepStats(TTimeStepStats* timeStepStats);
 void    report_writeErrorMsg(int code, char* msg);
 void    report_writeErrorCode(void);
 void    report_writeInputErrorMsg(int k, int sect, char* line, long lineCount);
-void    report_writeWarningMsg(char* msg, char* id);
+void    report_writeWarningMsg(char* msg, char* id); 
 void    report_writeTseriesErrorMsg(int code, TTable *tseries);
 
 void    inputrpt_writeInput(void);
@@ -496,7 +496,7 @@ void    controls_addToCount(char* s);
 int     controls_addVariable(char* tok[], int ntoks);
 int     controls_addExpression(char* tok[], int ntoks);
 int     controls_addRuleClause(int rule, int keyword, char* Tok[], int nTokens);
-int     controls_evaluate(DateTime currentTime, DateTime elapsedTime,
+int     controls_evaluate(DateTime currentTime, DateTime elapsedTime, 
         double tStep);
 
 //-----------------------------------------------------------------------------
diff --git a/src/solver/gage.c b/src/solver/gage.c
index 84e0af2da..d8e4e2b4f 100644
--- a/src/solver/gage.c
+++ b/src/solver/gage.c
@@ -406,7 +406,7 @@ void gage_setState(int j, DateTime t)
         // --- otherwise update next rainfall interval date
         Gage[j].startDate = Gage[j].nextDate;
         Gage[j].endDate = datetime_addSeconds(Gage[j].startDate,
-                  Gage[j].rainInterval);
+                          Gage[j].rainInterval);
         Gage[j].rainfall = Gage[j].nextRainfall;
         if ( !getNextRainfall(j) ) Gage[j].nextDate = NO_DATE;
     }
@@ -670,11 +670,11 @@ int getNextRainfall(int j)
         {
             if ( Frain.file && Gage[j].currentFilePos < Gage[j].endFilePos )
             {
-            fseek(Frain.file, Gage[j].currentFilePos, SEEK_SET);
-            fread(&Gage[j].nextDate, sizeof(DateTime), 1, Frain.file);
-            fread(&vNext, sizeof(float), 1, Frain.file);
-            Gage[j].currentFilePos = ftell(Frain.file);
-            rNext = convertRainfall(j, (double)vNext);
+                fseek(Frain.file, Gage[j].currentFilePos, SEEK_SET);
+                fread(&Gage[j].nextDate, sizeof(DateTime), 1, Frain.file);
+                fread(&vNext, sizeof(float), 1, Frain.file);
+                Gage[j].currentFilePos = ftell(Frain.file);
+                rNext = convertRainfall(j, (double)vNext);
             }
             else return 0;
         }
@@ -684,9 +684,9 @@ int getNextRainfall(int j)
             k = Gage[j].tSeries;
             if ( k >= 0 )
             {
-            if ( !table_getNextEntry(&Tseries[k],
-                &Gage[j].nextDate, &rNext) ) return 0;
-            rNext = convertRainfall(j, rNext);
+                if ( !table_getNextEntry(&Tseries[k],
+                        &Gage[j].nextDate, &rNext) ) return 0;
+                rNext = convertRainfall(j, rNext);
             }
             else return 0;
         }
diff --git a/src/solver/globals.h b/src/solver/globals.h
index 193903697..cdc04eac3 100644
--- a/src/solver/globals.h
+++ b/src/solver/globals.h
@@ -19,7 +19,7 @@
 //   - Minimum dynamic wave routing variable time step added.
 //   Build 5.1.011:
 //   - Changed WarningCode to Warnings (# warnings issued)
-//   - Added error message text as a variable.
+//   - Added error message text as a variable. 
 //   - Added elapsed simulation time (in decimal days) variable.
 //   - Added variables associated with detailed routing events.
 //   Build 5.1.012:
diff --git a/src/solver/inlet.c b/src/solver/inlet.c
index 1ec914c4d..4defe127e 100644
--- a/src/solver/inlet.c
+++ b/src/solver/inlet.c
@@ -3,7 +3,7 @@
 //
 //   Project:  EPA SWMM5
 //   Version:  5.2
-//   Date:     06/01/22 (Build 5.2.1)
+//   Date:     10/08/22 (Build 5.2.2)
 //   Author:   L. Rossman
 //
 //   Street/Channel Inlet Functions
@@ -16,6 +16,8 @@
 //
 //   Build 5.2.1:
 //   - Substitutes the constant BIG for HUGE.
+//   Build 5.2.2:
+//   - Additional statistics added to Street Flow Summary table.
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
@@ -1030,17 +1032,18 @@ void writeStreetStatsHeader()
     report_writeLine("*******************");
     report_writeLine("");
     fprintf(Frpt.file,
-"\n  ----------------------------------------------------------------------------------------------------------------------"
-"\n                        Peak   Maximum   Maximum                             Peak Flow   Average      Bypass    BackFlow"
-"\n                        Flow    Spread     Depth  Inlet             Inlet      Capture   Capture   Frequency   Frequency");
+"\n  ---------------------------------------------------------------------------------------------------------------------------------------"
+"\n                                                                                        Peak     Avg.   Bypass     Back     Peak     Peak"
+"\n                        Peak   Maximum   Maximum                                        Flow     Flow     Flow     Flow  Capture   Bypass"
+"\n                        Flow    Spread     Depth  Inlet             Inlet     Inlet  Capture  Capture     Freq     Freq  / Inlet     Flow");
     if (UnitSystem == US) fprintf(Frpt.file,
-"\n  Street Conduit         %3s        ft        ft  Design            Location         %%         %%           %%           %%",
-        FlowUnitWords[FlowUnits]);
+"\n  Street Conduit         %3s        ft        ft  Design            Location  Count     Pcnt     Pcnt     Pcnt     Pcnt      %3s      %3s",
+        FlowUnitWords[FlowUnits], FlowUnitWords[FlowUnits], FlowUnitWords[FlowUnits]);
     else fprintf(Frpt.file,
-"\n  Street Conduit         %3s         m         m  Design            Location         %%         %%           %%           %%",
-        FlowUnitWords[FlowUnits]);
+"\n  Street Conduit         %3s         m         m  Design            Location            Pcnt     Pcnt     Pcnt     Pcnt      %3s      %3s",
+        FlowUnitWords[FlowUnits], FlowUnitWords[FlowUnits], FlowUnitWords[FlowUnits]);
     fprintf(Frpt.file,
-"\n  ----------------------------------------------------------------------------------------------------------------------");
+"\n  ---------------------------------------------------------------------------------------------------------------------------------------");
 }
 
 //=============================================================================
@@ -1095,19 +1098,24 @@ void writeStreetStats(int link)
             fprintf(Frpt.file, "  ON-GRADE");
         else
             fprintf(Frpt.file, "  ON-SAG  ");
+        fprintf(Frpt.file, "  %5d", inlet->numInlets);            
         fp = inlet->stats.flowPeriods / 100.0;
         if (fp > 0.0)
         {
             cp = inlet->stats.capturePeriods / 100.0;
-            fprintf(Frpt.file, " %9.2f", inlet->stats.peakFlowCapture);
+            fprintf(Frpt.file, "  %7.2f", inlet->stats.peakFlowCapture);
             if (cp > 0.0)
             {
                 afc = inlet->stats.avgFlowCapture / cp;
                 bpf = inlet->stats.bypassFreq / cp;
             }
-            fprintf(Frpt.file, " %9.2f", afc);
-            fprintf(Frpt.file, "   %9.2f", bpf);
-            fprintf(Frpt.file, "   %9.2f", inlet->stats.backflowPeriods / fp);
+            fprintf(Frpt.file, "  %7.2f", afc);
+            fprintf(Frpt.file, "  %7.2f", bpf);
+            fprintf(Frpt.file, "  %7.2f", inlet->stats.backflowPeriods / fp);
+            fprintf(Frpt.file, "  %7.2f", (maxFlow / Street[t].sides) * UCF(FLOW) *
+                0.01 * inlet->stats.peakFlowCapture / inlet->numInlets);
+            fprintf(Frpt.file, "  %7.2f", maxFlow * UCF(FLOW) * 0.01 *
+                (100.0 - inlet->stats.peakFlowCapture));            
         }
     }
 }
diff --git a/src/solver/lid.c b/src/solver/lid.c
index d9a0c7e78..e471e2941 100644
--- a/src/solver/lid.c
+++ b/src/solver/lid.c
@@ -356,7 +356,7 @@ int lid_readProcParams(char* toks[], int ntoks)
 //    LID_ID  STORAGE   <parameters>
 //    LID_ID  DRAIN     <parameters>
 //    LID_ID  DRAINMAT  <parameters>
-//    LID_ID  REMOVALS  <parameters> 
+//    LID_ID  REMOVALS  <parameters>
 //
 {
     int j, m;
@@ -712,7 +712,7 @@ int readStorageData(int j, char* toks[], int ntoks)
 //  Output:  returns error code
 //
 //  Format of data is:
-//    LID_ID STORAGE  Thickness  VoidRatio  Ksat  ClogFactor  (YES/NO) 
+//    LID_ID STORAGE  Thickness  VoidRatio  Ksat  ClogFactor  (YES/NO)
 //
 {
     int    i;
@@ -1638,7 +1638,7 @@ void lid_getRunoff(int j, double tStep)
     double lidArea;               // area of an LID unit
     double qImperv = 0.0;         // runoff from impervious areas (cfs)
     double qPerv = 0.0;           // runoff from pervious areas (cfs)
-    double lidInflow = 0.0;       // inflow to an LID unit (ft/s) 
+    double lidInflow = 0.0;       // inflow to an LID unit (ft/s)
     double qRunoff = 0.0;         // surface runoff from all LID units (cfs)
     double qDrain = 0.0;          // drain flow from all LID units (cfs)
     double qReturn = 0.0;         // LID outflow returned to pervious area (cfs)
diff --git a/src/solver/lid.h b/src/solver/lid.h
index c3ff11592..565cdb0b4 100644
--- a/src/solver/lid.h
+++ b/src/solver/lid.h
@@ -15,7 +15,7 @@
 //   - Support added for separate routing of LID drain flows.
 //   - Detailed LID reporting modified.
 //   Build 5.1.011:
-//   - Water depth replaces moisture content for LID's pavement layer.
+//   - Water depth replaces moisture content for LID's pavement layer. 
 //   - Arguments for lidproc_saveResults() modified.
 //   Build 5.1.012:
 //   - Redefined meaning of wasDry in TLidRptFile structure.
@@ -47,8 +47,8 @@
 //-----------------------------------------------------------------------------
 enum LidTypes {
     BIO_CELL,                // bio-retention cell
-    RAIN_GARDEN,             // rain garden
-    GREEN_ROOF,              // green roof
+    RAIN_GARDEN,             // rain garden 
+    GREEN_ROOF,              // green roof 
     INFIL_TRENCH,            // infiltration trench
     POROUS_PAVEMENT,         // porous pavement
     RAIN_BARREL,             // rain barrel
@@ -69,7 +69,7 @@ typedef struct
 {
     double    thickness;          // depression storage or berm ht. (ft)
     double    voidFrac;           // available fraction of storage volume
-    double    roughness;          // surface Mannings n
+    double    roughness;          // surface Mannings n 
     double    surfSlope;          // land surface slope (fraction)
     double    sideSlope;          // swale side slope (run/rise)
     double    alpha;              // slope/roughness term in Manning eqn.
@@ -204,7 +204,7 @@ typedef struct
     int      drainNode;      // node receiving drain flow
     TLidRptFile* rptFile;    // pointer to detailed report file
 
-    TGrnAmpt soilInfil;      // infil. object for biocell soil layer
+    TGrnAmpt soilInfil;      // infil. object for biocell soil layer 
     double   surfaceDepth;   // depth of ponded water on surface layer (ft)
     double   paveDepth;      // depth of water in porous pavement layer
     double   soilMoisture;   // moisture content of biocell soil layer
@@ -212,7 +212,7 @@ typedef struct
 
     // net inflow - outflow from previous time step for each LID layer (ft/s)
     double   oldFluxRates[MAX_LAYERS];
-
+                                     
     double   dryTime;        // time since last rainfall (sec)
     double   oldDrainFlow;   // previous drain flow (cfs)
     double   newDrainFlow;   // current drain flow (cfs)
diff --git a/src/solver/link.c b/src/solver/link.c
index b93cdfbaa..052a030b9 100644
--- a/src/solver/link.c
+++ b/src/solver/link.c
@@ -3,7 +3,7 @@
 //
 //   Project:  EPA SWMM5
 //   Version:  5.2
-//   Date:     06/01/22   (Build 5.2.1)
+//   Date:     10/29/22   (Build 5.2.2)
 //   Author:   L. Rossman
 //             M. Tryby (EPA)
 //
@@ -44,6 +44,8 @@
 //   - Support added for variable speed pumps.
 //   Build 5.2.1
 //   - Warning no longer issued when conduit elevation drop < MIN_DELTA_Z.
+//   Build 5.2.2:
+//   - Warning for conduit elevation drop < MIN_DELTA_Z restored.
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
@@ -1264,9 +1266,7 @@ double conduit_getSlope(int j)
     delta = fabs(elev1 - elev2);
     if ( delta < MIN_DELTA_Z )
     {
-        /*  Deprecated as of v.5.2.1
         report_writeWarningMsg(WARN04, Link[j].ID);
-        */
         delta = MIN_DELTA_Z;
     }
 
diff --git a/src/solver/mathexpr.c b/src/solver/mathexpr.c
index 2ce4d423d..c39dff7e1 100644
--- a/src/solver/mathexpr.c
+++ b/src/solver/mathexpr.c
@@ -6,9 +6,9 @@
 **                 operators.
 **  AUTHORS:       L. Rossman, US EPA - NRMRL
 **                 F. Shang, University of Cincinnati
-**  VERSION:       5.2.0
-**  LAST UPDATE:   11/01/21
-**  BUG FIXES:     Problems related to '^' operator (L.Rossman, 11/01/21)
+**  VERSION:       5.2.2
+**  LAST UPDATE:   09/02/2022
+**  BUG FIXES:     Problems related to '^' operator (F. Shang, 09/02/2022)
 ******************************************************************************/
 /*
 **   Operand codes:
@@ -34,12 +34,12 @@
 **	  20 = acos
 **	  21 = atan
 **	  22 = acot
-**    23 = sinh
+**        23 = sinh
 **	  24 = cosh
 **	  25 = tanh
 **	  26 = coth
 **	  27 = log10
-**    28 = step (x<=0 ? 0 : 1)
+**        28 = step (x<=0 ? 0 : 1)
 **	  31 = ^
 ******************************************************************************/
 #define _CRT_SECURE_NO_DEPRECATE
@@ -190,6 +190,7 @@ double getNumber()
     char c[] = " ";
     char sNumber[255];
     int  errflag = 0;
+    int  decimalCount = 0;
 
     /* --- get whole number portion of number */
     sNumber[0] = '\0';
@@ -205,6 +206,8 @@ double getNumber()
     {
         if (S[Pos] == '.')
         {
+            decimalCount++;
+            if (decimalCount > 1) Err = 1;
             strcat(sNumber, ".");
             Pos++;
             while (Pos < Len && isDigit(S[Pos]))
@@ -257,7 +260,7 @@ int getOperand()
       case '-': code = 4;
         if (Pos < Len-1 &&
             isDigit(S[Pos+1]) &&
-            (CurLex == 0 || CurLex == 1))
+            (CurLex <= 6 || CurLex == 31))
         {
             Pos++;
             Fvalue = -getNumber();
@@ -294,7 +297,7 @@ int getLex()
             n = getMathFunc();
             if ( n == 0 ) n = getVariable();
         }
-        else if ( isDigit(S[Pos]) )
+        else if ( S[Pos] == '.' || isDigit(S[Pos]) )
         {
             n = 7;
             Fvalue = getNumber();
@@ -330,6 +333,7 @@ ExprTree * getSingleOp(int *lex)
 {
     int opcode;
     ExprTree *left;
+    ExprTree *node;
 
     /* --- open parenthesis, so continue to grow the tree */
     if ( *lex == 1 )
@@ -374,6 +378,17 @@ ExprTree * getSingleOp(int *lex)
         }
     }   
     *lex = getLex();
+
+    /* --- exponentiation */
+	if (*lex == 31)
+	{
+		node = newNode();
+		node->left = left;
+		node->opcode = *lex;
+		*lex = getLex();
+		node->right = getSingleOp(lex);
+		left = node;
+    }
     return left;
 }
 
@@ -398,7 +413,7 @@ ExprTree * getOp(int *lex)
         else if ( *lex == 3) *lex = getLex();
     }
     left = getSingleOp(lex);
-    while ( *lex == 5 || *lex == 6 || *lex == 31)
+    while ( *lex == 5 || *lex == 6)
     {
         opcode = *lex;
         *lex = getLex();
@@ -518,88 +533,88 @@ double mathexpr_eval(MathExpr *expr, double (*getVariableValue) (int))
 	    case 3:
  		r1 = ExprStack[stackindex];
 		stackindex--;
-        if (stackindex < 0) break;
+                if (stackindex < 0) break;
 		r2 = ExprStack[stackindex];
 		ExprStack[stackindex] = r2 + r1;
 		break;
 
-        case 4:  
-        r1 = ExprStack[stackindex];
+            case 4:  
+                r1 = ExprStack[stackindex];
 		stackindex--;
-        if (stackindex < 0) break;
+                if (stackindex < 0) break;
 		r2 = ExprStack[stackindex];
 		ExprStack[stackindex] = r2 - r1;
 		break;
 
-        case 5:  
-        r1 = ExprStack[stackindex];
+            case 5:  
+                r1 = ExprStack[stackindex];
 		stackindex--;
-        if (stackindex < 0) break;
+                if (stackindex < 0) break;
 		r2 = ExprStack[stackindex];
 		ExprStack[stackindex] = r2 * r1;
 		break;
 
-        case 6:  
+            case 6:  
 		r1 = ExprStack[stackindex];
 		stackindex--;
-        if (stackindex < 0) break;
-        r2 = ExprStack[stackindex];
+                if (stackindex < 0) break;
+                r2 = ExprStack[stackindex];
 		ExprStack[stackindex] = r2 / r1;
 		break;				
 
-        case 7:  
+            case 7:  
 		stackindex++;
-        if (stackindex >= MAX_STACK_SIZE) break;
+                if (stackindex >= MAX_STACK_SIZE) break;
 		ExprStack[stackindex] = node->fvalue;
 		break;
 
-        case 8:
-        if (getVariableValue != NULL)
-        {
-           r1 = getVariableValue(node->ivar);
-        }
-        else r1 = 0.0;
+            case 8:
+                if (getVariableValue != NULL)
+                {
+                    r1 = getVariableValue(node->ivar);
+                }
+                else r1 = 0.0;
 		stackindex++;
-        if (stackindex >= MAX_STACK_SIZE) break;
-        ExprStack[stackindex] = r1;
+                if (stackindex >= MAX_STACK_SIZE) break;
+                ExprStack[stackindex] = r1;
 		break;
 
-        case 9: 
+            case 9: 
 		ExprStack[stackindex] = -ExprStack[stackindex];
 		break;
 
-        case 10: 
+            case 10: 
 		r1 = ExprStack[stackindex];
 		r2 = cos(r1);
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 11: 
+            case 11: 
 		r1 = ExprStack[stackindex];
 		r2 = sin(r1);
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 12: 
+            case 12: 
 		r1 = ExprStack[stackindex];
 		r2 = tan(r1);
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 13: 
+            case 13: 
 		r1 = ExprStack[stackindex];
 		if (r1 == 0.0) r2 = 0.0;
 		else r2 = 1.0/tan( r1 );    
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 14: 
+            case 14: 
 		r1 = ExprStack[stackindex];
 		r2 = fabs( r1 );       
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 15: 
+            case 15: 
 		r1 = ExprStack[stackindex];
 		if (r1 < 0.0) r2 = -1.0;
 		else if (r1 > 0.0) r2 = 1.0;
@@ -607,93 +622,93 @@ double mathexpr_eval(MathExpr *expr, double (*getVariableValue) (int))
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 16: 
+            case 16: 
 		r1 = ExprStack[stackindex];
 		if (r1 < 0.0) r2 = 0.0;
 		else r2 = sqrt( r1 );     
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 17: 
+            case 17: 
 		r1 = ExprStack[stackindex];
 		if (r1 <= 0) r2 = 0.0;
 		else r2 = log(r1);
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 18: 
+            case 18: 
 		r1 = ExprStack[stackindex];
 		r2 = exp(r1);
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 19: 
+            case 19: 
 		r1 = ExprStack[stackindex];
 		r2 = asin( r1 );
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 20: 
+            case 20: 
 		r1 = ExprStack[stackindex];
 		r2 = acos( r1 );      
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 21: 
+            case 21: 
 		r1 = ExprStack[stackindex];
 		r2 = atan( r1 );      
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 22: 
+            case 22: 
 		r1 = ExprStack[stackindex];
 		r2 = 1.57079632679489661923 - atan(r1);  
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 23:
+            case 23:
 		r1 = ExprStack[stackindex];
 		r2 = (exp(r1)-exp(-r1))/2.0;
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 24: 
+            case 24: 
 		r1 = ExprStack[stackindex];
 		r2 = (exp(r1)+exp(-r1))/2.0;
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 25: 
+            case 25: 
 		r1 = ExprStack[stackindex];
 		r2 = (exp(r1)-exp(-r1))/(exp(r1)+exp(-r1));
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 26: 
+            case 26: 
 		r1 = ExprStack[stackindex];
 		r2 = (exp(r1)+exp(-r1))/(exp(r1)-exp(-r1));
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 27: 
+            case 27: 
 		r1 = ExprStack[stackindex];
 		if (r1 == 0.0) r2 = 0.0;
 		else r2 = log10( r1 );     
 		ExprStack[stackindex] = r2;
 		break;
 
-        case 28:
+            case 28:
  		r1 = ExprStack[stackindex];
 		if (r1 <= 0.0) r2 = 0.0;
 		else           r2 = 1.0;
 		ExprStack[stackindex] = r2;
 		break;
                
-        case 31: 
+            case 31: 
 		r1 = ExprStack[stackindex];
-        stackindex--;
-        if (stackindex < 0) break;
-        r2 = ExprStack[stackindex];
+                stackindex--;
+                if (stackindex < 0) break;
+                r2 = ExprStack[stackindex];
 		if (r2 <= 0.0) r2 = 0.0;
 		else r2 = pow(r2, r1);
 		ExprStack[stackindex] = r2;
@@ -741,9 +756,9 @@ MathExpr * mathexpr_create(char *formula, int (*getVar) (char *))
     tree = getTree();
     if (Bc == 0 && Err == 0)
     {
-	    traverseTree(tree, &expr);
-	    while (expr)
-	    {
+        traverseTree(tree, &expr);
+        while (expr)
+        {
             result = expr;
             expr = expr->prev;
         }
diff --git a/src/solver/node.c b/src/solver/node.c
index c3ad97aad..2c8fa2501 100644
--- a/src/solver/node.c
+++ b/src/solver/node.c
@@ -3,7 +3,7 @@
 //
 //   Project:  EPA SWMM5
 //   Version:  5.2
-//   Date:     06/01/22   (Build 5.2.1)
+//   Date:     10/29/22   (Build 5.2.2)
 //   Author:   L. Rossman
 //
 //   Conveyance system node functions.
@@ -34,6 +34,9 @@
 //   - Warning no longer issued when node full depth is increased to match
 //     crown of highest connecting link.
 //   - a2 term for paraboloid shaped storage units was corrected
+//   Build 5.2.2:
+//   - Warning restored for node full depth being increased to crown of highest
+//     connecting link.
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
@@ -204,12 +207,11 @@ void  node_validate(int j)
     TDwfInflow* inflow;
 
     // --- see if full depth was increased to accommodate conduit crown
-/*  Deprecated as of v.5.2.1
     if ( Node[j].fullDepth > Node[j].oldDepth && Node[j].oldDepth > 0.0 )
     {
         report_writeWarningMsg(WARN02, Node[j].ID);
     }
-*/
+
     // --- check that initial depth does not exceed max. depth
     if ( Node[j].initDepth > Node[j].fullDepth + Node[j].surDepth )
         report_writeErrorMsg(ERR_NODE_DEPTH, Node[j].ID);
@@ -1096,7 +1098,7 @@ double storage_getLosses(int j, double tStep)
                 exfilRate *= lossRatio; 
             }
         }
-
+ 
     // --- save evap & infil losses at the node
     Storage[Node[j].subIndex].evapLoss = evapRate * tStep;
     Storage[Node[j].subIndex].exfilLoss = exfilRate * tStep;
diff --git a/src/solver/objects.h b/src/solver/objects.h
index 2e5146444..07f5129fd 100644
--- a/src/solver/objects.h
+++ b/src/solver/objects.h
@@ -147,7 +147,7 @@ typedef struct
    int           pastInterval;    // seconds since pastRain last updated
    int           coGage;          // index of gage with same rain timeseries
    int           isUsed;          // TRUE if gage used by any subcatchment
-   int           isCurrent;       // TRUE if gage's rainfall is current
+   int           isCurrent;       // TRUE if gage's rainfall is current 
 }  TGage;
 
 //-------------------
@@ -203,11 +203,11 @@ typedef struct
     int          tSeries;         // time series index
     double       monthlyEvap[12]; // monthly evaporation values
     double       panCoeff[12];    // monthly pan coeff. values
-    int          recoveryPattern; // soil recovery factor pattern
+    int          recoveryPattern; // soil recovery factor pattern 
     int          dryOnly;         // true if evaporation only in dry periods
     //----------------------------
     double       rate;            // current evaporation rate (ft/sec)
-    double       recoveryFactor;  // current soil recovery factor
+    double       recoveryFactor;  // current soil recovery factor 
 }   TEvap;
 
 //-------------------
@@ -404,7 +404,7 @@ typedef struct
    double        lidArea;         // area devoted to LIDs (ft2)
    double        rainfall;        // current rainfall (ft/sec)
    double        evapLoss;        // current evap losses (ft/sec)
-   double        infilLoss;       // current infil losses (ft/sec)
+   double        infilLoss;       // current infil losses (ft/sec) 
    double        runon;           // runon from other subcatchments (cfs)
    double        oldRunoff;       // previous runoff (cfs)
    double        newRunoff;       // current runoff (cfs)
@@ -568,7 +568,7 @@ typedef struct
    TExfil*     exfil;             // ptr. to exfiltration object
    //-----------------------------
    double      hrt;               // hydraulic residence time (sec)
-   double      evapLoss;          // evaporation loss (ft3)
+   double      evapLoss;          // evaporation loss (ft3) 
    double      exfilLoss;         // exfiltration loss (ft3)
 }  TStorage;
 
@@ -620,10 +620,10 @@ typedef struct
     double       aFull;                     // area when full (ft2)
     double       rFull;                     // hyd. radius when full (ft)
     double       wMax;                      // width at widest point (ft)
-    double       ywMax;                     // depth at max width (ft)
+    double       ywMax;                     // depth at max width (ft) 
     double       sMax;                      // section factor at max. flow (ft^4/3)
     double       aMax;                      // area at max. flow (ft2)
-    double       lengthFactor;              // floodplain / channel length
+    double       lengthFactor;              // floodplain / channel length 
     //--------------------------------------
     double       roughness;                 // Manning's n
     double       areaTbl[N_TRANSECT_TBL];   // table of area v. depth
@@ -751,10 +751,10 @@ typedef struct
 {
    int           type;            // pump type
    int           pumpCurve;       // pump curve table index
-   double        initSetting;     // initial speed setting
+   double        initSetting;     // initial speed setting 
    double        yOn;             // startup depth (ft)
    double        yOff;            // shutoff depth (ft)
-   double        xMin;            // minimum pt. on pump curve
+   double        xMin;            // minimum pt. on pump curve 
    double        xMax;            // maximum pt. on pump curve
 }  TPump;
 
@@ -1115,14 +1115,14 @@ typedef struct
    int           objType;         // either NODE or LINK
    int           index;           // node or link index
    double        value;           // value of node or link statistic
-}  TMaxStats;
+}  TMaxStats; 
 
 //------------------
 // REPORT FIELD INFO
 //------------------
-typedef struct
+typedef struct 
 {
-   char          Name[80];        // name of reported variable
+   char          Name[80];        // name of reported variable 
    char          Units[80];       // units of reported variable
    char          Enabled;         // TRUE if appears in report table
    int           Precision;       // number of decimal places when reported
diff --git a/src/solver/project.c b/src/solver/project.c
index a9bc162a3..55a0866c8 100644
--- a/src/solver/project.c
+++ b/src/solver/project.c
@@ -3,7 +3,7 @@
 //
 //   Project:  EPA SWMM5
 //   Version:  5.2
-//   Date:     11/01/21  (Build 5.2.0)
+//   Date:     11/21/22  (Build 5.2.2)
 //   Author:   L. Rossman
 //
 //   Project management functions.
@@ -49,6 +49,9 @@
 //   - Support added for Streets and Inlets.
 //   - Support added for RptFlags.disabled option.
 //   - Object's rptFlag changed to record its index in output file.
+//   Build 5.2.2:
+//   - Default number of threads changed from OMP max. number to 1
+//     to be consistent with User Manual.
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
@@ -64,7 +67,7 @@
 #endif
 
 #include "headers.h"
-#include "lid.h"
+#include "lid.h" 
 #include "hash.h"
 #include "mempool.h"
 
@@ -72,7 +75,7 @@
 //  Shared variables
 //-----------------------------------------------------------------------------
 static HTtable* Htable[MAX_OBJ_TYPES]; // Hash tables for object ID names
-static char     MemPoolAllocated;      // TRUE if memory pool allocated
+static char     MemPoolAllocated;      // TRUE if memory pool allocated 
 
 //-----------------------------------------------------------------------------
 //  External Functions (declared in funcs.h)
@@ -290,7 +293,7 @@ int  project_init(void)
 //  Input:   none
 //  Output:  returns an error code
 //  Purpose: initializes the internal state of all objects.
-//
+// 
 {
     int j, k;
     climate_initState();
@@ -508,7 +511,7 @@ int project_readOption(char* s1, char* s2)
 
       // --- simulation ending date
       case END_DATE:
-        if ( !datetime_strToDate(s2, &EndDate) )
+        if ( !datetime_strToDate(s2, &EndDate) ) 
         {
             return error_setInpError(ERR_DATETIME, s2);
         }
@@ -626,8 +629,8 @@ int project_readOption(char* s1, char* s2)
         }
         break;
 
-      case NORMAL_FLOW_LTD:
-        m = findmatch(s2, NormalFlowWords);
+      case NORMAL_FLOW_LTD: 
+        m = findmatch(s2, NormalFlowWords); 
         if ( m < 0 ) return error_setInpError(ERR_KEYWORD, s2);
         NormalFlowLtd = m;
         break;
@@ -704,7 +707,7 @@ int project_readOption(char* s1, char* s2)
         break;
 
       // --- minimum surface area (ft2 or sq. meters) associated with nodes
-      //     under dynamic wave flow routing
+      //     under dynamic wave flow routing 
       case MIN_SURFAREA:
         if (!getDouble(s2, &MinSurfArea))
             return error_setInpError(ERR_NUMBER, s2);
@@ -821,7 +824,7 @@ void setDefaults()
 
    // Interface files
    Frain.mode      = SCRATCH_FILE;     // Use scratch rainfall file
-   Fclimate.mode   = NO_FILE;
+   Fclimate.mode   = NO_FILE; 
    Frunoff.mode    = NO_FILE;
    Frdii.mode      = NO_FILE;
    Fhotstart1.mode = NO_FILE;
@@ -852,14 +855,14 @@ void setDefaults()
    ForceMainEqn    = H_W;              // Hazen-Williams eqn. for force mains
    LinkOffsets     = DEPTH_OFFSET;     // Use depth for link offsets
    LengtheningStep = 0;                // No lengthening of conduits
-   CourantFactor   = 0.0;              // No variable time step
+   CourantFactor   = 0.0;              // No variable time step 
    MinSurfArea     = 0.0;              // Force use of default min. surface area
    MinSlope        = 0.0;              // No user supplied minimum conduit slope
-   SkipSteadyState = FALSE;            // Do flow routing in steady state periods
+   SkipSteadyState = FALSE;            // Do flow routing in steady state periods 
    IgnoreRainfall  = FALSE;            // Analyze rainfall/runoff
    IgnoreRDII      = FALSE;            // Analyze RDII
-   IgnoreSnowmelt  = FALSE;            // Analyze snowmelt
-   IgnoreGwater    = FALSE;            // Analyze groundwater
+   IgnoreSnowmelt  = FALSE;            // Analyze snowmelt 
+   IgnoreGwater    = FALSE;            // Analyze groundwater 
    IgnoreRouting   = FALSE;            // Analyze flow routing
    IgnoreQuality   = FALSE;            // Analyze water quality
    WetStep         = 300;              // Runoff wet time step (secs)
@@ -869,15 +872,15 @@ void setDefaults()
    MinRouteStep    = 0.5;              // Minimum variable time step (sec)
    ReportStep      = 900;              // Reporting time step (secs)
    StartDryDays    = 0.0;              // Antecedent dry days
-   MaxTrials       = 0;                // Force use of default max. trials
+   MaxTrials       = 0;                // Force use of default max. trials 
    HeadTol         = 0.0;              // Force use of default head tolerance
    SysFlowTol      = 0.05;             // System flow tolerance for steady state
    LatFlowTol      = 0.05;             // Lateral flow tolerance for steady state
-   NumThreads      = 0;                // Number of parallel threads to use
+   NumThreads      = 1;                // Number of parallel threads to use
    NumEvents       = 0;                // Number of detailed routing events
 
    // Deprecated options
-   SlopeWeighting  = TRUE;             // Use slope weighting
+   SlopeWeighting  = TRUE;             // Use slope weighting 
    Compatibility   = SWMM4;            // Use SWMM 4 up/dn weighting method
 
    // Starting & ending date/time
@@ -934,7 +937,7 @@ void setDefaults()
        Evap.panCoeff[i]    = 1.0;
    }
    Evap.recoveryPattern = -1;
-   Evap.recoveryFactor  = 1.0;
+   Evap.recoveryFactor  = 1.0; 
    Evap.tSeries = -1;
    Evap.dryOnly = FALSE;
 
diff --git a/src/solver/qualrout.c b/src/solver/qualrout.c
index d535d9a25..d9c640f79 100644
--- a/src/solver/qualrout.c
+++ b/src/solver/qualrout.c
@@ -107,7 +107,7 @@ void qualrout_execute(double tStep)
 {
     int    i, j;
     double qIn, vAvg;
- 
+
     // --- find mass flow each link contributes to its downstream node
     for ( i = 0; i < Nobjects[LINK]; i++ ) findLinkMassFlow(i, tStep);
 
@@ -125,7 +125,7 @@ void qualrout_execute(double tStep)
             if ( qIn < ZERO ) qIn = 0.0;
             treatmnt_setInflow(qIn, Node[j].newQual);
         }
-
+       
         // --- find new quality at the node 
         if ( Node[j].type == STORAGE || Node[j].oldVolume > ZeroVolume )
         {
@@ -330,7 +330,7 @@ void findLinkQual(int i, double tStep)
         // --- start with concen. at start of time step
         c1 = Link[i].oldQual[p];
 
-	// --- update mass balance accounting for seepage loss
+        // --- update mass balance accounting for seepage loss
         massbal_addSeepageLoss(p, qSeep*c1);
 
         // --- increase concen. by evaporation factor
diff --git a/src/solver/runoff.c b/src/solver/runoff.c
index b8f9fb72b..080674fbb 100644
--- a/src/solver/runoff.c
+++ b/src/solver/runoff.c
@@ -3,7 +3,7 @@
 //
 //   Project:  EPA SWMM5
 //   Version:  5.2
-//   Date:     11/01/21   (Build 5.2.0)
+//   Date:     10/17/22   (Build 5.2.2)
 //   Author:   L. Rossman
 //             M. Tryby
 //
@@ -27,7 +27,9 @@
 //   Build 5.1.014:
 //   - Fixed street sweeping bug.
 //   Build 5.2.0:
-//   - Support added for saving rainfall amounts in previous 48 hours. 
+//   - Support added for saving rainfall amounts in previous 48 hours.
+//   Build 5.2.2:
+//   - Fixed possible use of canSweep in runoff_execute() with no assigned value. 
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
@@ -204,12 +206,12 @@ void runoff_execute()
 
     // --- see if street sweeping can occur on current date
     day = datetime_dayOfYear(currentDate);
+    canSweep = FALSE;
     if ( SweepStart <= SweepEnd )
     {
         if ( day >= SweepStart && day <= SweepEnd ) canSweep = TRUE;
     }
     else if ( day <= SweepEnd || day >= SweepStart ) canSweep = TRUE;
-    else canSweep = FALSE;
 
     // --- get runoff time step (in seconds)
     runoffStep = runoff_getTimeStep(currentDate);
diff --git a/src/solver/stats.c b/src/solver/stats.c
index 2e4d2f7fc..be05e73d4 100644
--- a/src/solver/stats.c
+++ b/src/solver/stats.c
@@ -592,7 +592,7 @@ void stats_updateNodeStats(int j, double tStep, DateTime aDate)
         k = Node[j].subIndex;
         StorageStats[k].avgVol += newVolume;
         StorageStats[k].evapLosses += 
-            Storage[Node[j].subIndex].evapLoss; 
+            Storage[Node[j].subIndex].evapLoss;
         StorageStats[k].exfilLosses +=
             Storage[Node[j].subIndex].exfilLoss; 
 
diff --git a/src/solver/statsrpt.c b/src/solver/statsrpt.c
index f76ef7a48..baa3a40d8 100644
--- a/src/solver/statsrpt.c
+++ b/src/solver/statsrpt.c
@@ -3,7 +3,7 @@
 //
 //   Project:  EPA SWMM5
 //   Version:  5.2
-//   Date:     06/01/22 (Build 5.2.1)
+//   Date:     11/19/22 (Build 5.2.2)
 //   Author:   L. Rossman
 //
 //   Report writing functions for summary statistics.
@@ -27,6 +27,9 @@
 //   - Fixes value used for total reporting time.
 //   Build 5.2.1:
 //   - Replaces the "3" in "ft3" and "m3" with ANSI superscript (\xB3).
+//   Build 5.2.2
+//   - Calculation of % Evaporation and % Exfiltration losses for storage
+//     units was corrected.
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
@@ -512,7 +515,7 @@ void writeStorageVolumes()
 {
     int    j, k, days, hrs, mins;
     double avgVol, maxVol, pctAvgVol, pctMaxVol;
-    double addedVol, pctEvapLoss, pctSeepLoss;
+    double pctEvapLoss, pctSeepLoss;
 
     if ( Nnodes[STORAGE] > 0 )
     {
@@ -524,16 +527,16 @@ void writeStorageVolumes()
         
 // OWA EDIT - write unicode super script 3 (\xC2\xB3) instead of extended ascii (\xB3)
         fprintf(Frpt.file,
-"\n  --------------------------------------------------------------------------------------------------"
-"\n                         Average     Avg  Evap Exfil       Maximum     Max    Time of Max    Maximum"
-"\n                          Volume    Pcnt  Pcnt  Pcnt        Volume    Pcnt     Occurrence    Outflow");
+"\n  ------------------------------------------------------------------------------------------------"
+"\n                         Average    Avg   Evap  Exfil     Maximum    Max    Time of Max    Maximum"
+"\n                          Volume   Pcnt   Pcnt   Pcnt      Volume   Pcnt     Occurrence    Outflow");
         if ( UnitSystem == US ) fprintf(Frpt.file,
-"\n  Storage Unit          1000 ft\xC2\xB3    Full  Loss  Loss      1000 ft\xC2\xB3    Full    days hr:min        ");
+"\n  Storage Unit          1000 ft\xC2\xB3   Full   Loss   Loss    1000 ft\xC2\xB3   Full    days hr:min        ");
         else fprintf(Frpt.file,
-"\n  Storage Unit           1000 m\xC2\xB3    Full  Loss  Loss       1000 m\xC2\xB3    Full    days hr:min        ");
+"\n  Storage Unit           1000 m\xC2\xB3   Full   Loss   Loss     1000 m\xC2\xB3   Full    days hr:min        ");
         fprintf(Frpt.file, "%3s", FlowUnitWords[FlowUnits]);
         fprintf(Frpt.file,
-"\n  --------------------------------------------------------------------------------------------------");
+"\n  ------------------------------------------------------------------------------------------------");
 
         for ( j = 0; j < Nobjects[NODE]; j++ )
         {
@@ -551,14 +554,13 @@ void writeStorageVolumes()
             }
             pctEvapLoss = 0.0;
             pctSeepLoss = 0.0;
-            addedVol = NodeInflow[j] + StorageStats[k].initVol;
-            if ( addedVol > 0.0 )
+            if ( NodeInflow[j] > 0.0 )
             {
-                pctEvapLoss = StorageStats[k].evapLosses / addedVol * 100.0;
-                pctSeepLoss = StorageStats[k].exfilLosses / addedVol * 100.0;
+                pctEvapLoss = StorageStats[k].evapLosses / NodeInflow[j] * 100.0;
+                pctSeepLoss = StorageStats[k].exfilLosses / NodeInflow[j] * 100.0;
             }
 
-            fprintf(Frpt.file, "%10.3f    %4.0f  %4.0f  %4.0f    %10.3f    %4.0f",
+            fprintf(Frpt.file, "%10.3f  %5.1f  %5.1f  %5.1f  %10.3f  %5.1f",
                 avgVol*UCF(VOLUME)/1000.0, pctAvgVol, pctEvapLoss, pctSeepLoss,
                 maxVol*UCF(VOLUME)/1000.0, pctMaxVol);
 
diff --git a/src/solver/swmm5.c b/src/solver/swmm5.c
index 3ef3f6fc7..bf3b63b4a 100644
--- a/src/solver/swmm5.c
+++ b/src/solver/swmm5.c
@@ -17,7 +17,7 @@
 //   ==============
 //   Build 5.1.008:
 //   - Support added for the MinGW compiler.
-//   - Reporting of project options moved to swmm_start. 
+//   - Reporting of project options moved to swmm_start.
 //   - Hot start file now read before routing system opened.
 //   - Final routing step adjusted so that total duration not exceeded.
 //   Build 5.1.011:
@@ -126,7 +126,7 @@
 //-----------------------------------------------------------------------------
 //  Unit conversion factors
 //-----------------------------------------------------------------------------
-const double Ucf[10][2] = 
+const double Ucf[10][2] =
       {//  US      SI
       {43200.0,   1097280.0 },         // RAINFALL (in/hr, mm/hr --> ft/sec)
       {12.0,      304.8     },         // RAINDEPTH (in, mm --> ft)
@@ -431,9 +431,9 @@ int DLLEXPORT swmm_start(int saveResults)
         massbal_open();
         stats_open();
 
-        // --- write heading for control actions listing 
-	    if (!RptFlags.disabled && RptFlags.controls)
-                report_writeControlActionsHeading();
+        // --- write heading for control actions listing
+        if (!RptFlags.disabled && RptFlags.controls)
+            report_writeControlActionsHeading();
     }
 
 #ifdef EXH
@@ -457,7 +457,7 @@ int DLLEXPORT swmm_step(double *elapsedTime)
 {
     // --- check that simulation can proceed
     *elapsedTime = 0.0;
-    if ( ErrorCode ) 
+    if ( ErrorCode )
         return ErrorCode;
     if ( !IsOpenFlag )
         return (ErrorCode = ERR_API_NOT_OPEN);
@@ -594,7 +594,7 @@ void execRouting()
 
         // --- if no runoff analysis, update climate state (for evaporation)
         else climate_setState(getDateTime(NewRoutingTime));
-  
+
         // --- route flows & pollutants through drainage system
         //     (while updating NewRoutingTime)
         if ( DoRouting )
@@ -883,7 +883,7 @@ double  DLLEXPORT swmm_getValue(int property, int index)
 //
 //  Input:   property = an object's property code
 //           index = the object's index in the array of like objects
-//           
+//
 //  Output:  returns the property's current value
 //  Purpose: retrieves the value of an object's property.
 {
@@ -925,7 +925,7 @@ void  DLLEXPORT swmm_setValue(int property, int index, double value)
     case swmm_SUBCATCH_RPTFLAG:
         if (!IsStartedFlag && index >= 0 && index < Nobjects[SUBCATCH])
             Subcatch[index].rptFlag = (value > 0.0);
-        return;            
+        return;
     case swmm_NODE_LATFLOW:
         setNodeLatFlow(index, value);
         return;
@@ -935,20 +935,20 @@ void  DLLEXPORT swmm_setValue(int property, int index, double value)
     case swmm_NODE_RPTFLAG:
         if (!IsStartedFlag && index >= 0 && index < Nobjects[NODE])
             Node[index].rptFlag = (value > 0.0);
-        return;            
+        return;
     case swmm_LINK_SETTING:
         setLinkSetting(index, value);
         return;
     case swmm_LINK_RPTFLAG:
         if (!IsStartedFlag && index >= 0 && index < Nobjects[LINK])
             Link[index].rptFlag = (value > 0.0);
-        return;            
+        return;
     case swmm_ROUTESTEP:
         setRoutingStep(value);
         return;
     case swmm_REPORTSTEP:
         if (!IsStartedFlag && value > 0)
-            ReportStep = (int)value;                
+            ReportStep = (int)value;
         return;
     case swmm_NOREPORT:
         if (!IsStartedFlag)
@@ -963,8 +963,8 @@ double  DLLEXPORT swmm_getSavedValue(int property, int index, int period)
 //
 //  Input:   property = an object's property code
 //           index = the object's index in the array of like objects
-//           period = a reporting time period (starting from 1) 
-//  Output:  returns the property's saved value 
+//           period = a reporting time period (starting from 1)
+//  Output:  returns the property's saved value
 //  Purpose: retrieves an object's computed value at a specific reporting time period.
 {
     if (!IsOpenFlag)
@@ -1078,7 +1078,7 @@ double getNodeValue(int property, int index)
         case swmm_NODE_DEPTH:
           return node->newDepth * UCF(LENGTH);
         case swmm_NODE_HEAD:
-          return (node->newDepth + node->invertElev) * UCF(LENGTH); 
+          return (node->newDepth + node->invertElev) * UCF(LENGTH);
         case swmm_NODE_VOLUME:
           return node->newVolume * UCF(VOLUME);
         case swmm_NODE_LATFLOW:
@@ -1258,7 +1258,7 @@ double getSavedDate(int period)
 //
 //  Input:   period = a reporting period (starting at 1)
 //  Output:  returns the date/time of the reporting period in decimal days
-//  Purpose: retrieves the date/time of a reporting period. 
+//  Purpose: retrieves the date/time of a reporting period.
 {
     double days;
     output_readDateTime(period, &days);
diff --git a/src/solver/table.c b/src/solver/table.c
index aced49e13..f5917cacb 100644
--- a/src/solver/table.c
+++ b/src/solver/table.c
@@ -3,7 +3,7 @@
 //
 //   Project:  EPA SWMM5
 //   Version:  5.2
-//   Date:     11/01/21   (Build 5.2.0)
+//   Date:     10/17/22   (Build 5.2.2)
 //   Author:   L. Rossman
 //
 //   Table (curve and time series) functions.
@@ -28,6 +28,8 @@
 //   - The table_getInverseArea function was renamed table_getStorageDepth and
 //     was refactored.
 //   - Support added for relative file names.
+//   Build 5.2.2:
+//   - Prevent re-reading a time series file from start once end is reached.
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
@@ -759,6 +761,13 @@ double table_tseriesLookup(TTable *table, double x, char extend)
     &&   table->x2 >= x
     &&   table->x1 != table->x2 )
     return table_interpolate(x, table->x1, table->y1, table->x2, table->y2);
+    
+    // --- end of external time series file has been reached
+    if ( table->file.mode == USE_FILE && feof(table->file.file) )
+    {
+        if (extend == TRUE) return table->y1;
+        else return 0;
+    }
 
     // --- x lies before current time bracket:
     //     move to start of time series
diff --git a/src/solver/text.h b/src/solver/text.h
index 70bfc1f50..8448978c4 100644
--- a/src/solver/text.h
+++ b/src/solver/text.h
@@ -3,7 +3,7 @@
 //
 //   Project: EPA SWMM5
 //   Version: 5.2
-//   Date:    06/01/22  (Build 5.2.1)
+//   Date:    10/18/22  (Build 5.2.2)
 //   Author:  L. Rossman
 //
 //   Text strings
@@ -25,7 +25,7 @@
 #define FMT03 " There are errors.\n"
 #define FMT04 " There are warnings.\n"
 #define FMT08 \
-  "\n  EPA STORM WATER MANAGEMENT MODEL - VERSION 5.2 (Build 5.2.1)"
+  "\n  EPA STORM WATER MANAGEMENT MODEL - VERSION 5.2 (Build 5.2.2)"
 #define FMT09 \
   "\n  ------------------------------------------------------------"
 #define FMT10 "\n"
diff --git a/src/solver/xsect.c b/src/solver/xsect.c
index 5ebab53c0..1a53d36e2 100644
--- a/src/solver/xsect.c
+++ b/src/solver/xsect.c
@@ -3,7 +3,7 @@
 //
 //   Project:  EPA SWMM5
 //   Version:  5.2
-//   Date:     11/01/21   (Build 5.2.0)
+//   Date:     10/17/22   (Build 5.2.2)
 //   Author:   L. Rossman
 //             M. Tryby (EPA)
 //
@@ -32,6 +32,8 @@
 //   - Width at full height set to 0 for closed rectangular shape.
 //   Build 5.2.0:
 //   - Support added for Street cross sections.
+//   Build 5.2.2:
+//   - Feasibility check added to Mod. Baskethandle & Rect.-Round shapes.
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
@@ -430,6 +432,7 @@ int xsect_setParams(TXsect *xsect, int type, double p[], double ucf)
 
         // --- depth of circular bottom
         xsect->yBot  = xsect->rBot * (1.0 - cos(theta/2.0));
+        if (xsect->yBot > xsect->yFull) return FALSE;
         xsect->ywMax = xsect->yFull;
 
         xsect->aFull = xsect->wMax * (xsect->yFull - xsect->yBot) + xsect->aBot;
@@ -455,6 +458,7 @@ int xsect_setParams(TXsect *xsect, int type, double p[], double ucf)
 
         // --- height of circular arc
         xsect->yBot = xsect->rBot * (1.0 - cos(theta/2.0));
+        if (xsect->yBot > xsect->yFull) return FALSE;
         xsect->ywMax = xsect->yFull - xsect->yBot;
 
         // --- area of circular arc
diff --git a/src/solver/xsect.dat b/src/solver/xsect.dat
index 10b10ed33..fbecb58ac 100644
--- a/src/solver/xsect.dat
+++ b/src/solver/xsect.dat
@@ -3,7 +3,7 @@
 //
 //   Project:  EPA SWMM5
 //   Version:  5.2
-//   Date:     06/01/22   (Build 5.2.1)
+//   Date:     08/01/22   (Build 5.2.1)
 //   Author:   L. Rossman
 //
 //   Tables of relative geometric properties for rounded cross-sections.


Test patch:
diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml
index 2e2d3ee1f..c224b9e7d 100644
--- a/.github/workflows/build-test.yml
+++ b/.github/workflows/build-test.yml
@@ -144,7 +144,7 @@ jobs:
       - name: Before reg test
         env:
           NRTESTS_URL: https://github.com/OpenWaterAnalytics/swmm-nrtestsuite
-          BENCHMARK_TAG: v3.0.0
+          BENCHMARK_TAG: v3.0.1
         run: ./${{ matrix.before_reg_test }} ${{ env.BENCHMARK_TAG }}
 
       - name: Run reg test