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

Issue:
Update flow direction in API function
Bug report issue from pyswmm: https://github.com/OpenWaterAnalytics/pyswmm/issues/302

https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/8e4610611ae3d61edac53518dc65d67108b400f3/src/solver/toolkit.c#L2007

From @bemcdonnell research:

>When the model is loaded, based on the slope of the pipes, a link is reversed inside SWMM to keep a positive slope between the nodes. As a result, swmm solves flows with the link reversed and when we output to the OUT/RPT files, the flows are multiplied by -1 for those reversed links. The follow variable is stored

https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/8e4610611ae3d61edac53518dc65d67108b400f3/src/solver/objects.h#L677

When we scrape results from the running sim, you are seeing the number that the solver sees. What we should be doing inside the API is multiplying the output for flow by the flow direction value (which is either 1 or -1).


add unit test for link flow getter
tests positive and negative sloped conditions

@jennwuu
Add CITATION Reference File
Add citation reference file to direct users on how to cite OWA SWMM in publications.
Update .rpt text to indicate OWA SWMM codebase
Related to discussion from #352 

It is important user understands the source of model results [re-replicating results, documentation, etc]. When a user views .rpt, the header is not descriptive to indicate which source of engine used. I think this is important as we add more features in the api. 

At the moment, the .rpt file shows:
```
  EPA STORM WATER MANAGEMENT MODEL - VERSION 5.1 (Build 5.1.14)
  --------------------------------------------------------------
```

Update flow direction in API function
Bug report issue from pyswmm: https://github.com/OpenWaterAnalytics/pyswmm/issues/302

https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/8e4610611ae3d61edac53518dc65d67108b400f3/src/solver/toolkit.c#L2007

From @bemcdonnell research:

>When the model is loaded, based on the slope of the pipes, a link is reversed inside SWMM to keep a positive slope between the nodes. As a result, swmm solves flows with the link reversed and when we output to the OUT/RPT files, the flows are multiplied by -1 for those reversed links. The follow variable is stored

https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/8e4610611ae3d61edac53518dc65d67108b400f3/src/solver/objects.h#L677

When we scrape results from the running sim, you are seeing the number that the solver sees. What we should be doing inside the API is multiplying the output for flow by the flow direction value (which is either 1 or -1).




Discussion / hints:

Fix patch:
diff --git a/.gitignore b/.gitignore
index 9aed7e952..fec94365b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,7 @@
 
 
 # Build files
+ci-tools/
 build/
 *.o
 /Debug/
@@ -45,3 +46,4 @@ tests/solver/data/feng*
 
 # Generated files
 *_export.h
+version.h
diff --git a/AUTHORS b/AUTHORS
deleted file mode 100644
index f76d9c764..000000000
--- a/AUTHORS
+++ /dev/null
@@ -1,26 +0,0 @@
-# Authors ordered by first contribution.
-
-
-Authors with Contributions in the Public Domain:
-
-Lewis Rossman <LRossman@cinci.rr.com>
-Robert Dickinson <robert.dickinson@gmail.com>
-Michael Tryby <tryby.michael@epa.gov>
-Katherine Ratliff <ratliff.katherine@epa.gov>
-Michelle Simon <simon.michelle@epa.gov>
-
-
-Authors with Contributions Subject to Copyright (see LICENSE):
-
-Bryant E. McDonnell <bemcdonnell@gmail.com>
-Adam Erispaha <aerispaha@gmail.com>
-Sam Hatchett <samhatchett@gmail.com>
-Gonzalo Peña-Castellanos <goanpeca@gmail.com>
-Abhiram Mullapudi <abhiramm@umich.edu>
-Jennifer Wu <wuu.jennifer@gmail.com >
-Dominik Leutnant <leutnant@fh-muenster.de>
-Xu Xi <12907470@qq.com>
-Caleb Buahin <caleb.buahin@gmail.com>
-Hsi-Nien Tan <hsi-nien.tan@vumc.org>
-Mingda Zhang <mingda_zhang@163.com>
-Laurent Courty <lrntct@gmail.com>
diff --git a/CITATION.cff b/CITATION.cff
new file mode 100644
index 000000000..4723ae477
--- /dev/null
+++ b/CITATION.cff
@@ -0,0 +1,23 @@
+cff-version: 1.2.0
+message: "If you use this software, please cite it as below."
+authors:
+- family-names: "McDonnell"
+  given-names: "Bryant"
+  orcid: "https://orcid.org/0000-0002-6250-2220"
+- family-names: "Wu"
+  given-names: "Jia Xin"
+  orcid: "https://orcid.org/0000-0003-2233-9542"
+- family-names: "Ratliff"
+  given-names: "Katherine"
+  orcid: "https://orcid.org/0000-0003-1410-2756"
+- family-names: "Mullapudi"
+  given-names: "Abhiram"
+  orcid: "https://orcid.org/0000-0001-8141-3621"
+- family-names: "Tryby"
+  given-names: "Michael"
+  orcid: "https://orcid.org/0000-0001-5525-0734"
+title: "Open Water Analytics Stormwater Management Model"
+version: 5.1.13
+doi: 10.5281/zenodo.5484299
+date-released: 2021-01-12
+url: "https://github.com/OpenWaterAnalytics/Stormwater-Management-Model"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 77fee6f75..087455567 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -4,10 +4,14 @@
 # Created: July 11, 2019
 # Updated: May 19, 2021
 #
-# Author: Michael E. Tryby
-#         US EPA ORD/CESER
+# Authors: Michael E. Tryby
+#          US EPA ORD/CESER
 #
 
+################################################################################
+##################    CMAKELISTS FOR SWMM-SOLVER PROJECT    ####################
+################################################################################
+
 
 cmake_minimum_required (VERSION 3.13)
 
@@ -18,9 +22,9 @@ endif()
 
 
 project(swmm-solver
-    VERSION 5.1.13
+    VERSION 5.1.14
     LANGUAGES C CXX
-    )
+)
 
 # Append local dir to module search path
 # list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
@@ -41,9 +45,12 @@ set(LIBRARY_DIST "lib")
 set(CONFIG_DIST  "cmake")
 
 
+# Define build options
 option(BUILD_TESTS "Build component tests (requires Boost)" OFF)
 option(BUILD_DOCS "Build toolkit docs (requires Doxygen)" OFF)
 
+# Added option to statically link libraries to address GitHub Ubuntu 20.04 symbol errors (issue #340)
+option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
 
 # Add project subdirectories
 if(BUILD_DOCS)
@@ -68,11 +75,11 @@ endif()
 include(InstallRequiredSystemLibraries)
 
 
-# Create install target for License and Authors files
+# Create install target for License and Contributors files
 install(
     FILES
         "LICENSE"
-        "AUTHORS"
+        "CONTRIBUTORS"
     DESTINATION
         "."
 )
@@ -80,7 +87,7 @@ install(
 
 # Configure CPack driven installer package
 set(CPACK_GENERATOR "ZIP;TGZ")
-set(CPACK_PACKAGE_VENDOR "US_EPA")
+set(CPACK_PACKAGE_VENDOR "OWA")
 set(CPACK_ARCHIVE_FILE_NAME "swmm")
 
 include(CPack)
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
new file mode 100644
index 000000000..7245880ab
--- /dev/null
+++ b/CONTRIBUTORS
@@ -0,0 +1,111 @@
+#
+# CONTRIBUTORS
+#
+# List of people whose contributions reside in the default branch
+# of OWA SWMM ordered alphabetically by last name. This file is modeled after
+# the CREDITS file maintained by the Linux project.
+#
+# Fields are:
+#   name (N), email (E), license (L), description (D)
+#
+
+N: Colleen Barr
+E: barr.colleen@epa.gov
+L: Public Domain
+D: Output file API
+
+N: Caleb Buahin
+E: caleb.buahin@gmail.com
+L: MIT License
+D: Development operations, bug fix, v5.1.14 merge, review
+
+N: Laurent Courty
+E: lrntct@gmail.com
+L: MIT License
+D: Bug fix, testing
+
+N: Robert Dickinson
+E: robert.dickinson@gmail.com
+L: Public Domain
+D: Legacy maintainer
+
+N: Adam Erispaha
+E: aerispaha@gmail.com
+L: MIT License
+D: Linux makefile
+
+N: Sam Hatchett
+E: samhatchett@gmail.com
+L: MIT License
+D: Development operations
+
+N: Constantine Karos
+E: ckaros@outlook.com
+L: MIT License
+D: Bug fix, testing, development operations, Water quality API
+
+N: Dominik Leutnant
+E: leutnant@fh-muenster.de
+L: MIT License
+D: Mac OS build
+
+N: Brooke Mason
+E: bemason@umich.edu
+L: MIT License
+D: Water quality API, testing
+
+N: Bryant McDonnell
+E: bemcdonnell@gmail.com
+L: MIT License
+D: Founder, maintainer, toolkit API, testing, review, bug fix, documentation
+
+N: Abhiram Mullapudi
+E: abhiramm@umich.edu
+L: MIT License
+D: Rain API, testing, water quality API, development operations, review
+
+N: Gonzalo Peña-Castellanos
+E: goanpeca@gmail.com
+L: MIT License
+D: Development operations, testing, documentation
+
+N: Katherine Ratliff
+E: ratliff.katherine@epa.gov
+L: MIT License
+D: Stats API, bug fix, testing, review
+
+N: Lewis Rossman
+E: LRossman@cinci.rr.com
+L: Public Domain
+D: Legacy developer
+
+N: Michelle Simon
+E: simon.michelle@epa.gov
+L: Public Domain
+D: Documentation
+
+N: Hsi-Nien Tan
+E: hsi-nien.tan@vumc.org
+L: MIT License
+D: Bug fix, testing
+
+N: Michael Tryby
+E: tryby.michael@epa.gov
+L: Public Domain
+D: Mentor, development operations, review
+D: Output library, testing framework, CLI, versioning, Python wrapper
+
+N: Jia Xin Wu
+E: wuu.jennifer@gmail.com
+L: MIT License
+D: Maintainer, LID API, bug fixes, testing, development operations, Python wrapper, review
+
+N: Xu Xi
+E: 12907470@qq.com
+L: MIT License
+D: Bug fix
+
+N: Mingda Zhang
+E: mingda_zhang@163.com
+L: MIT License
+D: Bug fix, testing
diff --git a/LICENSE b/LICENSE
index 270ff7558..1d04a2c91 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,32 +1,17 @@
-This project contains original material released as part of USEPA SWMM v5.1.13.
-Original material residing in the public domain is unclaimable.
-
-This project also contains new material prepared by the United States
-Government for which domestic copyright protection is not available under 17
-USC § 105.
-
-
-Public Domain
-
-Material original to USEPA SWMM v5.1.13 No Copyright Restrictions
 
-Output library, shared objects, CLI, build and test systems No Copyright
-Restrictions 2020 U.S. Federal Government
 
-===============================================================================
 
 This project contains material from https://github.com/OpenWaterAnalytics/
-Stormwater-Management-Model. All material created by the AUTHORS is released
-under the MIT License.
+Stormwater-Management-Model. All material created by the CONTRIBUTORS is released
+under the MIT License unless otherwise noted.
 
 OWA SWMM may also includes third-party software libraries which have separate
 licensing policies.
 
 
-
 MIT License
 
-Copyright (c) 2020 see AUTHORS, excluding material in the public
+Copyright (c) 2020-2021 see CONTRIBUTORS, excluding material in the public
 domain.
 
 
@@ -49,6 +34,25 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 
 
+===============================================================================
+
+This project contains original material released as part of USEPA SWMM v5.1.14.
+Original material residing in the public domain is unclaimable.
+
+This project also contains new material prepared by the United States
+Government for which domestic copyright protection is not available under 17
+USC § 105.
+
+
+Public Domain
+
+Material original to USEPA SWMM v5.1.14 No Copyright Restrictions
+
+Output library, shared objects, CLI, build and test systems No Copyright
+Restrictions 2020-2021 U.S. Federal Government
+
+
+===============================================================================
 
 Third-Party Libraries
 
diff --git a/README.md b/README.md
index a74ea77ad..e5c747a1b 100644
--- a/README.md
+++ b/README.md
@@ -2,34 +2,45 @@
 
 ORD Stormwater Management Model (aka "SWMM")
 
+## Introduction
+This is the open source SWMM source code repository maintained by the Open
+Water Analytics group.
+
+SWMM is a dynamic hydrology-hydraulic water quality simulation model. It is
+used for single event or long-term (continuous) simulation of runoff quantity
+and quality from primarily urban areas. SWMM source code is written in the C
+Programming Language and released under combination a of MIT-License and Public
+Domain. For more information on licensing, please see the [LICENSE](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/develop/LICENSE).
+
 ## Project Information
 
-[![license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model)
-[![Join the chat at https://gitter.im/OpenWaterAnalytics/lobby](https://badges.gitter.im/OpenWaterAnalytics/Stormwater-Management-Model.svg)](https://gitter.im/OpenWaterAnalytics/lobby)
+[![license](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/develop/LICENSE)
 [![docs](https://img.shields.io/badge/docs-passing-green.svg)](http://wateranalytics.org/Stormwater-Management-Model/)
 
-## Build Status
 ![build](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/workflows/Build%20and%20Test/badge.svg?branch=master)
 
-# Introduction
-This is the open source SWMM source code repository maintained by the Open
-Water Analytics group.
+## Citing This Work
 
-SWMM is a dynamic hydrology-hydraulic water quality simulation model. It is
-used for single event or long-term (continuous) simulation of runoff quantity
-and quality from primarily urban areas. SWMM source code is written in the C
-Programming Language and released in the Public Domain.
+Open source software is typically developed by unpaid community-forward volunteers
+who see greater purpose for their code bases.  The contributors dedicate much of
+their own time to make robust software so that it can be used and easily understood
+by users.  When you use any of the compiled or raw code, build scripts, testing
+or testing artifacts found in this project consider the amount of time it took
+the contributing members to make it.  The following link provides the appropriate
+way to cite this software. Show your appreciation through proper citation!
+
+[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5484299.svg)](https://doi.org/10.5281/zenodo.5484299)
 
-# Contributing
+## Contributing
 
 Everyone is welcome to contribute to this project.
 
-See [CONTRIBUTING.md](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/develop/.github/CONTRIBUTING.md) for insructions on setting your development environment.
+See [CONTRIBUTING.md](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/wiki/Contributing) for instructions on setting your development environment.
 
-# Regression Testing
+## OWA-SWMM Testing
 
-To run the test suite for please refer to the [REGRESSION_TESTING.md](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/develop/.github/REGRESSION_TESTING.md)
+To run the test suite for please refer to the [REGRESSION_TESTING.md](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/wiki/Testing-System)
 
-# Code of Conduct
+## Code of Conduct
 
-The SWMM Project follows the [Contributor Covenant Code of Conduct](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/develop/.github/CODE_OF_CONDUCT.md)
+The SWMM Project follows the [Contributor Covenant Code of Conduct](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/wiki/Code-of-Conduct)
diff --git a/ReleaseNotes.md b/ReleaseNotes.md
index 491934fb2..8f1b6155d 100644
--- a/ReleaseNotes.md
+++ b/ReleaseNotes.md
@@ -6,15 +6,17 @@ official USEPA SWMM release.
 
 See the AUTHORS file for a list of contributors.
 
-
-## Toolkit API (new functions):
+## Toolkit API (new functions) 
+--------------------------------
 
 ### Projects
+
 swmm_project_findObject()  
 swmm_getObjectId()  
 swmm_countObjects()  
 
 ### Simulation Settings
+
 swmm_getSimulationDateTime()  
 swmm_getCurrentDateTime()  
 swmm_setSimulationDateTime()  
@@ -23,6 +25,7 @@ swmm_getSimulationParam()
 swmm_getSimulationUnit()  
 
 ### Nodes
+
 swmm_getNodeType()  
 swmm_getNodeParam()  
 swmm_setNodeParam()  
@@ -33,13 +36,16 @@ swmm_setNodeInflow()
 swmm_getNodeStats()  
 
 ### Storage
+
 swmm_getStorageStats()  
 
 ### Outfall
+
 swmm_setOutfallStage()  
 swmm_getOutfallStats()  
 
 ### Links
+
 swmm_getLinkType()  
 swmm_getLinkConnections()  
 swmm_getLinkDirection()  
@@ -51,9 +57,11 @@ swmm_setLinkSetting()
 swmm_getLinkStats()  
 
 ### Pumps
+
 swmm_getPumpStats()  
 
 ### Subcatchments
+
 swmm_getSubcatchOutConnection()  
 swmm_getSubcatchParam()  
 swmm_setSubcatchParam()  
@@ -62,10 +70,12 @@ swmm_getSubcatchPollut()
 swmm_getSubcatchStats()  
 
 ### System
+
 swmm_getSystemRoutingTotals()  
 swmm_getSystemRunoffTotals()  
 
 ### LIDs
+
 swmm_getLidUCount()  
 swmm_getLidUParam()  
 swmm_setLidUParam()  
@@ -79,8 +89,10 @@ swmm_setLidCParam()
 swmm_getLidGResult()  
 
 ### Rain Gages
+
 swmm_getGagePrecip()  
 swmm_setGagePrecip()  
 
 ### Utility
+
 swmm_getVersionInfo()  
diff --git a/docs/AUTHORS.dox b/docs/AUTHORS.dox
index e3e80e375..8e608a884 100644
--- a/docs/AUTHORS.dox
+++ b/docs/AUTHORS.dox
@@ -1,21 +1,9 @@
-/** 
+/**
 @defgroup AUTHORS Authors at Open Water Analytics
 
-The OWA-SWMM project builds on top of the contributions put forward by Lew Rossman with his original work on delivering EPA-SWMM5. We are grateful for all the work that has been put into SWMM5 and we are committed to delivering advances to the engine in a community driven approach. 
+The OWA-SWMM project builds on top of the contributions put forward by Lew Rossman with his original work on delivering EPA-SWMM5. We are grateful for all the work that has been put into SWMM5 and we are committed to delivering advances to the engine in a community driven approach.
 
-- Lewis Rossman <LRossman@cinci.rr.com>*
-- Robert Dickinson <robert.dickinson@gmail.com>*
-- Michael Tryby <tryby.michael@epa.gov>*
-- Bryant E. McDonnell <bemcdonnell@gmail.com>
-- Adam Erispaha <aerispaha@gmail.com>
-- Sam Hatchett <samhatchett@gmail.com>
-- Gonzalo Peña-Castellanos <goanpeca@gmail.com>
-- Katherine Ratliff <ratliff.katherine@epa.gov>*
-- Abhiram Mullapudi <abhiramm@umich.edu>
-- Jennifer Wu <jennifer.wu@live.com>
-- Hsi-Nien Tan <hsi-nien.tan@mail.hyd.ncku.edu.tw>
-
-Authors ordered by first contribution. Author contributions are made under the @subpage MIT-License, except for authors whose contributions are made in the public domain, who are denoted with *.
+The following link provides a list of all contributors as well as their types of contributions [CONTRIBUTORS](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/develop/CONTRIBUTORS)
 
 Stand on the shoulders of Giants! For a list of all the contributors over time (SWMM5 and before), please see [Acknowledgements](https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/wiki/Acknowledgements)
-*/
\ No newline at end of file
+*/
diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt
index f413b5f13..98d6e6ba4 100644
--- a/docs/CMakeLists.txt
+++ b/docs/CMakeLists.txt
@@ -31,7 +31,7 @@ set(DOXY_SOURCES
 
 
 set(DOXYGEN_PROJECT_NAME "OWA-SWMM Toolkit")
-set(DOXYGEN_PROJECT_NUMBER "5.2")
+set(DOXYGEN_PROJECT_NUMBER "5.1.14")
 set(DOXYGEN_OPTIMIZE_OUTPUT_FOR_C "YES")
 set(DOXYGEN_HIDE_SCOPE_NAMES "YES")
 set(DOXYGEN_SHOW_INCLUDE_FILES "NO")
diff --git a/extern/boost.cmake b/extern/boost.cmake
index 4f9c10aaa..839df22ec 100644
--- a/extern/boost.cmake
+++ b/extern/boost.cmake
@@ -7,6 +7,10 @@
 # Author: Michael E. Tryby
 #         US EPA - ORD/CESER
 #
+# Usage: 
+#  Create environment variable with the following pattern -- "BOOST_ROOT_X_XX_X"  
+#  where Xs are the Boost version -- pointing to install location.
+# 
 
 
 if(WIN32)
@@ -17,8 +21,14 @@ else()
 endif()
 
 
-# Environment variable "BOOST_ROOT_X_XX_X" points to local install location
-if (DEFINED ENV{BOOST_ROOT_1_72_0})
+# ADD NEW BOOST LIBRARIES VERSIONS HERE
+if (DEFINED ENV{BOOST_ROOT_1_76_0})
+    set(BOOST_ROOT $ENV{BOOST_ROOT_1_76_0})
+
+elseif (DEFINED ENV{BOOST_ROOT_1_74_0})
+    set(BOOST_ROOT $ENV{BOOST_ROOT_1_74_0})
+
+elseif (DEFINED ENV{BOOST_ROOT_1_72_0})
     set(BOOST_ROOT $ENV{BOOST_ROOT_1_72_0})
 
 elseif(DEFINED ENV{BOOST_ROOT_1_67_0})
@@ -27,9 +37,11 @@ elseif(DEFINED ENV{BOOST_ROOT_1_67_0})
 endif()
 
 
+set(CMAKE_FIND_DEBUG_MODE FALSE)
 find_package(Boost 1.67.0
     COMPONENTS
         unit_test_framework
     )
+set(CMAKE_FIND_DEBUG_MODE FALSE)
 
 include_directories (${Boost_INCLUDE_DIRS})
diff --git a/extern/version.cmake b/extern/version.cmake
new file mode 100644
index 000000000..202d59963
--- /dev/null
+++ b/extern/version.cmake
@@ -0,0 +1,43 @@
+#
+# version.cmake - generate SWMM version information header
+#
+# Created: November 2, 2021
+# Updated:
+#
+# Author:  see CONTRIBUTORS
+#
+# Usage:
+#   GEN_VER_HEADER=ON -- overwrites version.h file with current info 
+#
+
+
+option(GEN_VER_HEADER "Automatically update version header" ON)
+
+if(GEN_VER_HEADER)
+
+    # Get the latest commit hash for the working branch
+    execute_process(
+        COMMAND 
+            git rev-parse HEAD
+        WORKING_DIRECTORY 
+            ${CMAKE_CURRENT_LIST_DIR}
+        OUTPUT_VARIABLE 
+            GIT_HASH
+        OUTPUT_STRIP_TRAILING_WHITESPACE
+    )
+
+    # Generate a build id
+    string(
+        TIMESTAMP BUILD_ID UTC
+    )
+
+    # Configure the version header
+    configure_file(
+        ../../extern/version.h.in version.h
+    )
+
+    file(COPY ${CMAKE_CURRENT_BINARY_DIR}/version.h
+        DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/
+    )
+
+endif()
diff --git a/extern/version.h.in b/extern/version.h.in
new file mode 100644
index 000000000..6fcc6a895
--- /dev/null
+++ b/extern/version.h.in
@@ -0,0 +1,39 @@
+/*
+ *  version.h - SWMM version header file
+ *
+ *  Created on: Nov 2, 2021
+ *  
+ *  Author:     see CONTRIBUTORS
+ *
+ *  Note: 
+ *    The cmake build process automatically generates this file. Do not edit.
+ */
+
+
+#ifndef VERSION_H_
+#define VERSION_H_
+
+
+
+#define PROJECT             "SWMM"
+#define ORGANIZATION        "Open_Water_Analytics"
+
+#define VERSION             "@swmm-solver_VERSION@"
+#define VERSION_MAJOR       @swmm-solver_VERSION_MAJOR@
+#define VERSION_MINOR       @swmm-solver_VERSION_MINOR@
+#define VERSION_PATCH       @swmm-solver_VERSION_PATCH@
+#define GIT_HASH            "@GIT_HASH@"
+
+#define PLATFORM            "@CMAKE_SYSTEM_NAME@"
+#define COMPILER            "@CMAKE_C_COMPILER_ID@"
+#define COMPILER_VERSION    "@CMAKE_C_COMPILER_VERSION@"
+#define BUILD_ID            "@BUILD_ID@"
+
+
+static inline int get_version_legacy() { \
+    return VERSION_MAJOR * 10000 + VERSION_MINOR * 1000 + VERSION_PATCH; \
+}
+
+
+
+#endif /* VERSION_H_ */
diff --git a/src/outfile/CMakeLists.txt b/src/outfile/CMakeLists.txt
index 914eadadc..11b7e5ce8 100644
--- a/src/outfile/CMakeLists.txt
+++ b/src/outfile/CMakeLists.txt
@@ -2,9 +2,11 @@
 # CMakeLists.txt - CMake configuration file for swmm/outfile
 #
 # Created: July 11, 2019
+# Updated: Jan 14, 2021
 #
 # Author: Michael E. Tryby
 #         US EPA ORD/CESER
+#         
 #
 
 # configure file groups
@@ -16,8 +18,7 @@ set(SWMM_OUT_PUBLIC_HEADERS
 
 
 # the binary output file API
-add_library(swmm-output
-    SHARED
+add_library(swmm-output    
         swmm_output.c
         errormanager.c
 )
@@ -41,6 +42,16 @@ file(COPY ${CMAKE_CURRENT_BINARY_DIR}/swmm_output_export.h
 )
 
 
+set_target_properties(swmm-output
+    PROPERTIES
+        MACOSX_RPATH TRUE
+        SKIP_BUILD_RPATH FALSE
+        BUILD_WITH_INSTALL_RPATH FALSE
+        INSTALL_RPATH "${PACKAGE_RPATH}"
+        INSTALL_RPATH_USE_LINK_PATH TRUE
+)
+
+
 install(TARGETS swmm-output
     EXPORT
         swmm-outputTargets
diff --git a/src/outfile/include/swmm_output.h b/src/outfile/include/swmm_output.h
index 3c57ad29e..fbaa394e9 100644
--- a/src/outfile/include/swmm_output.h
+++ b/src/outfile/include/swmm_output.h
@@ -12,6 +12,8 @@
 #ifndef SWMM_OUTPUT_H_
 #define SWMM_OUTPUT_H_
 
+
+
 #define MAXFILENAME 259    // Max characters in file path
 #define MAXELENAME 31      // Max characters in element name
 
@@ -26,6 +28,7 @@ typedef struct Handle *SMO_Handle;
 extern "C" {
 #endif
 
+
 int EXPORT_OUT_API SMO_init(SMO_Handle *p_handle);
 int EXPORT_OUT_API SMO_close(SMO_Handle p_handle);
 int EXPORT_OUT_API SMO_open(SMO_Handle p_handle, const char *path);
@@ -56,8 +59,11 @@ void EXPORT_OUT_API SMO_freeMemory(void *array);
 void EXPORT_OUT_API SMO_clearError(SMO_Handle p_handle_in);
 int EXPORT_OUT_API SMO_checkError(SMO_Handle p_handle_in, char **msg_buffer);
 
+
 #ifdef __cplusplus
 }
 #endif
 
+
+
 #endif /* SWMM_OUTPUT_H_ */
diff --git a/src/outfile/include/swmm_output_enums.h b/src/outfile/include/swmm_output_enums.h
index 15d574eca..e4ab35bf9 100644
--- a/src/outfile/include/swmm_output_enums.h
+++ b/src/outfile/include/swmm_output_enums.h
@@ -2,9 +2,11 @@
  *  swmm_output_enums.h
  *
  *  Created on: October 18, 2019
+ *  Updated on: January 14, 2020
  *
  *  Author: Michael E. Tryby
  *          US EPA - ORD/CESER
+ * 
  */
 
 
@@ -91,8 +93,8 @@ typedef enum {
     SMO_flood_losses,           // (flow units),
     SMO_outfall_flows,          // (flow units),
     SMO_volume_stored,          // (ft3 or m3),
-    SMO_evap_rate               // (in/day or mm/day),
-	//p_evap_rate             // (in/day or mm/day)
+    SMO_evap_rate,              // (in/day or mm/day),
+    SMO_p_evap_rate             // (in/day or mm/day)
 } SMO_systemAttribute;
 
 
diff --git a/src/outfile/swmm_output.c b/src/outfile/swmm_output.c
index 4b7c3b33f..57fa847d6 100644
--- a/src/outfile/swmm_output.c
+++ b/src/outfile/swmm_output.c
@@ -44,7 +44,6 @@ struct IDentry {
 };
 typedef struct IDentry idEntry;
 
-
 //-----------------------------------------------------------------------------
 //  Shared variables
 //-----------------------------------------------------------------------------
@@ -101,7 +100,6 @@ float *newFloatArray(int n);
 int   *newIntArray(int n);
 char  *newCharArray(int n);
 
-
 int EXPORT_OUT_API SMO_init(SMO_Handle *p_handle)
 //  Purpose: Initialized pointer for the opaque SMO_Handle.
 //
@@ -717,7 +715,7 @@ int EXPORT_OUT_API SMO_getSystemAttribute(SMO_Handle p_handle, int periodIndex,
 //
 {
     int     errorcode = 0;
-    float   temp;
+    float   *temp;
     data_t *p_data;
 
     p_data = (data_t *)p_handle;
@@ -726,11 +724,13 @@ int EXPORT_OUT_API SMO_getSystemAttribute(SMO_Handle p_handle, int periodIndex,
         errorcode = -1;
     else if (periodIndex < 0 || periodIndex >= p_data->Nperiods)
         errorcode = 422;
+    else if
+        MEMCHECK(temp = newFloatArray(1)) errorcode = 411;
     else {
         // don't need to loop since there's only one system
-        temp = getSystemValue(p_data, periodIndex, attr);
+        temp[0] = getSystemValue(p_data, periodIndex, attr);
 
-        *outValueArray = &temp;
+        *outValueArray = temp;
         *length        = 1;
     }
 
diff --git a/src/run/CMakeLists.txt b/src/run/CMakeLists.txt
index f203e386c..28325ba82 100644
--- a/src/run/CMakeLists.txt
+++ b/src/run/CMakeLists.txt
@@ -2,6 +2,7 @@
 # CMakeLists.txt - CMake configuration file for swmm-solver/run
 #
 # Created: July 11, 2019
+# Updated: Jan 14, 2021
 #
 # Modified by: Michael E. Tryby
 #              US EPA ORD/NRMRL
diff --git a/src/run/main.c b/src/run/main.c
index 8eefd3ac1..dee6418d2 100644
--- a/src/run/main.c
+++ b/src/run/main.c
@@ -1,16 +1,14 @@
 /*
- *  main.c - Main stub for the command line version of EPA SWMM 5.1
- *
- *  Created on: October 9, 2020
- *  Updated on:
- *
- *  Author:     Michael E. Tryby
- *              US EPA - ORD/CESER
- *
- */
-
-// System includes
+  *  main.c - Main stub for the command line version of EPA SWMM 5.1
+  *
+  *  Created on: October 9, 2020
+  *  Updated on:
+  *
+  *  Author:      See CONTRIBUTORS
+  */
+
 #include <stdio.h>
+#include <time.h>
 #include <string.h>
 #include <math.h>
 
@@ -25,6 +23,19 @@
 #define BAR_LEN 50l
 #define MSG_LEN 84
 
+#define FMT_USAGE \
+"\nUsage:\n \
+ \trunswmm <input file> <report file> <output file>\n\n"
+
+#define FMT_HELP \
+"\n\nOWA Stormwater Management Model (SWMM5) Help\n\n \
+ Commands:\n \
+ \t--help (-h)       Help Docs\n \
+ \t--version (-v)    Build Version\n \
+ \nUsage:\n \
+ \t swmm5 <input file> <report file> <output file>\n\n"
+
+
 static long Start;
 
 
@@ -76,9 +87,7 @@ int  main(int argc, char *argv[])
 //  f3 = name of binary output file if saved (or blank if not saved).
 //
 {
-    // --- check for proper number of command line arguments
     if (argc == 4) {
-        // --- extract file names from command line arguments
         char *inputFile = argv[1];
         char *reportFile = argv[2];
 
@@ -87,13 +96,12 @@ int  main(int argc, char *argv[])
             binaryFile = argv[3];
 
         Start = current_time_millis();
-        // --- run SWMM
         swmm_run_cb(inputFile, reportFile, binaryFile, &progress_bar);
 
         long stop = current_time_millis();
         char time[TIMER_LEN + 1] = {'\0'};
 
-        printf("\n\n... EPA-SWMM completed in %s", format_time(time, stop - Start));
+        printf("\n\n... SWMM completed in %s", format_time(time, stop - Start));
 
         char errMsg[128];
         int  msgLen = 127;
@@ -109,37 +117,26 @@ int  main(int argc, char *argv[])
     }
 
     else if (argc == 2) {
-        // --- extract first argument
         char *arg1 = argv[1];
 
-        if (strcmp(arg1, "--help") == 0 || strcmp(arg1, "-h") == 0) {
-            // Help
-            printf("\n\nEPA Stormwater Management Model (SWMM5) Help\n\n");
-            printf("Commands:\n");
-            printf("\t--help (-h)       Help Docs\n");
-            printf("\t--version (-v)    Build Version\n");
-            printf("\nUsage:\n");
-            printf("\t swmm5 <input file> <report file> <output file>\n\n");
-        }
-        else if (strcmp(arg1, "--version") == 0 || strcmp(arg1, "-v") == 0) {
-            int version = swmm_getVersion();
-            int vMajor = version / 10000;
-            int vMinor = (version - 10000 * vMajor) / 1000;
-            int vRelease = (version - 10000 * vMajor - 1000 * vMinor);
+        if (strcmp(arg1, "--help") == 0 || strcmp(arg1, "-h") == 0)
+            printf(FMT_HELP);
 
-            // Output version number
+        else if (strcmp(arg1, "--version") == 0 || strcmp(arg1, "-v") == 0) {
             printf("\nVersion:\n");
-            printf("\tEPA-SWMM %d.%d.%0d\n\n", vMajor, vMinor, vRelease);
+            printf("\tOWA-SWMM v%s (Build %.10s)\n\n", swmm_getSemVersion(), 
+                swmm_getBuildId());
         }
+
         else {
             printf("\nError:\n");
             printf("\tUnknown Argument (See Help --help)\n\n");
         }
     }
+
     else {
-        printf("\nUsage:\n");
-        printf("\trunswmm <input file> <report file> <output file>\n\n");
+        printf(FMT_USAGE);
     }
 
     return 0;
-}
+}
\ No newline at end of file
diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt
index b3f344107..e10fa4a9a 100644
--- a/src/solver/CMakeLists.txt
+++ b/src/solver/CMakeLists.txt
@@ -14,6 +14,9 @@ find_package(OpenMP
         C
 )
 
+# Generate version header
+include(../../extern/version.cmake)
+
 
 # configure file groups
 set(SWMM_PUBLIC_HEADERS
@@ -28,29 +31,29 @@ file(GLOB
         RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.c *.h
 )
 
+
 if(BUILD_DEF)
-    # Build library with def file interface for backward compatibility
+    # Builds library with def file interface for backward compatibility
     set_source_files_properties(${PROJECT_SOURCE_DIR}/bindings/swmm5.def
         PROPERTIES_HEADER_FILE_ONLY TRUE
     )
 
-    add_library(swmm5
-        SHARED
+    add_library(swmm5        
             ${SWMM_SOURCES}
             ${PROJECT_SOURCE_DIR/bindings/swmm5.def}
             $<TARGET_OBJECTS:shared_objs>
     )
 
 else()
-
-    add_library(swmm5
-        SHARED
+    # Performs standard library build
+    add_library(swmm5        
             ${SWMM_SOURCES}
             $<TARGET_OBJECTS:shared_objs>
     )
 
 endif()
 
+# Sets MSVC compiler flags
 target_compile_options(swmm5
     PUBLIC
         "$<$<C_COMPILER_ID:MSVC>:"
@@ -85,6 +88,29 @@ target_include_directories(swmm5
         ${CMAKE_CURRENT_SOURCE_DIR}/..
 )
 
+include(GenerateExportHeader)
+generate_export_header(swmm5
+    BASE_NAME toolkit  
+    EXPORT_MACRO_NAME EXPORT_TOOLKIT
+    EXPORT_FILE_NAME toolkit_export.h
+    STATIC_DEFINE SHARED_EXPORTS_BUILT_AS_STATIC
+)
+
+file(COPY ${CMAKE_CURRENT_BINARY_DIR}/toolkit_export.h
+    DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/include
+)
+
+
+set_target_properties(swmm5
+    PROPERTIES
+        MACOSX_RPATH TRUE
+        SKIP_BUILD_RPATH FALSE
+        BUILD_WITH_INSTALL_RPATH FALSE
+        INSTALL_RPATH "${PACKAGE_RPATH}"
+        INSTALL_RPATH_USE_LINK_PATH TRUE
+)
+
+
 install(TARGETS swmm5 EXPORT swmm5Targets
     RUNTIME    DESTINATION "${TOOL_DIST}"
     LIBRARY    DESTINATION "${LIBRARY_DIST}"
diff --git a/src/solver/Roadmap.txt b/src/solver/Roadmap.txt
new file mode 100644
index 000000000..11952fad7
--- /dev/null
+++ b/src/solver/Roadmap.txt
@@ -0,0 +1,189 @@
+A Roadmap to the SWMM 5 Engine Source Code
+==========================================
+
+The SWMM 5 computational engine consists of 49 C-code files plus several
+header files. The engine can be compiled either as a Dynamic Link Library
+(DLL) under Windows or as a stand-alone console application under both
+Windows and Linux, depending on which of the #define DLL and #define CLE
+declarations at the top of swmm5.c is commented out.
+
+The following header files contain definitions that are used throughout the
+code and should be consulted if the meaning of a variable, a data structure,
+or a constant is unclear:
+
+enums.h       defines various enumerated (symbolic) constants.
+
+objects.h     defines the major classes of data objects used by SWMM 5.
+
+consts.h      defines useful numerical constants.
+
+text.h        defines various text strings used throughout the code.
+
+macros.h      defines several macros used throughout the code.
+
+globals.h     declares global variables that are referenced in many
+              SWMM 5 code modules.
+
+funcs.h       contains prototypes of functions that can be called from any
+              module of SWMM 5 that #includes funcs.h.
+
+--------------------------------------------------------------------------
+
+The following modules form the main core of the SWMM 5 engine:
+
+swmm5.c       contains functions that provide supervisory control over the
+              program.
+
+project.c     contains functions that create and destroy all project data,
+              establish default values, and look up objects by ID name.
+
+input.c       reads a project's data from an input file.
+
+runoff.c      computes runoff quantity and quality from the project's
+              subcatchments.
+
+routing.c     routes runoff and external inflows through the project's
+              drainage system network of nodes and links.
+
+massbal.c     performs mass balance calculations for runoff and routing.
+
+stats.c       collects summary statistics on flow rates, water depths,
+              solution iterations, and variable time steps for a
+	      simulation.
+
+statsrpt.c    writes summary simulation results to a status report.
+
+output.c      writes/reads runoff and routing results to/from a binary
+              output file.
+
+report.c      prepares a status report of simulation results and, for the
+              command line version of SWMM 5, reports complete results for
+	      selected subcatchments, nodes, and links.
+
+inputrpt.c    writes a summary of a project's input data to the status report.
+
+-------------------------------------------------------------------------------
+
+The following collection of modules are used to perform runoff calculations:
+
+rain.c        places data from external rainfall files into a single rainfall
+              interface file.
+
+gage.c        provides rainfall data, either from an interface file or from an
+              internal time series, for runoff calculations.
+
+climate.c     provides temperature, evaporation, and wind speed data to the
+              simulation.
+
+snow.c        computes snow fall accumulation, snow removal operations, and
+              snow melt for a project's subcatchments.
+
+infil.c       performs infiltration calculations on a project's subcatchments.
+
+gwater.c      computes groundwater fluxes and updates groundwater depths over
+              the project's study area.
+
+subcatch.c    computes rainfall runoff, pollutant buildup and washoff, and
+              street sweeping over individual subcatchments.
+
+landuse.c     evaluates pollutant buildup and washoff functions for a project's
+              various types of land uses.
+
+lid.c         evaluates the hydrologic performance of Low Impact Development
+              practices utilized within subcatchment areas.              
+
+lidproc.c     computes the hydrologic performance of individual LID units.
+
+-------------------------------------------------------------------------------
+
+These modules are used for flow and water quality routing:
+
+flowrout.c     implements top-level control of flow routing through a project's
+               drainage network.
+
+inflow.c       provides direct time series inflows and recurring dry weather
+               inflows to the drainage system's nodes at each step of the
+	       simulation.
+
+rdii.c         computes rainfall dependent infiltration/inflow at selected nodes
+               of the drainage network.
+
+kinwave.c      performs kinematic wave flow routing calculations at each time
+               step of the simulation.
+
+dynwave.c      performs dynamic wave flow routing calculations at each time
+               step of the simulation
+
+dwflow.c       solves the dynamic wave flow continuity and momentum equations in
+               a single conduit over a single time step.
+
+controls.c     implements rule-based control actions on pumps and regulators
+               as the simulation unfolds.
+
+qualrout.c     performs routing of water quality constituents through the
+               study area's drainage system.
+
+treatmnt.c     computes pollutant removal at specific nodes of the drainage
+               system where user-defined treatment functions have been
+	       assigned.
+
+node.c         contains functions used to compute the properties and behavior
+               of the drainage system's nodes which include junctions, flow
+               dividers, storage units, and outfalls.
+
+link.c         contains functions used to compute the properties and behavior
+               of the drainage system's links which include conduits, pumps,
+               orifices, weirs, and outlets.
+
+forcmain.c     computes friction losses in force mains that use either the
+               Hazen-Williams or Darcy-Weisbach equations in place of the
+               Manning equation for pressurized flow.
+
+culvert.c      computes flow reduction in culvert-type conduits due to
+               inlet control using equations from the FHWA HEC-5 circular.
+
+-------------------------------------------------------------------------------
+
+The following modules provide various support functions for SWMM 5:
+
+datetime.c     functions for manipulating dates and times.
+
+error.c        error reporting functions.
+
+findroot.c     equation root finding functions.
+
+hash.c         functions that implement hash tables for fast object retrieval.
+
+hotstart.c     saves or reads the state of the drainage system to or from a
+               hot start file.
+
+iface.c        functions for reading from and writing to routing interface
+               files.
+
+keywords.c     defines lists of keywords that appear as part of a SWMM 5
+               input file.
+
+mathexpr.c     functions that parse and evaluate user-supplied mathematical
+               expressions for pollutant removal at treatment nodes.
+
+mempool.c      functions that provide a memory pool used to store object
+               ID names.
+
+odesolve.c     implementation of a fifth-order Runge-Kutta ordinary
+               differential equation solver.
+
+shape.c        functions that compute the geometric cross-section properties
+               of closed conduits with user-defined shapes.
+
+table.c        functions used for accessing lookup tables that contain
+               SWMM 5's curve data and time series data.
+
+toposort.c     functions used to topologically sort the links of a drainage
+               network and detect any closed cyclic loops.
+
+transect.c     functions that create geometric tables for irregular shaped
+               cross section transects.
+
+xsect.c        functions that compute geometric properties of conduit cross
+               sections.
+             
\ No newline at end of file
diff --git a/src/solver/swmm5.def b/src/solver/bindings/swmm5.def
similarity index 100%
rename from src/solver/swmm5.def
rename to src/solver/bindings/swmm5.def
diff --git a/src/solver/consts.h b/src/solver/consts.h
index 6df094e7a..62bf52747 100644
--- a/src/solver/consts.h
+++ b/src/solver/consts.h
@@ -6,6 +6,7 @@
 //   Date:    03/20/14  (Build 5.1.001)
 //            08/01/16  (Build 5.1.011)
 //            05/10/18  (Build 5.1.013)
+//            03/01/20  (Build 5.1.014)
 //   Author:  L. Rossman
 //
 //   Various Constants
@@ -14,14 +15,6 @@
 //------------------
 // General Constants
 //------------------
-
-// Update VERSION and SEMVERSION Simultaneously
-#define   VERSION            51013          // Eventually will be deprecated.
-#define   SEMVERSION_MAJOR   "5"            // Major Semantic Version
-#define   SEMVERSION_MINOR   "1"            // Minor Semantic Version
-#define   SEMVERSION_PATCH   "13"           // Patch Semantic Version
-#define   SEMVERSION_LEN     20             // Version String Len
-
 #define   MAGICNUMBER        516114522
 #define   EOFMARK            0x1A           // Use 0x04 for UNIX systems
 #define   MAXTITLE           3              // Max. # title lines
diff --git a/src/solver/dwflow.c b/src/solver/dwflow.c
index 420a6898d..de096ad38 100644
--- a/src/solver/dwflow.c
+++ b/src/solver/dwflow.c
@@ -7,6 +7,7 @@
 //             03/19/15   (Build 5.1.008)
 //             03/14/17   (Build 5.1.012)
 //             05/10/18   (Build 5.1.013)
+//             03/01/20   (Build 5.1.014)
 //   Author:   L. Rossman (EPA)
 //             M. Tryby (EPA)
 //             R. Dickinson (CDM)
@@ -23,6 +24,11 @@
 //   Build 5.1.013:
 //   - Preissmann slot surcharge option implemented.
 //   - Changed sign of uniform loss rate term (dq6) in flow updating equation.
+//
+//   Build 5.1.014:
+//   - Conduit evap. and seepage loss initialized to 0 in dwflow_findConduitFlow.
+//   - Most current flow (qLast) used instead of previous time period flow
+//     (qOld) in call to link_getLossRate. 
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
@@ -96,6 +102,8 @@ void  dwflow_findConduitFlow(int j, int steps, double omega, double dt)
     barrels = Conduit[k].barrels;
     qOld = Link[j].oldFlow / barrels;
     qLast = Conduit[k].q1;
+    Conduit[k].evapLossRate = 0.0;                                             //(5.1.014)
+    Conduit[k].seepLossRate = 0.0;                                             //(5.1.014)
 
     // --- get most current heads at upstream and downstream ends of conduit
     n1 = Link[j].node1;
@@ -226,7 +234,7 @@ void  dwflow_findConduitFlow(int j, int steps, double omega, double dt)
     }
 
     // --- 6. term for evap and seepage losses per unit length
-    dq6 = link_getLossRate(j, qOld, dt) * 2.5 * dt * v / link_getLength(j);
+    dq6 = link_getLossRate(j, qLast) * 2.5 * dt * v / link_getLength(j);       //(5.1.014)
 
     // --- combine terms to find new conduit flow
     denom = 1.0 + dq1 + dq5;
diff --git a/src/solver/dynwave.c b/src/solver/dynwave.c
index 40b6a71a6..294adc873 100644
--- a/src/solver/dynwave.c
+++ b/src/solver/dynwave.c
@@ -45,6 +45,10 @@
 //   - Storage nodes allowed to pressurize if their surcharge depth > 0.
 //   - Minimum flow needed to compute a Courant time step modified.
 //
+//   Build 5.1.014:
+//   - updateNodeFlows() modified to subtract conduit evap. and seepage losses
+//     from downstream node inflow instead of upstream node outflow.
+//
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
@@ -541,18 +545,19 @@ void updateNodeFlows(int i)
         k = Link[i].subIndex;
         uniformLossRate = Conduit[k].evapLossRate + Conduit[k].seepLossRate; 
         barrels = Conduit[k].barrels;
+        uniformLossRate *= barrels;                                            //(5.1.014)
     }
 
     // --- update total inflow & outflow at upstream/downstream nodes
     if ( q >= 0.0 )
     {
-        Node[n1].outflow += q + uniformLossRate;
-        Node[n2].inflow  += q;
+        Node[n1].outflow += q;                                                 //(5.1.014)
+        Node[n2].inflow  += q - uniformLossRate;                               //(5.1.014)
     }
     else
     {
-        Node[n1].inflow   -= q;
-        Node[n2].outflow  -= q - uniformLossRate;
+        Node[n1].inflow   -= q + uniformLossRate;                              //(5.1.014)
+        Node[n2].outflow  -= q;                                                //(5.1.014)
     }
 
     // --- add surf. area contributions to upstream/downstream nodes
diff --git a/src/solver/flowrout.c b/src/solver/flowrout.c
index 7b2503d40..b50b12787 100644
--- a/src/solver/flowrout.c
+++ b/src/solver/flowrout.c
@@ -7,6 +7,7 @@
 //             09/15/14  (Build 5.1.007)
 //             03/19/15  (Build 5.1.008)
 //             03/14/17  (Build 5.1.012)
+//             03/01/20  (Build 5.1.014)
 //   Author:   L. Rossman (EPA)
 //             M. Tryby (EPA)
 //
@@ -25,6 +26,9 @@
 //   - Overflow computed in updateStorageState() must be non-negative.
 //   - Terminal storage nodes now updated corectly.
 //
+//   Build 5.1.014:
+//   - Arguments to function link_getLossRate changed.
+//
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
@@ -766,7 +770,7 @@ int steadyflow_execute(int j, double* qin, double* qout, double tStep)
         else 
         {
             // --- adjust flow for evap and infil losses
-            q -= link_getLossRate(j, q, tStep);
+            q -= link_getLossRate(j, q);                                       //(5.1.014)
          
             // --- flow can't exceed full flow 
             if ( q > Link[j].qFull )
diff --git a/src/solver/funcs.h b/src/solver/funcs.h
index ce480964e..4199e54c3 100644
--- a/src/solver/funcs.h
+++ b/src/solver/funcs.h
@@ -8,6 +8,7 @@
 //             04/02/15  (Build 5.1.008)
 //             08/05/15  (Build 5.1.010)
 //             05/10/18  (Build 5.1.013)
+//             03/01/20  (Build 5.1.014)
 //   Author:   L. Rossman (EPA)
 //             M. Tryby (EPA)
 //
@@ -27,6 +28,9 @@
 //   Build 5.1.013:
 //   - Additional arguments added to function stats_updateSubcatchStats.
 //
+//   Build 5.1.014:
+//   - Arguments to link_getLossRate function changed.
+//
 //-----------------------------------------------------------------------------
 
 void     project_open(char *f1, char *f2, char *f3);
@@ -336,9 +340,7 @@ void    node_initState(int node);
 void    node_initInflow(int node, double tStep);
 void    node_setOldHydState(int node);
 void    node_setOldQualState(int node);
-
 void    node_setOutletDepth(int node, double yNorm, double yCrit, double z);
-void    node_setDividerCutoff(int node, int link);
 
 double  node_getSurfArea(int node, double depth);
 double  node_getDepth(int node, double volume);
@@ -415,7 +417,7 @@ double  link_getYnorm(int link, double q);
 double  link_getVelocity(int link, double q, double y);
 double  link_getFroude(int link, double v, double y);
 double  link_getPower(int link);
-double  link_getLossRate(int link, double q, double tStep);
+double  link_getLossRate(int link, double q);                                  //(5.1.014)
 char    link_getFullState(double a1, double a2, double aFull);
 
 void    link_getResults(int link, double wt, float x[]);
@@ -519,4 +521,3 @@ void     writecon(char *s);                   // writes string to console
 DateTime getDateTime(double elapsedMsec);     // convert elapsed time to date
 void     getElapsedTime(DateTime aDate,       // convert elapsed date
          int* days, int* hrs, int* mins);
-void     getSemVersion(char* semver);         // get semantic version
diff --git a/src/solver/globals.h b/src/solver/globals.h
index 1d7c9207e..b3d2ca403 100644
--- a/src/solver/globals.h
+++ b/src/solver/globals.h
@@ -97,7 +97,8 @@ EXTERN int
                   SweepEnd,                 // Day of year when sweeping ends
                   MaxTrials,                // Max. trials for DW routing
                   NumThreads,               // Number of parallel threads used
-                  NumEvents;                // Number of detailed events
+                  NumEvents,                // Number of detailed events
+		  ExtPollutFlag;	    // Enable external pollutant injection
                 //InSteadyState;            // System flows remain constant
 
 EXTERN double
diff --git a/src/solver/include/swmm5.h b/src/solver/include/swmm5.h
index 906332005..7753a0553 100644
--- a/src/solver/include/swmm5.h
+++ b/src/solver/include/swmm5.h
@@ -1,14 +1,15 @@
-/** @file swmm5.h
- @see http://github.com/openwateranalytics/stormwater-management-model
-
- swmm5.h
- @brief Prototypes for SWMM5 functions exported to swmm5.dll.
- @date 03/24/14  (Build 5.1.001)
- @date 08/01/16  (Build 5.1.011)
- @version 5.1
- @authors L. Rossman, OpenWaterAnalytics members: 
- see <a href="https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/develop/AUTHORS">AUTHORS</a>.
-*/
+//-----------------------------------------------------------------------------
+//   swmm5.h
+//
+//   Project: EPA SWMM5
+//   Version: 5.1
+//   Date:    03/24/14  (Build 5.1.001)
+//            08/01/16  (Build 5.1.011)
+//   Author:  L. Rossman
+//
+//   Prototypes for SWMM5 functions exported to swmm5.dll.
+//
+//-----------------------------------------------------------------------------
 
 #ifndef SWMM5_H
 #define SWMM5_H
@@ -51,10 +52,10 @@ int swmm_IsStartedFlag(void);
 
 
 // --- use "C" linkage for C++ programs
-#ifdef __cplusplus
-extern "C" {
-#endif
 
+#ifdef __cplusplus
+extern "C" { 
+#endif 
 
 /**
  @brief Opens SWMM input file, reads in network data, runs, and closes
@@ -116,8 +117,8 @@ int DLLEXPORT swmm_getMassBalErr(float* runoffErr, float* flowErr, float* qualEr
 int DLLEXPORT swmm_close(void);
 
 /**
- @brief Get Legacy SWMM version number
- @return Version
+ @brief Get SWMM version number
+ @return Version as integer
 */
 int DLLEXPORT swmm_getVersion(void);
 
@@ -126,9 +127,8 @@ int DLLEXPORT swmm_getError(char* errMsg, int msgLen);
 
 int DLLEXPORT swmm_getWarnings(void);
 
-
-#ifdef __cplusplus
-}   // matches the linkage specification from above */
+#ifdef __cplusplus 
+}   // matches the linkage specification from above */ 
 #endif
 
 #endif
diff --git a/src/solver/include/toolkit.h b/src/solver/include/toolkit.h
index 6861f64b0..7a0bdf250 100644
--- a/src/solver/include/toolkit.h
+++ b/src/solver/include/toolkit.h
@@ -1,51 +1,46 @@
-/** @file toolkit.h
- @see http://github.com/openwateranalytics/stormwater-management-model
-
- toolkit.h
- @brief Exportable Functions for Toolkit API.
- @date 08/30/2016 (First Contribution)
- @authors B. McDonnell (EmNet LLC), OpenWaterAnalytics members: see <a href="https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/develop/AUTHORS">AUTHORS</a>.
+/*
+ *  toolkit.h - OWA SWMM Toolkit API
+ *
+ *  Created on: Aug 30, 2016
+ *  Updated on:
+ *
+ *  Author:      See CONTRIBUTORS
+ * 
+ *  Note: 
+ *     Originally developed by Bryant McDonnell 
+ */
 
+#ifndef TOOLKIT_H
+#define TOOLKIT_H
 
-*/
-#ifndef TOOLKITAPI_H
-#define TOOLKITAPI_H
 
-#ifdef WINDOWS
-#ifdef __MINGW32__
-#define DLLEXPORT __declspec(dllexport) __cdecl
-#else
-#define DLLEXPORT __declspec(dllexport) __stdcall
-#endif
-#else
-#define DLLEXPORT
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
 
 #define _CRT_SECURE_NO_DEPRECATE
 
-
 #include "toolkit_enums.h"
 #include "toolkit_structs.h"
+#include "toolkit_export.h"
 
 
-// /**
-//  @brief Get full semantic version number
-//  @param[out] semver sematic version (char array)
-// */
-// void DLLEXPORT   swmm_getSemVersion(char* semver);
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 
 /**
- @brief Get full semantic version number info
- @param[out] major sematic version major number
- @param[out] minor sematic version minor number
- @param[out] patch sematic version patch number
- @return error code
+ @brief Get full semantic version number
+ @param[out] Pointer to version number string
+ @returns error code
 */
-int  DLLEXPORT   swmm_getVersionInfo(char **major, char **minor, char **patch);
+EXPORT_TOOLKIT const char *swmm_getSemVersion();
+
+/**
+ @brief Get Build Id
+ @param[out] Pointer to build id string
+ @returns error code
+*/
+EXPORT_TOOLKIT const char *swmm_getBuildId();
+
 
 /**
  @brief Opens SWMM input file, reads in network data, runs, and closes
@@ -55,7 +50,7 @@ int  DLLEXPORT   swmm_getVersionInfo(char **major, char **minor, char **patch);
  @param pointer to callback function (for printing progress)
  @return error code
 */
-int  DLLEXPORT   swmm_run_cb(const char *f1, const char *f2, const char *f3,
+EXPORT_TOOLKIT int swmm_run_cb(const char *f1, const char *f2, const char *f3,
     void (*callback) (double *));
 
 /**
@@ -64,7 +59,7 @@ int  DLLEXPORT   swmm_run_cb(const char *f1, const char *f2, const char *f3,
  @param[out] errorMsg The error string represented by the code
  @return Error code
 */
-int DLLEXPORT swmm_getAPIError(int errorCode, char **errorMsg);
+EXPORT_TOOLKIT int swmm_getAPIError(int errorCode, char **errorMsg);
 
 /**
  @brief Finds the index of an object given its ID.
@@ -73,7 +68,7 @@ int DLLEXPORT swmm_getAPIError(int errorCode, char **errorMsg);
  @param[out] index The objects index
  @return Error code
 */
-int DLLEXPORT swmm_project_findObject(SM_ObjectType type, char *id, int *index);
+EXPORT_TOOLKIT int swmm_project_findObject(SM_ObjectType type, char *id, int *index);
 
 /**
 @brief Gets Simulation Unit
@@ -81,7 +76,7 @@ int DLLEXPORT swmm_project_findObject(SM_ObjectType type, char *id, int *index);
 @param[out] value Option value
 @return Error code
 */
-int DLLEXPORT swmm_getSimulationUnit(SM_Units type, int *value);
+EXPORT_TOOLKIT int swmm_getSimulationUnit(SM_Units type, int *value);
 
 /**
  @brief Gets Simulation Analysis Setting
@@ -89,7 +84,7 @@ int DLLEXPORT swmm_getSimulationUnit(SM_Units type, int *value);
  @param[out] value Option value
  @return Error code
  */
-int DLLEXPORT swmm_getSimulationAnalysisSetting(SM_SimOption type, int *value);
+EXPORT_TOOLKIT int swmm_getSimulationAnalysisSetting(SM_SimOption type, int *value);
 
 /**
  @brief Gets Simulation Analysis Setting
@@ -97,7 +92,7 @@ int DLLEXPORT swmm_getSimulationAnalysisSetting(SM_SimOption type, int *value);
  @param[out] value Option value
  @return Error code
  */
-int DLLEXPORT swmm_getSimulationParam(SM_SimSetting type, double *value);
+EXPORT_TOOLKIT int swmm_getSimulationParam(SM_SimSetting type, double *value);
 
 /**
  @brief Gets Object Count
@@ -105,7 +100,7 @@ int DLLEXPORT swmm_getSimulationParam(SM_SimSetting type, double *value);
  @param[out] count Option value
  @return Error code
  */
-int DLLEXPORT swmm_countObjects(SM_ObjectType type, int *count);
+EXPORT_TOOLKIT int swmm_countObjects(SM_ObjectType type, int *count);
 
 /**
  @brief Gets Object ID
@@ -114,7 +109,7 @@ int DLLEXPORT swmm_countObjects(SM_ObjectType type, int *count);
  @param[out] id The string ID of object.
  @return Error code
  */
-int DLLEXPORT swmm_getObjectId(SM_ObjectType type, int index, char **id);
+EXPORT_TOOLKIT int swmm_getObjectId(SM_ObjectType type, int index, char **id);
 
 /**
  @brief Gets Object Index
@@ -123,7 +118,7 @@ int DLLEXPORT swmm_getObjectId(SM_ObjectType type, int index, char **id);
  @param[out] index of the Object
  @return errcode Error Code
  */
-int DLLEXPORT swmm_getObjectIndex(SM_ObjectType type, char *id, int *index);
+EXPORT_TOOLKIT int swmm_getObjectIndex(SM_ObjectType type, char *id, int *index);
 
 /**
  @brief Get the type of node with specified index.
@@ -132,7 +127,7 @@ int DLLEXPORT swmm_getObjectIndex(SM_ObjectType type, char *id, int *index);
  id must be pre-allocated by the caller.
  @return Error code
 */
-int DLLEXPORT swmm_getNodeType(int index, SM_NodeType *Ntype);
+EXPORT_TOOLKIT int swmm_getNodeType(int index, SM_NodeType *Ntype);
 
 /**
  @brief Get the type of link with specified index.
@@ -140,7 +135,7 @@ int DLLEXPORT swmm_getNodeType(int index, SM_NodeType *Ntype);
  @param[out] Ltype The type code for the link (@ref SM_LinkType).
  @return Error code
 */
-int DLLEXPORT swmm_getLinkType(int index, SM_LinkType *Ltype);
+EXPORT_TOOLKIT int swmm_getLinkType(int index, SM_LinkType *Ltype);
 
 /**
  @brief Get the link Connection Node Indeces. If the conduit has a
@@ -151,7 +146,7 @@ int DLLEXPORT swmm_getLinkType(int index, SM_LinkType *Ltype);
  @param[out] Node2 The downstream node index.
  @return Error code
 */
-int DLLEXPORT swmm_getLinkConnections(int index, int *node1, int *node2);
+EXPORT_TOOLKIT int swmm_getLinkConnections(int index, int *node1, int *node2);
 
 /**
  @brief Get the link flow direction (see @ref swmm_getLinkType() for notes.
@@ -159,7 +154,7 @@ int DLLEXPORT swmm_getLinkConnections(int index, int *node1, int *node2);
  @param[out] value The link flow direction.
  @return Error code
 */
-int DLLEXPORT swmm_getLinkDirection(int index, signed char *value);
+EXPORT_TOOLKIT int swmm_getLinkDirection(int index, signed char *value);
 
 /**
  @brief Get the Subcatchment connection. Subcatchments can load to a
@@ -169,7 +164,7 @@ int DLLEXPORT swmm_getLinkDirection(int index, signed char *value);
  @param[out] out_index The object index
  @return Error code
 */
-int DLLEXPORT swmm_getSubcatchOutConnection(int index, SM_ObjectType *type, int *out_index);
+EXPORT_TOOLKIT int swmm_getSubcatchOutConnection(int index, SM_ObjectType *type, int *out_index);
 
 /**
  @brief Get the number of lid units on a subcatchment.
@@ -177,7 +172,7 @@ int DLLEXPORT swmm_getSubcatchOutConnection(int index, SM_ObjectType *type, int
  @param[out] value The number of lid units on a subcatchment
  @return Error code
 */
-int DLLEXPORT swmm_getLidUCount(int index, int *value);
+EXPORT_TOOLKIT int swmm_getLidUCount(int index, int *value);
 
 /**
  @brief Get a property value for a specified lid unit on a specified subcatchment
@@ -187,7 +182,7 @@ int DLLEXPORT swmm_getLidUCount(int index, int *value);
  @param[out] value The value of the lid unit's property
  @return Error code
 */
-int DLLEXPORT swmm_getLidUParam(int index, int lidIndex, SM_LidUProperty param, double *value);
+EXPORT_TOOLKIT int swmm_getLidUParam(int index, int lidIndex, SM_LidUProperty param, double *value);
 
 /**
  @brief Set a property value for a specified lid unit on a specified subcatchment
@@ -197,7 +192,7 @@ int DLLEXPORT swmm_getLidUParam(int index, int lidIndex, SM_LidUProperty param,
  @param value The new value of the lid unit's property
  @return Error code
 */
-int DLLEXPORT swmm_setLidUParam(int index, int lidIndex, SM_LidUProperty param, double value);
+EXPORT_TOOLKIT int swmm_setLidUParam(int index, int lidIndex, SM_LidUProperty param, double value);
 
 /**
  @brief Get the lid option for a specified lid unit on a specified subcatchment
@@ -207,7 +202,7 @@ int DLLEXPORT swmm_setLidUParam(int index, int lidIndex, SM_LidUProperty param,
  @param[out] value The value of the option for the lid unit
  @return Error code
 */
-int DLLEXPORT swmm_getLidUOption(int index, int lidIndex, SM_LidUOptions param, int *value);
+EXPORT_TOOLKIT int swmm_getLidUOption(int index, int lidIndex, SM_LidUOptions param, int *value);
 
 /**
  @brief Set the lid option for a specified lid unit on a specified subcatchment
@@ -217,7 +212,7 @@ int DLLEXPORT swmm_getLidUOption(int index, int lidIndex, SM_LidUOptions param,
  @param value The new value of the option for the lid unit
  @return Error code
 */
-int DLLEXPORT swmm_setLidUOption(int index, int lidIndex, SM_LidUOptions param, int value);
+EXPORT_TOOLKIT int swmm_setLidUOption(int index, int lidIndex, SM_LidUOptions param, int value);
 
 /**
  @brief Get the lid control surface immediate overflow condition
@@ -225,7 +220,7 @@ int DLLEXPORT swmm_setLidUOption(int index, int lidIndex, SM_LidUOptions param,
  @param[out] condition The value of surface immediate overflow condition
  @return Error code
 */
-int DLLEXPORT swmm_getLidCOverflow(int lidControlIndex, int *condition);
+EXPORT_TOOLKIT int swmm_getLidCOverflow(int lidControlIndex, int *condition);
 
 /**
  @brief Get a property value for specified lid control
@@ -235,7 +230,7 @@ int DLLEXPORT swmm_getLidCOverflow(int lidControlIndex, int *condition);
  @param[out] value The value of lid control's property
  @return Error code
 */
-int DLLEXPORT swmm_getLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_LidLayerProperty param, double *value);
+EXPORT_TOOLKIT int swmm_getLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_LidLayerProperty param, double *value);
 
 /**
  @brief Set a property value for specified lid control
@@ -245,7 +240,7 @@ int DLLEXPORT swmm_getLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_
  @param value The new value for the lid control's property
  @return Error code
 */
-int DLLEXPORT swmm_setLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_LidLayerProperty param, double value);
+EXPORT_TOOLKIT int swmm_setLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_LidLayerProperty param, double value);
 
 /**
  @brief Get the lid unit water balance simulated value at current time
@@ -256,7 +251,7 @@ int DLLEXPORT swmm_setLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_
  @param[out] result The result for the specified lid unit
  @return Error code
 */
-int DLLEXPORT swmm_getLidUFluxRates(int index, int lidIndex, SM_LidLayer layerIndex, double *result);
+EXPORT_TOOLKIT int swmm_getLidUFluxRates(int index, int lidIndex, SM_LidLayer layerIndex, double *result);
 
 /**
  @brief Get the lid group of a specified subcatchment result at current time
@@ -265,7 +260,7 @@ int DLLEXPORT swmm_getLidUFluxRates(int index, int lidIndex, SM_LidLayer layerIn
  @param[out] result The result for the specified lid group
  @return Error code
 */
-int DLLEXPORT swmm_getLidGResult(int index, SM_LidResult type, double *result);
+EXPORT_TOOLKIT int swmm_getLidGResult(int index, SM_LidResult type, double *result);
 
 /**
  @brief Get the lid unit of a specified subcatchment result at current time
@@ -275,7 +270,7 @@ int DLLEXPORT swmm_getLidGResult(int index, SM_LidResult type, double *result);
  @param[out] result The result for the specified lid unit
  @return Error code
 */
-int DLLEXPORT swmm_getLidUResult(int index, int lidIndex, SM_LidResult type, double *result);
+EXPORT_TOOLKIT int swmm_getLidUResult(int index, int lidIndex, SM_LidResult type, double *result);
 
 /**
  @brief Get a property value for specified node.
@@ -284,7 +279,7 @@ int DLLEXPORT swmm_getLidUResult(int index, int lidIndex, SM_LidResult type, dou
  @param[out] value The value of the node's property
  @return Error code
 */
-int DLLEXPORT swmm_getNodeParam(int index, SM_NodeProperty param, double *value);
+EXPORT_TOOLKIT int swmm_getNodeParam(int index, SM_NodeProperty param, double *value);
 
 /**
  @brief Set a property value for specified node.
@@ -293,7 +288,7 @@ int DLLEXPORT swmm_getNodeParam(int index, SM_NodeProperty param, double *value)
  @param value The new value of the node's property
  @return Error code
 */
-int DLLEXPORT swmm_setNodeParam(int index, SM_NodeProperty param, double value);
+EXPORT_TOOLKIT int swmm_setNodeParam(int index, SM_NodeProperty param, double value);
 
 /**
  @brief Get a property value for specified link.
@@ -302,7 +297,7 @@ int DLLEXPORT swmm_setNodeParam(int index, SM_NodeProperty param, double value);
  @param[out] value The value of the link's property
  @return Error code
 */
-int DLLEXPORT swmm_getLinkParam(int index, SM_LinkProperty param, double *value);
+EXPORT_TOOLKIT int swmm_getLinkParam(int index, SM_LinkProperty param, double *value);
 
 /**
  @brief Set a property value for specified link.
@@ -311,7 +306,7 @@ int DLLEXPORT swmm_getLinkParam(int index, SM_LinkProperty param, double *value)
  @param value The new value of the link's property
  @return Error code
 */
-int DLLEXPORT swmm_setLinkParam(int index, SM_LinkProperty param, double value);
+EXPORT_TOOLKIT int swmm_setLinkParam(int index, SM_LinkProperty param, double value);
 
 /**
  @brief Get a property value for specified subcatchment.
@@ -320,7 +315,7 @@ int DLLEXPORT swmm_setLinkParam(int index, SM_LinkProperty param, double value);
  @param[out] value The value of the subcatchment's property
  @return Error code
 */
-int DLLEXPORT swmm_getSubcatchParam(int index, SM_SubcProperty param, double *value);
+EXPORT_TOOLKIT int swmm_getSubcatchParam(int index, SM_SubcProperty param, double *value);
 
 /**
  @brief Set a property value for specified subcatchment.
@@ -329,7 +324,7 @@ int DLLEXPORT swmm_getSubcatchParam(int index, SM_SubcProperty param, double *va
  @param value The new value of the subcatchment's property
  @return Error code
 */
-int DLLEXPORT swmm_setSubcatchParam(int index, SM_SubcProperty param, double value);
+EXPORT_TOOLKIT int swmm_setSubcatchParam(int index, SM_SubcProperty param, double value);
 
 /**
  @brief Get the current simulation datetime information.
@@ -342,7 +337,7 @@ int DLLEXPORT swmm_setSubcatchParam(int index, SM_SubcProperty param, double val
  @param[out] second The seconds
  @return Error code
 */
-int DLLEXPORT swmm_getSimulationDateTime(SM_TimePropety type, int *year, int *month,
+EXPORT_TOOLKIT int swmm_getSimulationDateTime(SM_TimePropety type, int *year, int *month,
                                          int *day, int *hour, int *minute,
                                          int *second);
 
@@ -357,7 +352,7 @@ int DLLEXPORT swmm_getSimulationDateTime(SM_TimePropety type, int *year, int *mo
  @param second The second
  @return Error code
 */
-int DLLEXPORT swmm_setSimulationDateTime(SM_TimePropety type, int year, int month,
+EXPORT_TOOLKIT int swmm_setSimulationDateTime(SM_TimePropety type, int year, int month,
                                          int day, int hour, int minute,
                                          int second);
 
@@ -371,7 +366,7 @@ int DLLEXPORT swmm_setSimulationDateTime(SM_TimePropety type, int year, int mont
  @param[out] second The seconds
  @return Error code
 */
-int DLLEXPORT swmm_getCurrentDateTime(int *year, int *month, int *day,
+EXPORT_TOOLKIT int swmm_getCurrentDateTime(int *year, int *month, int *day,
                                       int *hour, int *minute, int *second);
 
 /**
@@ -381,7 +376,7 @@ int DLLEXPORT swmm_getCurrentDateTime(int *year, int *month, int *day,
  @param[out] result The result of the node's property
  @return Error code
 */
-int DLLEXPORT swmm_getNodeResult(int index, SM_NodeResult type, double *result);
+EXPORT_TOOLKIT int swmm_getNodeResult(int index, SM_NodeResult type, double *result);
 
 /**
  @brief Gets pollutant values for a specified node.
@@ -390,16 +385,37 @@ int DLLEXPORT swmm_getNodeResult(int index, SM_NodeResult type, double *result);
  @param[out] PollutArray result array
  @return Error code
 */
-int DLLEXPORT swmm_getNodePollut(int index, SM_NodePollut type, double **pollutArray, int *length);
+EXPORT_TOOLKIT int swmm_getNodePollut(int index, SM_NodePollut type, double **pollutArray, int *length);
 
 /**
- @brief Get a result value for specified link.
+ @brief Sets pollutant values for a specified node.
+ @param index The index of a node
+ @param pollutant_index Pollutant index to set
+ @param pollutant_value Pollutant value to set 
+ @return Error code
+*/
+EXPORT_TOOLKIT int swmm_setNodePollut(int index, SM_NodePollut type, int pollutant_index, double pollutant_value);
+
+/**
+ @brief Sets pollutant values for a specified node.
+ @param index The index of a node
+ @param type The property type code (See @ref SM_NodePollut)
+ @param pollutant_index Pollutant index to set
+ @param pollutant_value Pollutant value to set 
+ @return Error code
+*/
+
+EXPORT_TOOLKIT int swmm_setLinkPollut(int index, SM_LinkPollut type, int pollutant_index, double pollutant_value);
+
+/**
+ @brief Sets pollutant values for a specified link.
  @param index The index of a link
- @param type The property type code (See @ref SM_LinkResult)
- @param[out] result The result of the link's property
+ @param type The property type code (See @ref SM_LinkPollut)
+ @param pollutant_index Pollutant index to set
+ @param pollutant_value Pollutant value to set 
  @return Error code
 */
-int DLLEXPORT swmm_getLinkResult(int index, SM_LinkResult type, double *result);
+EXPORT_TOOLKIT int swmm_getLinkResult(int index, SM_LinkResult type, double *result);
 
 /**
  @brief Gets pollutant values for a specified link.
@@ -408,7 +424,7 @@ int DLLEXPORT swmm_getLinkResult(int index, SM_LinkResult type, double *result);
  @param[out] PollutArray result array
  @return Error code
 */
-int DLLEXPORT swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutArray, int *length);
+EXPORT_TOOLKIT int swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutArray, int *length);
 
 /**
  @brief Get a result value for specified subcatchment.
@@ -417,7 +433,7 @@ int DLLEXPORT swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutA
  @param[out] result The result of the subcatchment's property
  @return Error code
 */
-int DLLEXPORT swmm_getSubcatchResult(int index, SM_SubcResult type, double *result);
+EXPORT_TOOLKIT int swmm_getSubcatchResult(int index, SM_SubcResult type, double *result);
 
 /**
  @brief Gets pollutant values for a specified subcatchment.
@@ -426,7 +442,7 @@ int DLLEXPORT swmm_getSubcatchResult(int index, SM_SubcResult type, double *resu
  @param[out] PollutArray result array
  @return Error code
 */
-int DLLEXPORT swmm_getSubcatchPollut(int index, SM_SubcPollut type, double **pollutArray, int *length);
+EXPORT_TOOLKIT int swmm_getSubcatchPollut(int index, SM_SubcPollut type, double **pollutArray, int *length);
 
 /**
 @brief Get precipitation rates for a gage.
@@ -435,7 +451,7 @@ int DLLEXPORT swmm_getSubcatchPollut(int index, SM_SubcPollut type, double **pol
 @param[out] GageArray precipitation rate
 @return Error code
 */
-int DLLEXPORT swmm_getGagePrecip(int index, SM_GagePrecip type, double *result);
+EXPORT_TOOLKIT int swmm_getGagePrecip(int index, SM_GagePrecip type, double *result);
 
 /**
  @brief Get a node statistics.
@@ -444,7 +460,7 @@ int DLLEXPORT swmm_getGagePrecip(int index, SM_GagePrecip type, double *result);
  pre-allocated by the caller.
  @return Error code
 */
-int DLLEXPORT swmm_getNodeStats(int index, SM_NodeStats *nodeStats);
+EXPORT_TOOLKIT int swmm_getNodeStats(int index, SM_NodeStats *nodeStats);
 
 /**
  @brief Get the cumulative inflow for a node.
@@ -452,7 +468,7 @@ int DLLEXPORT swmm_getNodeStats(int index, SM_NodeStats *nodeStats);
  @param[out] value The total inflow.
  @return Error code
 */
-int DLLEXPORT swmm_getNodeTotalInflow(int index, double *value);
+EXPORT_TOOLKIT int swmm_getNodeTotalInflow(int index, double *value);
 
 /**
  @brief Get a storage statistics.
@@ -461,7 +477,7 @@ int DLLEXPORT swmm_getNodeTotalInflow(int index, double *value);
  pre-allocated by the caller.
  @return Error code
 */
-int DLLEXPORT swmm_getStorageStats(int index, SM_StorageStats *storageStats);
+EXPORT_TOOLKIT int swmm_getStorageStats(int index, SM_StorageStats *storageStats);
 
 /**
  @brief Get outfall statistics.
@@ -472,7 +488,7 @@ int DLLEXPORT swmm_getStorageStats(int index, SM_StorageStats *storageStats);
  pollutants array.
  @return Error code
 */
-int DLLEXPORT swmm_getOutfallStats(int index, SM_OutfallStats *outfallStats);
+EXPORT_TOOLKIT int swmm_getOutfallStats(int index, SM_OutfallStats *outfallStats);
 
 // /**
 //  @brief Free outfall statistics structure.
@@ -480,7 +496,7 @@ int DLLEXPORT swmm_getOutfallStats(int index, SM_OutfallStats *outfallStats);
 //  pollutants array.
 //  @return Error code
 // */
-// void DLLEXPORT swmm_freeOutfallStats(SM_OutfallStats *outfallStats);
+// void EXPORT_TOOLKIT_API swmm_freeOutfallStats(SM_OutfallStats *outfallStats);
 
 /**
  @brief Get link statistics.
@@ -489,7 +505,7 @@ int DLLEXPORT swmm_getOutfallStats(int index, SM_OutfallStats *outfallStats);
  pre-allocated by the caller.
  @return Error code
 */
-int DLLEXPORT swmm_getLinkStats(int index, SM_LinkStats *linkStats);
+EXPORT_TOOLKIT int swmm_getLinkStats(int index, SM_LinkStats *linkStats);
 
 /**
  @brief Get pump statistics.
@@ -498,7 +514,7 @@ int DLLEXPORT swmm_getLinkStats(int index, SM_LinkStats *linkStats);
  pre-allocated by the caller.
  @return Error code
 */
-int DLLEXPORT swmm_getPumpStats(int index, SM_PumpStats *pumpStats);
+EXPORT_TOOLKIT int swmm_getPumpStats(int index, SM_PumpStats *pumpStats);
 
 /**
  @brief Get subcatchment statistics.
@@ -509,7 +525,7 @@ int DLLEXPORT swmm_getPumpStats(int index, SM_PumpStats *pumpStats);
  pollutants array.
  @return Error code
 */
-int DLLEXPORT swmm_getSubcatchStats(int index, SM_SubcatchStats *subcatchStats);
+EXPORT_TOOLKIT int swmm_getSubcatchStats(int index, SM_SubcatchStats *subcatchStats);
 
 /**
  @brief Get system routing totals.
@@ -517,7 +533,7 @@ int DLLEXPORT swmm_getSubcatchStats(int index, SM_SubcatchStats *subcatchStats);
  pre-allocated by the caller.
  @return Error code
 */
-int DLLEXPORT swmm_getSystemRoutingTotals(SM_RoutingTotals *routingTotals);
+EXPORT_TOOLKIT int swmm_getSystemRoutingTotals(SM_RoutingTotals *routingTotals);
 
 /**
  @brief Get system runoff totals.
@@ -525,7 +541,7 @@ int DLLEXPORT swmm_getSystemRoutingTotals(SM_RoutingTotals *routingTotals);
  pre-allocated by the caller.
  @return Error code
 */
-int DLLEXPORT swmm_getSystemRunoffTotals(SM_RunoffTotals *runoffTotals);
+EXPORT_TOOLKIT int swmm_getSystemRunoffTotals(SM_RunoffTotals *runoffTotals);
 
 /**
  @brief Set a link setting (pump, orifice, or weir). Setting for an orifice
@@ -535,7 +551,7 @@ int DLLEXPORT swmm_getSystemRunoffTotals(SM_RunoffTotals *runoffTotals);
  @param setting The new setting for the link.
  @return Error code
 */
-int DLLEXPORT swmm_setLinkSetting(int index, double setting);
+EXPORT_TOOLKIT int swmm_setLinkSetting(int index, double setting);
 
 /**
  @brief Set an inflow rate to a node. The inflow rate is held constant
@@ -544,7 +560,7 @@ int DLLEXPORT swmm_setLinkSetting(int index, double setting);
  @param flowrate The new node inflow rate.
  @return Error code
 */
-int DLLEXPORT swmm_setNodeInflow(int index, double flowrate);
+EXPORT_TOOLKIT int swmm_setNodeInflow(int index, double flowrate);
 
 /**
  @brief Set outfall stage.
@@ -552,7 +568,7 @@ int DLLEXPORT swmm_setNodeInflow(int index, double flowrate);
  @param stage The outfall node stage (head).
  @return Error code
 */
-int DLLEXPORT swmm_setOutfallStage(int index, double stage);
+EXPORT_TOOLKIT int swmm_setOutfallStage(int index, double stage);
 
 /**
 @brief Set a total precipitation intensity to the gage.
@@ -560,18 +576,20 @@ int DLLEXPORT swmm_setOutfallStage(int index, double stage);
 @param total_precip The new total precipitation intensity.
 @return Error code
 */
-int DLLEXPORT swmm_setGagePrecip(int index, double total_precip);
+EXPORT_TOOLKIT int swmm_setGagePrecip(int index, double total_precip);
 
 /**
  @brief Helper function to free memory array allocated in SWMM.
  @param array The pointer to the array
  @return Void.
 */
-void DLLEXPORT swmm_freeMemory(void *memory);
+EXPORT_TOOLKIT void swmm_freeMemory(void *memory);
+
 
 #ifdef __cplusplus
 }    // matches the linkage specification from above */
 #endif
 
 
-#endif
+
+#endif // TOOLKIT_H
diff --git a/src/solver/include/toolkit_enums.h b/src/solver/include/toolkit_enums.h
index 25e5ef73f..9b54f7b2d 100644
--- a/src/solver/include/toolkit_enums.h
+++ b/src/solver/include/toolkit_enums.h
@@ -4,9 +4,7 @@
  *  Created on: November 13, 2020
  *  Updated on:
  *
- *  Author:     Michael E. Tryby
- *              US EPA - ORD/CESER
- *
+ *  Author:     See CONTRIBUTORS
  */
 
 
@@ -132,12 +130,15 @@ typedef enum {
     SM_NODEFLOOD      = 4,  /**< Flooding Rate */
     SM_NODEDEPTH      = 5,  /**< Node Depth */
     SM_NODEHEAD       = 6,  /**< Node Head */
-    SM_LATINFLOW      = 7   /**< Lateral Inflow Rate */
+    SM_LATINFLOW      = 7,  /**< Lateral Inflow Rate */
+    SM_HRT	      = 8   /**< HRT */
 } SM_NodeResult;
 
 /// Node pollutant result property codes
 typedef enum {
     SM_NODEQUAL       = 0,  /**< Current Node Quality */
+    SM_NODECIN        = 1,  /**< Inflow Concentration */
+    SM_NODEREACTORC   = 2   /**< Reactor Concentation */
 } SM_NodePollut;
 
 /// Link result property codes
@@ -156,6 +157,7 @@ typedef enum {
 typedef enum {
     SM_LINKQUAL      = 0,  /**< Current Link Quality */
     SM_TOTALLOAD     = 1,  /**< Total Quality Mass Loading */
+    SM_LINKREACTORC  = 2   /**< Reactor Concentration */
 } SM_LinkPollut;
 
 /// Subcatchment result property codes
diff --git a/src/solver/kinwave.c b/src/solver/kinwave.c
index d13662b68..c0fdf6fce 100644
--- a/src/solver/kinwave.c
+++ b/src/solver/kinwave.c
@@ -5,6 +5,7 @@
 //   Version:  5.1
 //   Date:     03/20/14  (Build 5.1.001)
 //             03/19/15  (Build 5.1.008)
+//             03/01/20  (Build 5.1.014)
 //   Author:   L. Rossman (EPA)
 //             M. Tryby (EPA)
 //
@@ -13,6 +14,9 @@
 //   Build 5.1.008:
 //   - Conduit inflow passed to function that computes conduit losses.
 //
+//   Build 5.1.014:
+//   - Arguments to function link_getLossRate changed.
+//
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
@@ -98,7 +102,7 @@ int kinwave_execute(int j, double* qinflow, double* qoutflow, double tStep)
     qin = (*qinflow) / Conduit[k].barrels / Qfull;
 
     // --- compute evaporation and infiltration loss rate
-	q3 = link_getLossRate(j, qin*Qfull, tStep) / Qfull;
+	q3 = link_getLossRate(j, qin*Qfull) / Qfull;                               //(5.1.014)
 
     // --- normalize previous areas
     a1 = Conduit[k].a1 / Afull;
diff --git a/src/solver/lid.c b/src/solver/lid.c
index 9deea8243..e7f6ef82d 100644
--- a/src/solver/lid.c
+++ b/src/solver/lid.c
@@ -12,6 +12,7 @@
 //             08/01/16   (Build 5.1.011)
 //             03/14/17   (Build 5.1.012)
 //             05/10/18   (Build 5.1.013)
+//             03/01/20   (Build 5.1.014)
 //   Author:   L. Rossman (US EPA)
 //
 //   This module handles all data processing involving LID (Low Impact
@@ -72,6 +73,10 @@
 //     control curve for underdrain flow.
 //   - Support added for unclogging permeable pavement at fixed intervals.
 //   - Support added for pollutant removal in underdrain flow.
+//
+//   Build 5.1.014:
+//   - Fixed bug in creating LidProcs when there are no subcatchments.
+//   - Fixed bug in adding underdrain pollutant loads to mass balances.
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
@@ -246,10 +251,10 @@ void lid_create(int lidCount, int subcatchCount)
             return;
         }
     }
-
+        
     //... initialize LID groups
     for (j = 0; j < GroupCount; j++) LidGroups[j] = NULL;
-
+    
     //... create LID objects
     if ( LidCount == 0 ) return;
     LidProcs = (TLidProc *) calloc(LidCount, sizeof(TLidProc));
@@ -1481,7 +1486,7 @@ void  lid_addDrainLoads(int j, double c[], double tStep)
                 //... update system mass balance totals
                 massbal_updateLoadingTotals(BMP_REMOVAL_LOAD, p, r*w);
                 if (isRunoffLoad)
-                    massbal_updateLoadingTotals(RUNOFF_LOAD, p, w*(1.0-r));
+                    massbal_updateLoadingTotals(RUNOFF_LOAD, p, w*(1.0 - r));
             }
 
             // process next LID unit in the group
diff --git a/src/solver/lidproc.c b/src/solver/lidproc.c
index a7ffba73e..249442509 100644
--- a/src/solver/lidproc.c
+++ b/src/solver/lidproc.c
@@ -12,6 +12,7 @@
 //             08/01/16   (Build 5.1.011)
 //             03/14/17   (Build 5.1.012)
 //             05/10/18   (Build 5.1.013)
+//             03/01/20   (Build 5.1.014)
 //   Author:   L. Rossman (US EPA)
 //
 //   This module computes the hydrologic performance of an LID (Low Impact
@@ -59,6 +60,10 @@
 //     to control underdrain flow.
 //   - Support added for regenerating pavement permeability at fixed intervals.
 //
+//   Build 5.1.014:
+//   - Fixed failure to initialize all LID layer moisture volumes to 0 before
+//     computing LID unit performance in lidproc_getOutflow.
+//
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
@@ -276,7 +281,11 @@ double lidproc_getOutflow(TLidUnit* lidUnit, TLidProc* lidProc, double inflow,
     x[STOR] = theLidUnit->storageDepth;
     x[PAVE] = theLidUnit->paveDepth;
 
-    //... initialize layer flux rates and moisture limits
+    //... 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;
diff --git a/src/solver/link.c b/src/solver/link.c
index c2e618291..3abc2f5f8 100644
--- a/src/solver/link.c
+++ b/src/solver/link.c
@@ -10,6 +10,7 @@
 //             08/01/16   (Build 5.1.011)
 //             03/14/17   (Build 5.1.012)
 //             05/10/18   (Build 5.1.013)
+//             03/01/20   (Build 5.1.014)
 //   Author:   L. Rossman (EPA)
 //             M. Tryby (EPA)
 //
@@ -45,6 +46,10 @@
 //   - Support added for head-dependent weir coefficient curves.
 //   - Adjustment of regulator link crest offset to match downstream node invert
 //     now only done for Dynamic Wave flow routing.
+//
+//  Build 5.1.014:
+//  - Conduit evap. and seepage losses initialized to 0 in conduit_initState()
+//    and not allowed to exceed current flow rate in conduit_getLossRate().
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
@@ -97,7 +102,7 @@ static double conduit_getLength(int j);
 static double conduit_getLengthFactor(int j, int k, double roughness);
 static double conduit_getSlope(int j);
 static double conduit_getInflow(int j);
-static double conduit_getLossRate(int j, double q, double tstep);
+static double conduit_getLossRate(int j, double q);                            //(5.1.014)
 
 static int    pump_readParams(int j, int k, char* tok[], int ntoks);
 static void   pump_validate(int j, int k);
@@ -865,7 +870,7 @@ double link_getPower(int j)
 
 //=============================================================================
 
-double link_getLossRate(int j, double q, double tStep)
+double link_getLossRate(int j, double q)                                       //(5.1.014)
 //
 //  Input:   j = link index
 //           q = flow rate (ft3/sec)
@@ -875,7 +880,7 @@ double link_getLossRate(int j, double q, double tStep)
 //           evaporation and seepage.
 //
 {
-    if ( Link[j].type == CONDUIT ) return conduit_getLossRate(j, q, tStep);
+    if ( Link[j].type == CONDUIT ) return conduit_getLossRate(j, q);           //(5.1.014)
     else return 0.0;
 }
 
@@ -1277,6 +1282,8 @@ void  conduit_initState(int j, int k)
 {
     Link[j].newDepth = link_getYnorm(j, Link[j].q0 / Conduit[k].barrels);
     Link[j].oldDepth = Link[j].newDepth;
+    Conduit[k].evapLossRate = 0.0;                                             //(5.1.014)
+    Conduit[k].seepLossRate = 0.0;                                             //(5.1.014)
 }
 
 //=============================================================================
@@ -1295,12 +1302,12 @@ double conduit_getInflow(int j)
 
 //=============================================================================
 
-////  This function was modified for relese 5.1.013.  ////                     //(5.1.013)
+////  This function was modified for relese 5.1.014.  ////                     //(5.1.014)
 
-double conduit_getLossRate(int j, double q, double tStep)
+double conduit_getLossRate(int j, double q)
 //
 //  Input:   j = link index
-//           tStep = time step (sec)
+//           q = current link flow rate (cfs)
 //  Output:  returns rate of evaporation & seepage losses (ft3/sec)
 //  Purpose: computes volumetric rate of water evaporation & seepage
 //           from a conduit (per barrel).
@@ -1310,7 +1317,6 @@ double conduit_getLossRate(int j, double q, double tStep)
     double depth = 0.5 * (Link[j].oldDepth + Link[j].newDepth);
     double length;
     double topWidth;
-    double maxLossRate;
     double evapLossRate = 0.0,
            seepLossRate = 0.0,
            totalLossRate = 0.0;
@@ -1342,17 +1348,13 @@ double conduit_getLossRate(int j, double q, double tStep)
         // --- compute total loss rate
         totalLossRate = evapLossRate + seepLossRate;
 
-        // --- total loss rate cannot exceed current volume
-        if ( totalLossRate > 0.0 )
+        // --- total loss rate cannot exceed flow rate
+        q = ABS(q);
+        if (totalLossRate > q)
         {
-            maxLossRate = 0.5 * (Link[j].oldVolume + Link[j].newVolume) / tStep;
-            maxLossRate = MIN(maxLossRate, fabs(q));
-            if ( totalLossRate > maxLossRate )
-            {
-                evapLossRate = evapLossRate * maxLossRate / totalLossRate;
-                seepLossRate = seepLossRate * maxLossRate / totalLossRate;
-                totalLossRate = maxLossRate;
-            }
+            evapLossRate = evapLossRate * q / totalLossRate;
+            seepLossRate = seepLossRate * q / totalLossRate;
+            totalLossRate = q;
         }
     }
 
diff --git a/src/solver/node.c b/src/solver/node.c
index b783ff1d3..b74909d8c 100644
--- a/src/solver/node.c
+++ b/src/solver/node.c
@@ -8,6 +8,7 @@
 //             04/02/15   (Build 5.1.008)
 //             08/05/15   (Build 5.1.010)
 //             05/10/18   (Build 5.1.013)
+//             03/01/20   (Build 5.1.014)
 //   Author:   L. Rossman
 //
 //   Conveyance system node functions.
@@ -27,6 +28,9 @@
 //   Build 5.1.013:
 //   - A surcharge depth can now be applied to storage nodes.
 //   - A negative inflow is now assigned to an Outfall node with backflow. 
+//
+//   Build 5.1.014:
+//   - Fixed bug in storage_losses() that affected storage exfiltration.
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
diff --git a/src/solver/objects.h b/src/solver/objects.h
index ef4a23be2..96e09e158 100644
--- a/src/solver/objects.h
+++ b/src/solver/objects.h
@@ -485,6 +485,7 @@ typedef struct
    char*         ID;              // node ID
    int           type;            // node type code
    int           subIndex;        // index of node's sub-category
+   int*          extPollutFlag;   // external pollutant flag
    char          rptFlag;         // reporting flag
    double        invertElev;      // invert elevation (ft)
    double        initDepth;       // initial storage level (ft)
@@ -502,6 +503,7 @@ typedef struct
    double        inflow;          // total inflow (cfs)
    double        outflow;         // total outflow (cfs)
    double        losses;          // evap + exfiltration loss (ft3)
+   double        hrt;		  // hydraulic retention time
    double        oldVolume;       // previous volume (ft3)
    double        newVolume;       // current volume (ft3)
    double        fullVolume;      // max. storage available (ft3)
@@ -512,6 +514,9 @@ typedef struct
    double        newLatFlow;      // current lateral inflow (cfs)
    double*       oldQual;         // previous quality state
    double*       newQual;         // current quality state
+   double*	 extQual;	  // external quality state
+   double*	 inQual;          // inflow quality state
+   double*	 reactorQual;     // concentration in the mixed reactor   
    double        oldFlowInflow;   // previous flow inflow
    double        oldNetInflow;    // previous net inflow
 }  TNode;
@@ -634,6 +639,7 @@ typedef struct
    char*         ID;              // link ID
    int           type;            // link type code
    int           subIndex;        // index of link's sub-category
+   int*          extPollutFlag;   // external pollutant flag
    char          rptFlag;         // reporting flag
    int           node1;           // start node index
    int           node2;           // end node index
@@ -664,6 +670,8 @@ typedef struct
    double*       oldQual;         // previous quality state
    double*       newQual;         // current quality state
    double*       totalLoad;       // total quality mass loading
+   double*       extQual;	  // external quality state 	
+   double*	 reactorQual;     // concentration in the mixed reactor   
    int           flowClass;       // flow classification
    double        dqdh;            // change in flow w.r.t. head (ft2/sec)
    signed char   direction;       // flow direction flag
diff --git a/src/solver/output.c b/src/solver/output.c
index 186a3979d..7eca52e7c 100644
--- a/src/solver/output.c
+++ b/src/solver/output.c
@@ -7,6 +7,7 @@
 //             03/19/15  (Build 5.1.008)
 //             08/05/15  (Build 5.1.010)
 //             05/10/18  (Build 5.1.013)
+//             03/01/20  (Build 5.1.014)
 //   Author:   L. Rossman (EPA)
 //
 //   Binary output file access functions.
@@ -24,14 +25,18 @@
 //   - Support added for saving average node & link routing results to
 //     binary file in each reporting period.
 //
+//   Build 5.1.014:
+//   - Incorrect loop limit fixed in function output_saveAvgResults.
+//
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
-#include "headers.h"
 
+#include "headers.h"
+#include "version.h"
 
 // Definition of 4-byte integer, 4-byte real and 8-byte real types
 #define INT4  int
@@ -178,7 +183,7 @@ int output_open()
     fseek(Fout.file, 0, SEEK_SET);
     k = MAGICNUMBER;
     fwrite(&k, sizeof(INT4), 1, Fout.file);   // Magic number
-    k = VERSION;
+    k = get_version_legacy();
     fwrite(&k, sizeof(INT4), 1, Fout.file);   // Version number
     k = FlowUnits;
     fwrite(&k, sizeof(INT4), 1, Fout.file);   // Flow units
@@ -936,7 +941,7 @@ void output_saveAvgResults(FILE* file)
     }
  
     // --- add each link's volume to total system storage
-    for (i = 0; i < Nobjects[NODE]; i++)
+    for (i = 0; i < Nobjects[LINK]; i++)                                       //(5.1.014)
     {
         SysResults[SYS_STORAGE] += (REAL4)(Link[i].newVolume * UCF(VOLUME));
     }
diff --git a/src/solver/project.c b/src/solver/project.c
index 5e9b8e751..70b5a8c56 100644
--- a/src/solver/project.c
+++ b/src/solver/project.c
@@ -1037,6 +1037,10 @@ void createObjects()
     {
         Node[j].oldQual = (double *) calloc(Nobjects[POLLUT], sizeof(double));
         Node[j].newQual = (double *) calloc(Nobjects[POLLUT], sizeof(double));
+	Node[j].extQual = (double *) calloc(Nobjects[POLLUT], sizeof(double));
+	Node[j].inQual = (double *) calloc(Nobjects[POLLUT], sizeof(double));
+	Node[j].reactorQual = (double *) calloc(Nobjects[POLLUT], sizeof(double));
+	Node[j].extPollutFlag = (int *) calloc(Nobjects[POLLUT], sizeof(int));
         Node[j].extInflow = NULL;
         Node[j].dwfInflow = NULL;
         Node[j].rdiiInflow = NULL;
@@ -1046,7 +1050,10 @@ void createObjects()
     {
         Link[j].oldQual = (double *) calloc(Nobjects[POLLUT], sizeof(double));
         Link[j].newQual = (double *) calloc(Nobjects[POLLUT], sizeof(double));
+	Link[j].extQual = (double *) calloc(Nobjects[POLLUT], sizeof(double));
         Link[j].totalLoad = (double *) calloc(Nobjects[POLLUT], sizeof(double));
+	Link[j].reactorQual = (double *) calloc(Nobjects[POLLUT], sizeof(double));
+	Link[j].extPollutFlag = (int *) calloc(Nobjects[POLLUT], sizeof(int));
     }
 
     // --- allocate memory for land use buildup/washoff functions
diff --git a/src/solver/qualrout.c b/src/solver/qualrout.c
index 7c16e45af..fd94ccd60 100644
--- a/src/solver/qualrout.c
+++ b/src/solver/qualrout.c
@@ -101,25 +101,27 @@ void qualrout_execute(double tStep)
 //
 {
     int    i, j;
+    int    p;
     double qIn, vAvg;
-
+ 
     // --- find mass flow each link contributes to its downstream node
     for ( i = 0; i < Nobjects[LINK]; i++ ) findLinkMassFlow(i, tStep);
 
     // --- find new water quality concentration at each node  
     for (j = 0; j < Nobjects[NODE]; j++)
     {
+
         // --- get node inflow and average volume
         qIn = Node[j].inflow;
         vAvg = (Node[j].oldVolume + Node[j].newVolume) / 2.0;
         
         // --- save inflow concentrations if treatment applied
-        if ( Node[j].treatment )
+        if ( Node[j].treatment || ExtPollutFlag == 1)
         {
             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 > FUDGE )
         {
@@ -128,11 +130,15 @@ void qualrout_execute(double tStep)
         else findNodeQual(j);
 
         // --- apply treatment to new quality values
-        if ( Node[j].treatment ) treatmnt_treat(j, qIn, vAvg, tStep);
+        if ( Node[j].treatment || ExtPollutFlag == 1) treatmnt_treat(j, qIn, vAvg, tStep);
     }
 
     // --- find new water quality in each link
     for ( i = 0; i < Nobjects[LINK]; i++ ) findLinkQual(i, tStep);
+
+    // --- default to swmm treatment
+    if (ExtPollutFlag == 1){ExtPollutFlag = 0;}
+
 }
 
 //=============================================================================
@@ -254,7 +260,8 @@ void findLinkQual(int i, double tStep)
            vEvap,            // volume lost to evaporation (ft3)
            vLosses,          // evap. + seepage volume loss (ft3)
            fEvap,            // evaporation concentration factor
-           barrels;          // number of barrels in conduit
+           barrels,          // number of barrels in conduit
+    	   lossExtQual;      // loss value for external quality 
 
     // --- identify index of upstream node
     j = Link[i].node1;
@@ -310,7 +317,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
@@ -329,9 +336,25 @@ void findLinkQual(int i, double tStep)
             massbal_addToFinalStorage(p, c2 * v2);
             c2 = 0.0;
         }
-
-        // --- assign new concen. to link
-        Link[i].newQual[p] = c2;
+	
+	// --- set reactor qual for external pollutant handling
+	Link[i].reactorQual[p] = c2;
+
+	if (Link[i].extPollutFlag[p] == 0)
+	{
+            // --- assign new concen. to link
+            Link[i].newQual[p] = c2;
+	}
+	// --- update mass balance and set external pollutant
+	else if( Link[i].extPollutFlag[p] == 1)
+	{
+	    // --- mass balance update
+            lossExtQual = c2 - Link[i].extQual[p];
+            lossExtQual = lossExtQual * v1/ tStep;
+            massbal_addReactedMass(p, lossExtQual);
+            Link[i].newQual[p] = Link[i].extQual[p];
+            Link[i].extPollutFlag[p] = 0;
+	}
     }
 }
 
@@ -452,6 +475,7 @@ void  findStorageQual(int j, double tStep)
 
         // --- assign new concen. to node
         Node[j].newQual[p] = c2;
+	Node[j].reactorQual[p] = c2;
     }
 }
 
@@ -498,4 +522,4 @@ double getReactedQual(int p, double c, double v1, double tStep)
     massbal_addReactedMass(p, lossRate);
     return c2;
 }
- 
\ No newline at end of file
+ 
diff --git a/src/solver/rain.c b/src/solver/rain.c
index 734bccce3..873031e74 100644
--- a/src/solver/rain.c
+++ b/src/solver/rain.c
@@ -7,6 +7,7 @@
 //            08/05/15  (Build 5.1.010)
 //            08/22/16  (Build 5.1.011)
 //            05/10/18  (Build 5.1.013)
+//            03/01/20  (Build 5.1.014)
 //   Author:  L. Rossman
 //
 //   Places rainfall data from external files into a SWMM rainfall
@@ -48,6 +49,9 @@
 //
 //   Release 5.1.013:
 //   - Variable x properly initialized with float value in readNwsOnlineValue().
+//
+//   Release 5.1.014:
+//   - Fixed indexing bug in rainFileConflict() function.
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
diff --git a/src/solver/rdii.c b/src/solver/rdii.c
index d9d7412f1..d94962489 100644
--- a/src/solver/rdii.c
+++ b/src/solver/rdii.c
@@ -7,6 +7,7 @@
 //             04/04/14   (Build 5.1.003)
 //             04/14/14   (Build 5.1.004)
 //             09/15/14   (Build 5.1.007)
+//             03/01/20   (Build 5.1.014)
 //   Author:   L. Rossman (EPA)
 //             R. Dickinson (CDM)
 //
@@ -19,6 +20,8 @@
 //   - Ignore RDII option implemented.
 //   - Rainfall climate adjustment implemented.
 //
+//   Build 5.1.014:
+//   - Fixes bug related to isUsed property of a unit hydrograph's rain gage.
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
diff --git a/src/solver/report.c b/src/solver/report.c
index 03437c4d5..07598b98a 100644
--- a/src/solver/report.c
+++ b/src/solver/report.c
@@ -10,6 +10,7 @@
 //             08/01/16    (Build 5.1.011)
 //             03/14/17    (Build 5.1.012)
 //             05/10/18    (Build 5.1.013)
+//             03/01/20    (Build 5.1.014)
 //   Author:   L. Rossman (EPA)
 //
 //   Report writing functions.
@@ -40,6 +41,8 @@
 //   - Name of surcharge method reported in report_writeOptions().
 //   - Missing format specifier added to fprintf() in report_writeErrorCode.
 //
+//   Build 5.1.014:
+//   - Fixed bug in confusing keywords with ID names in report_readOptions().
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
@@ -47,7 +50,10 @@
 #include <string.h>
 #include <math.h>
 #include <time.h>
+
 #include "headers.h"
+#include "version.h"
+
 
 #define WRITE(x) (report_writeLine((x)))
 #define LINE_10 "----------"
@@ -237,11 +243,9 @@ void report_writeLogo()
 //  Purpose: writes report header lines to report file.
 //
 {
-	char SEMVERSION[SEMVERSION_LEN];
-	getSemVersion(SEMVERSION);
-
 	sprintf(Msg, \
-		"\n  EPA STORM WATER MANAGEMENT MODEL - VERSION 5.1 (Build %s)", SEMVERSION);
+		"\n  OWA STORM WATER MANAGEMENT MODEL - VERSION v%s (OWA %.10s)", 
+        VERSION, BUILD_ID);
 
     fprintf(Frpt.file, "%s", Msg);
     fprintf(Frpt.file, FMT09);
@@ -815,7 +819,7 @@ void report_writeFlowError(TRoutingTotals *totals)
 
 //=============================================================================
 
-void report_writeQualError(TRoutingTotals QualTotals[])
+void report_writeQualError(TRoutingTotals* QualTotals)
 //
 //  Input:   totals = accumulated quality routing totals for each pollutant
 //  Output:  none
diff --git a/src/solver/roadway.c b/src/solver/roadway.c
index 4530f4fa3..0237ea96d 100644
--- a/src/solver/roadway.c
+++ b/src/solver/roadway.c
@@ -24,7 +24,10 @@
 #include <math.h>
 #include "headers.h"
 
-enum RoadSurface {PAVED = 1, GRAVEL = 2};
+enum RoadSurface {
+    PAVED = 1,
+    GRAVEL = 2
+};
 
 //-----------------------------------------------------------------------------
 //  Constants
@@ -39,7 +42,7 @@ enum RoadSurface {PAVED = 1, GRAVEL = 2};
 static const int N_Cr_Low_Paved = 4;
 static const double Cr_Low_Paved[4][2] = {
     {0.0, 2.85}, {0.2, 2.95}, {0.7, 3.03}, {4.0, 3.05}};
-    
+
 static const int N_Cr_Low_Gravel = 8;
 static const double Cr_Low_Gravel[8][2] = {
     {0.0, 2.5}, {0.5, 2.7},  {1.0, 2.8}, {1.5, 2.9}, {2.0, 2.98},
@@ -187,4 +190,3 @@ double getY(double x, const double table[][2], const int n)
     }
     return table[n-1][1];
 }
-
diff --git a/src/solver/runoff.c b/src/solver/runoff.c
index 3571a0b7d..a7a6f5d83 100644
--- a/src/solver/runoff.c
+++ b/src/solver/runoff.c
@@ -8,6 +8,7 @@
 //             03/19/15   (Build 5.1.008)
 //             08/01/16   (Build 5.1.011)
 //             03/14/17   (Build 5.1.012)
+//             03/01/20   (Build 5.1.014)
 //   Author:   L. Rossman
 //             M. Tryby
 //
@@ -29,6 +30,9 @@
 //
 //   Build 5.1.012:
 //   - Runoff wet time step no longer kept aligned with reporting times.
+//
+//   Build 5.1.014:
+//   - Fixed street sweeping bug.
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
diff --git a/src/solver/surfqual.c b/src/solver/surfqual.c
index 9dc6965cc..6f0dfc4f4 100644
--- a/src/solver/surfqual.c
+++ b/src/solver/surfqual.c
@@ -4,6 +4,7 @@
 //   Project:  EPA SWMM5
 //   Version:  5.1
 //   Date:     03/19/15  (Build 5.1.008)
+//             03/01/20  (Build 5.1.014)
 //   Author:   L. Rossman
 //
 //   Subcatchment water quality functions.
@@ -13,6 +14,8 @@
 //     subcatch.c.
 //   - Support for separate accounting of LID drain flows included. 
 //
+//   Build 5.1.014:
+//   - Fixed bug in computing effective BMP removal by LIDs.
 //-----------------------------------------------------------------------------
 #define _CRT_SECURE_NO_DEPRECATE
 
diff --git a/src/solver/swmm5.c b/src/solver/swmm5.c
index 0be2b4364..517436d62 100644
--- a/src/solver/swmm5.c
+++ b/src/solver/swmm5.c
@@ -112,6 +112,7 @@
 #include "text.h"                      // listing of all text strings
 #define  EXTERN                        // defined as 'extern' in headers.h
 #include "globals.h"                   // declaration of all global variables
+#include "version.h"
 
 #include "swmm5.h"                     // declaration of exportable functions
                                        //   callable from other programs
@@ -290,6 +291,9 @@ int DLLEXPORT swmm_start(int saveResults)
         NonConvergeCount = 0;
         IsStartedFlag = TRUE;
 
+	// --- initialize external pollutant control
+	ExtPollutFlag = 0;
+
         // --- initialize global continuity errors
         RunoffError = 0.0;
         GwaterError = 0.0;
@@ -603,18 +607,16 @@ int  DLLEXPORT swmm_getMassBalErr(float* runoffErr, float* flowErr,
 
 //=============================================================================
 
-int  DLLEXPORT swmm_getVersion(void)
+int DLLEXPORT swmm_getVersion(void)
 //
 //  Input:   none
-//  Output:  returns SWMM engine version number
+//  Output:  returns SWMM engine version number in legacy format
 //  Purpose: retrieves version number of current SWMM engine which
 //           uses a format of xyzzz where x = major version number,
 //           y = minor version number, and zzz = build number.
 //
-//  NOTE: Each New Release should be updated in consts.h
-//        THIS FUNCTION WILL EVENTUALLY BE DEPRECATED
 {
-    return VERSION;
+    return get_version_legacy();
 }
 
 //=============================================================================
@@ -891,16 +893,3 @@ int swmm_IsStartedFlag()
     // TRUE if a simulation has been started
     return IsStartedFlag;
 }
-
-
-void getSemVersion(char* semver)
-//
-//  Output: Returns Semantic Version
-//  Purpose: retrieves the current semantic version
-//
-//  NOTE: Each New Release should be updated in consts.h
-{
-    snprintf(semver, SEMVERSION_LEN, "%s.%s.%s",
-        SEMVERSION_MAJOR, SEMVERSION_MINOR, SEMVERSION_PATCH);
-}
-//=============================================================================
diff --git a/src/solver/text.h b/src/solver/text.h
index 6f3100613..f8224a77c 100644
--- a/src/solver/text.h
+++ b/src/solver/text.h
@@ -20,16 +20,18 @@
 //   Text strings
 //-----------------------------------------------------------------------------
 
-#define FMT01 \
- "\tswmm5 <input file> <report file> <output file>\n"
+//#include "consts.h"
+
+//#define FMT01 \
+// "\tswmm5 <input file> <report file> <output file>\n"
 
 #define FMT03 " There are errors.\n"
 #define FMT04 " There are warnings.\n"
 #define FMT05 "\n"
 #define FMT06 "\n o  Retrieving project data"
 #define FMT07 "\n o  Writing output report"
-#define FMT08 \
-  "\n  EPA STORM WATER MANAGEMENT MODEL - VERSION 5.1 (Build 5.1.013)"         //(5.1.013)
+//#define FMT08 \
+//  "\n  EPA STORM WATER MANAGEMENT MODEL - VERSION 5.1 (Build "SEMVERSION_MAJOR"."SEMVERSION_MINOR"."SEMVERSION_PATCH")"         //(5.1.014)
 #define FMT09 \
   "\n  --------------------------------------------------------------"
 #define FMT10 "\n"
@@ -47,7 +49,7 @@
 #define FMT21  "  Total elapsed time: "
 
 // Warning messages
-#define WARN01 "WARNING 01: wet weather time step reduced to recording interval for Rain Gage" 
+#define WARN01 "WARNING 01: wet weather time step reduced to recording interval for Rain Gage"
 #define WARN02 "WARNING 02: maximum depth increased for Node"
 #define WARN03 "WARNING 03: negative offset ignored for Link"
 #define WARN04 "WARNING 04: minimum elevation drop used for Conduit"
@@ -239,7 +241,7 @@
 #define  w_CUSTOM            "CUSTOM"
 #define  w_FORCE_MAIN        "FORCE_MAIN"
 #define  w_H_W               "H-W"
-#define  w_D_W               "D-W" 
+#define  w_D_W               "D-W"
 
 // Link Offset Options
 #define  w_ELEVATION         "ELEVATION"
@@ -256,7 +258,7 @@
 // Flow Volume Units
 #define  w_MGAL              "10^6 gal"
 #define  w_MLTRS             "10^6 ltr"
-#define  w_GAL               "gal" 
+#define  w_GAL               "gal"
 #define  w_LTR               "ltr"
 
 // Ponded Depth Units
diff --git a/src/solver/toolkit.c b/src/solver/toolkit.c
index 4976c7474..50c2f7b79 100644
--- a/src/solver/toolkit.c
+++ b/src/solver/toolkit.c
@@ -1,20 +1,24 @@
-/** @file toolkit.c
- @see http://github.com/openwateranalytics/stormwater-management-model
+/*
+ *  toolkit.c - OWA SWMM Toolkit API
+ *
+ *  Created on: Aug 30, 2016
+ *  Updated on:
+ *
+ *  Author:      See CONTRIBUTORS
+ * 
+ *  Note: 
+ *     Originally developed by Bryant McDonnell  
+ */
 
- toolkit.c
- @brief Exportable Functions for Toolkit API.
- @date 08/30/2016 (First Contribution)
- @authors B. McDonnell (EmNet LLC), OpenWaterAnalytics members: see <a href="https://github.com/OpenWaterAnalytics/Stormwater-Management-Model/blob/develop/AUTHORS">AUTHORS</a>.
-
-
-*/
 #define _CRT_SECURE_NO_DEPRECATE
 
 
 #include <math.h>
 #include <time.h>
+#include <stdio.h>
 
 #include "headers.h"
+#include "version.h"
 #include "shared/cstr_helper.h"
 
 #include "swmm5.h"
@@ -35,38 +39,33 @@ int  stats_getSubcatchStat(int index, TSubcatchStats **subcatchStats);
 
 
 // Utilty Function Declarations
-double* newDoubleArray(int n);
-
+double *newDoubleArray(int n);
 
 
-// void DLLEXPORT swmm_getSemVersion(char* semver)
-// //
-// //  Output: Returns Semantic Version
-// //  Purpose: retrieves the current semantic version
-// //
-// //  NOTE: Each New Release should be updated in consts.h
-// {
-//     getSemVersion(semver);
-// }
 
-int DLLEXPORT swmm_getVersionInfo(char** major, char** minor, char** patch)
+EXPORT_TOOLKIT const char *swmm_getSemVersion()
 //
-//  Output: Returns Semantic Version Info
+//  Output: Returns Semantic Version
 //  Purpose: retrieves the current semantic version
 //
-//  NOTE: Each New Release should be updated in consts.h
 {
-    cstr_duplicate(major, SEMVERSION_MAJOR);
-    cstr_duplicate(minor, SEMVERSION_MINOR);
-    cstr_duplicate(patch, SEMVERSION_PATCH);
-    return 0;
+    return VERSION;
+}
+
+EXPORT_TOOLKIT const char *swmm_getBuildId()
+//
+//  Output: Returns Build Id
+//  Purpose: retrieves the current build id
+//
+{
+    return BUILD_ID;
 }
 
 //-----------------------------------------------------------------------------
 //  Extended API Functions
 //-----------------------------------------------------------------------------
 
-int DLLEXPORT  swmm_run_cb(const char* f1, const char* f2, const char* f3,
+EXPORT_TOOLKIT int swmm_run_cb(const char* f1, const char* f2, const char* f3,
     void (*callback) (double *))
 //
 //  Input:   f1 = name of input file
@@ -135,7 +134,7 @@ int DLLEXPORT  swmm_run_cb(const char* f1, const char* f2, const char* f3,
 }
 
 
-int DLLEXPORT swmm_getAPIError(int errorCode, char **errorMsg)
+EXPORT_TOOLKIT int swmm_getAPIError(int errorCode, char **errorMsg)
 ///
 /// Input:   errorCode = error code
 /// Output:  errmessage String
@@ -148,7 +147,7 @@ int DLLEXPORT swmm_getAPIError(int errorCode, char **errorMsg)
 }
 
 
-int DLLEXPORT swmm_project_findObject(SM_ObjectType type, char *id, int *index)
+EXPORT_TOOLKIT int swmm_project_findObject(SM_ObjectType type, char *id, int *index)
 {
     int error_code_index = 0;
 
@@ -163,7 +162,7 @@ int DLLEXPORT swmm_project_findObject(SM_ObjectType type, char *id, int *index)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getSimulationDateTime(SM_TimePropety type, int *year, int *month, int *day,
+EXPORT_TOOLKIT int swmm_getSimulationDateTime(SM_TimePropety type, int *year, int *month, int *day,
                                          int *hour, int *minute, int *second)
 ///
 /// Input:   type = time type to return
@@ -204,7 +203,7 @@ int DLLEXPORT swmm_getSimulationDateTime(SM_TimePropety type, int *year, int *mo
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_setSimulationDateTime(SM_TimePropety type, int year, int month,
+EXPORT_TOOLKIT int swmm_setSimulationDateTime(SM_TimePropety type, int year, int month,
                                          int day, int hour, int minute,
                                          int second)
 ///
@@ -266,7 +265,7 @@ int DLLEXPORT swmm_setSimulationDateTime(SM_TimePropety type, int year, int mont
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT  swmm_getSimulationUnit(SM_Units type, int *value)
+EXPORT_TOOLKIT int  swmm_getSimulationUnit(SM_Units type, int *value)
 ///
 /// Input:   type = simulation unit type
 /// Output:  enum representation of units
@@ -298,7 +297,7 @@ int DLLEXPORT  swmm_getSimulationUnit(SM_Units type, int *value)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT  swmm_getSimulationAnalysisSetting(SM_SimOption type, int *value)
+EXPORT_TOOLKIT int  swmm_getSimulationAnalysisSetting(SM_SimOption type, int *value)
 ///
 /// Input:   type = analysis type
 /// Output:  setting True or False
@@ -339,7 +338,7 @@ int DLLEXPORT  swmm_getSimulationAnalysisSetting(SM_SimOption type, int *value)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT  swmm_getSimulationParam(SM_SimSetting type, double *value)
+EXPORT_TOOLKIT int  swmm_getSimulationParam(SM_SimSetting type, double *value)
 ///
 /// Input:   type = analysis type
 /// Output:  Simulation Parameter
@@ -411,7 +410,7 @@ int DLLEXPORT  swmm_getSimulationParam(SM_SimSetting type, double *value)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT  swmm_countObjects(SM_ObjectType type, int *count)
+EXPORT_TOOLKIT int  swmm_countObjects(SM_ObjectType type, int *count)
 ///
 /// Input:   type = object type (Based on SM_ObjectType enum)
 /// Output:  count = pointer to integer
@@ -431,7 +430,7 @@ int DLLEXPORT  swmm_countObjects(SM_ObjectType type, int *count)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getObjectIndex(SM_ObjectType type, char *id, int *index)
+EXPORT_TOOLKIT int swmm_getObjectIndex(SM_ObjectType type, char *id, int *index)
 ///
 /// Input:   type = object type (Based on SM_ObjectType enum)
 ///          char* = ID name
@@ -450,7 +449,7 @@ int DLLEXPORT swmm_getObjectIndex(SM_ObjectType type, char *id, int *index)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getObjectId(SM_ObjectType type, int index, char **id)
+EXPORT_TOOLKIT int swmm_getObjectId(SM_ObjectType type, int index, char **id)
 ///
 /// Input:   type = object type (Based on SM_ObjectType enum)
 ///          index = Index of desired ID
@@ -516,7 +515,7 @@ int DLLEXPORT swmm_getObjectId(SM_ObjectType type, int index, char **id)
    return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getNodeType(int index, SM_NodeType *Ntype)
+EXPORT_TOOLKIT int swmm_getNodeType(int index, SM_NodeType *Ntype)
 ///
 /// Input:   index = Index of desired ID
 ///          Ntype = Node type (Based on enum SM_NodeType)
@@ -540,7 +539,7 @@ int DLLEXPORT swmm_getNodeType(int index, SM_NodeType *Ntype)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getLinkType(int index, SM_LinkType *Ltype)
+EXPORT_TOOLKIT int swmm_getLinkType(int index, SM_LinkType *Ltype)
 ///
 /// Input:   index = Index of desired ID
 ///          Ltype = Link type (Based on enum SM_LinkType)
@@ -564,7 +563,7 @@ int DLLEXPORT swmm_getLinkType(int index, SM_LinkType *Ltype)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getLinkConnections(int index, int *Node1, int *Node2)
+EXPORT_TOOLKIT int swmm_getLinkConnections(int index, int *Node1, int *Node2)
 ///
 /// Input:   index = Index of desired ID
 /// Output:  Node1 and Node2 indeces
@@ -592,7 +591,7 @@ int DLLEXPORT swmm_getLinkConnections(int index, int *Node1, int *Node2)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getLinkDirection(int index, signed char *value)
+EXPORT_TOOLKIT int swmm_getLinkDirection(int index, signed char *value)
 ///
 /// Input:   index = Index of desired ID
 /// Output:  Link Direction (Only changes is slope < 0)
@@ -618,7 +617,7 @@ int DLLEXPORT swmm_getLinkDirection(int index, signed char *value)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getNodeParam(int index, SM_NodeProperty param, double *value)
+EXPORT_TOOLKIT int swmm_getNodeParam(int index, SM_NodeProperty param, double *value)
 ///
 /// Input:   index = Index of desired ID
 ///          param = Parameter desired (Based on enum SM_NodeProperty)
@@ -658,7 +657,7 @@ int DLLEXPORT swmm_getNodeParam(int index, SM_NodeProperty param, double *value)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_setNodeParam(int index, SM_NodeProperty param, double value)
+EXPORT_TOOLKIT int swmm_setNodeParam(int index, SM_NodeProperty param, double value)
 ///
 /// Input:   index = Index of desired ID
 ///          param = Parameter desired (Based on enum SM_NodeProperty)
@@ -704,7 +703,7 @@ int DLLEXPORT swmm_setNodeParam(int index, SM_NodeProperty param, double value)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getLinkParam(int index, SM_LinkProperty param, double *value)
+EXPORT_TOOLKIT int swmm_getLinkParam(int index, SM_LinkProperty param, double *value)
 ///
 /// Input:   index = Index of desired ID
 ///          param = Parameter desired (Based on enum SM_LinkProperty)
@@ -748,7 +747,7 @@ int DLLEXPORT swmm_getLinkParam(int index, SM_LinkProperty param, double *value)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_setLinkParam(int index, SM_LinkProperty param, double value)
+EXPORT_TOOLKIT int swmm_setLinkParam(int index, SM_LinkProperty param, double value)
 ///
 /// Input:   index = Index of desired ID
 ///          param = Parameter desired (Based on enum SM_LinkProperty)
@@ -806,7 +805,7 @@ int DLLEXPORT swmm_setLinkParam(int index, SM_LinkProperty param, double value)
 }
 
 
-int DLLEXPORT swmm_getSubcatchParam(int index, SM_SubcProperty param, double *value)
+EXPORT_TOOLKIT int swmm_getSubcatchParam(int index, SM_SubcProperty param, double *value)
 ///
 /// Input:   index = Index of desired ID
 ///          param = Parameter desired (Based on enum SM_SubcProperty)
@@ -846,7 +845,7 @@ int DLLEXPORT swmm_getSubcatchParam(int index, SM_SubcProperty param, double *va
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_setSubcatchParam(int index, SM_SubcProperty param, double value)
+EXPORT_TOOLKIT int swmm_setSubcatchParam(int index, SM_SubcProperty param, double value)
 ///
 /// Input:   index = Index of desired ID
 ///          param = Parameter desired (Based on enum SM_SubcProperty)
@@ -897,7 +896,7 @@ int DLLEXPORT swmm_setSubcatchParam(int index, SM_SubcProperty param, double val
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getSubcatchOutConnection(int index, SM_ObjectType *type, int *out_index)
+EXPORT_TOOLKIT int swmm_getSubcatchOutConnection(int index, SM_ObjectType *type, int *out_index)
 ///
 /// Input:   index = Index of desired ID
 ///         (Subcatchments can load to Node or another Subcatchment)
@@ -941,7 +940,7 @@ int DLLEXPORT swmm_getSubcatchOutConnection(int index, SM_ObjectType *type, int
 }
 
 
-int DLLEXPORT swmm_getLidUCount(int index, int *value)
+EXPORT_TOOLKIT int swmm_getLidUCount(int index, int *value)
 // Input:   index = Index of desired subcatchment
 // Output:  int = number of lid units for subcatchment
 // Return:  number of lid units for subcatchment
@@ -968,7 +967,7 @@ int DLLEXPORT swmm_getLidUCount(int index, int *value)
 }
 
 
-int DLLEXPORT swmm_getLidUParam(int index, int lidIndex, SM_LidUProperty param, double *value)
+EXPORT_TOOLKIT int swmm_getLidUParam(int index, int lidIndex, SM_LidUProperty param, double *value)
 //
 // Input:   index = Index of desired subcatchment
 //          lidIndex = Index of desired lid unit (subcatchment allow for multiple lid units)
@@ -1022,7 +1021,7 @@ int DLLEXPORT swmm_getLidUParam(int index, int lidIndex, SM_LidUProperty param,
 }
 
 
-int DLLEXPORT swmm_setLidUParam(int index, int lidIndex, SM_LidUProperty param, double value)
+EXPORT_TOOLKIT int swmm_setLidUParam(int index, int lidIndex, SM_LidUProperty param, double value)
 //
 // Input:   index = Index of desired subcatchment
 //          lidIndex = Index of desired lid unit (subcatchment allow for multiple lid units)
@@ -1087,7 +1086,7 @@ int DLLEXPORT swmm_setLidUParam(int index, int lidIndex, SM_LidUProperty param,
 }
 
 
-int DLLEXPORT swmm_getLidUOption(int index, int lidIndex, SM_LidUOptions param, int *value)
+EXPORT_TOOLKIT int swmm_getLidUOption(int index, int lidIndex, SM_LidUOptions param, int *value)
 //
 // Input:   index = Index of desired subcatchment
 //          lidIndex = Index of desired lid unit (subcatchment allow for multiple lid units)
@@ -1139,7 +1138,7 @@ int DLLEXPORT swmm_getLidUOption(int index, int lidIndex, SM_LidUOptions param,
 }
 
 
-int DLLEXPORT swmm_setLidUOption(int index, int lidIndex, SM_LidUOptions param, int value)
+EXPORT_TOOLKIT int swmm_setLidUOption(int index, int lidIndex, SM_LidUOptions param, int value)
 //
 // Input:   index = Index of desired subcatchment
 //          lidIndex = Index of desired lid unit (subcatchment allow for multiple lid units)
@@ -1237,7 +1236,7 @@ int DLLEXPORT swmm_setLidUOption(int index, int lidIndex, SM_LidUOptions param,
 }
 
 
-int DLLEXPORT swmm_getLidCOverflow(int lidControlIndex, int *condition)
+EXPORT_TOOLKIT int swmm_getLidCOverflow(int lidControlIndex, int *condition)
 //
 // Input:   lidControlIndex = Index of desired lid control
 // Output:  condition = value to be output
@@ -1269,7 +1268,7 @@ int DLLEXPORT swmm_getLidCOverflow(int lidControlIndex, int *condition)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_LidLayerProperty param, double *value)
+EXPORT_TOOLKIT int swmm_getLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_LidLayerProperty param, double *value)
 //
 // Input:   lidControlIndex = Index of desired lid control
 //          layerIndex = Index of desired lid control layer (Based on enum SM_LidLayer)
@@ -1452,7 +1451,7 @@ int DLLEXPORT swmm_getLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_
 }
 
 
-int DLLEXPORT swmm_setLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_LidLayerProperty param, double value)
+EXPORT_TOOLKIT int swmm_setLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_LidLayerProperty param, double value)
 //
 // Input:   lidControlIndex = Index of desired lid control
 //          layerIndex = Index of desired lid control layer (Based on enum SM_LidLayers)
@@ -1797,7 +1796,7 @@ int DLLEXPORT swmm_setLidCParam(int lidControlIndex, SM_LidLayer layerIndex, SM_
 // Active Simulation Results API
 //-------------------------------
 
-int DLLEXPORT swmm_getCurrentDateTime(int *year, int *month, int *day,
+EXPORT_TOOLKIT int swmm_getCurrentDateTime(int *year, int *month, int *day,
                                       int *hour, int *minute, int *second)
 ///
 /// Input:   timetype = time type to return
@@ -1832,7 +1831,7 @@ int DLLEXPORT swmm_getCurrentDateTime(int *year, int *month, int *day,
 }
 
 
-int DLLEXPORT swmm_getNodeResult(int index, SM_NodeResult type, double *result)
+EXPORT_TOOLKIT int swmm_getNodeResult(int index, SM_NodeResult type, double *result)
 ///
 /// Input:   index = Index of desired ID
 ///          type = Result Type (SM_NodeResult)
@@ -1874,16 +1873,18 @@ int DLLEXPORT swmm_getNodeResult(int index, SM_NodeResult type, double *result)
                             + Node[index].invertElev) * UCF(LENGTH); break;
             case SM_LATINFLOW:
                 *result = Node[index].newLatFlow * UCF(FLOW); break;
+	        case SM_HRT:
+		        *result = Storage[Node[index].subIndex].hrt; break;
             default: error_code_index = ERR_API_OUTBOUNDS; break;
         }
     }
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getNodePollut(int index, SM_NodePollut type, double **pollutArray, int *length)
+EXPORT_TOOLKIT int swmm_getNodePollut(int index, SM_NodePollut type, double **pollutArray, int *length)
 ///
 /// Input:   index = Index of desired ID
-///          type = Result Type (SM_NodePollut)
+///          type = Result Type (SM_NodePollut or SM_NODECIN or SM_NODEREACTORC)
 /// Output:  PollutArray pointer (pollutant data desired, byref)
 /// Return:  API Error
 /// Purpose: Gets Node Simulated Water Quality Value at Current Time
@@ -1909,6 +1910,8 @@ int DLLEXPORT swmm_getNodePollut(int index, SM_NodePollut type, double **pollutA
 
     else
     {
+        *length = Nobjects[POLLUT];
+
         switch (type)
         {
             case SM_NODEQUAL:
@@ -1916,9 +1919,24 @@ int DLLEXPORT swmm_getNodePollut(int index, SM_NodePollut type, double **pollutA
                 for (p = 0; p < Nobjects[POLLUT]; p++)
                 {
                     result[p] = Node[index].newQual[p];
-                } 
+                }
+                *pollutArray = result;
+            } break;
+            case SM_NODECIN:
+            {
+                for (p=0; p < Nobjects[POLLUT]; p++)
+                {
+                    result[p] = Node[index].inQual[p];
+                }
+                *pollutArray = result;
+            } break;
+            case SM_NODEREACTORC:
+            {
+                for (p=0; p < Nobjects[POLLUT]; p++)
+                {
+                    result[p] = Node[index].reactorQual[p];
+                }
                 *pollutArray = result;
-                *length = Nobjects[POLLUT];
             } break;
             default: error_code_index = ERR_API_OUTBOUNDS; break;
         }
@@ -1926,7 +1944,52 @@ int DLLEXPORT swmm_getNodePollut(int index, SM_NodePollut type, double **pollutA
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getLinkResult(int index, SM_LinkResult type, double *result)
+EXPORT_TOOLKIT int swmm_setNodePollut(int index, SM_NodePollut type, int pollutant_index, double pollutant_value)
+///
+/// Input:   index = Index of desired ID
+///          type = SM_NODEQUAL - Set's node's qual and allows accounting for loss and mixing calculation
+///          pollutant_index = Index of desired polluant
+///          pollutant_value = Value of the pollutant
+/// Return:  API Error
+/// Purpose: Set pollutant concentration in nodes at the current time step
+{
+	int error_code_index = 0;
+
+	// Check if Open
+	if(swmm_IsOpenFlag() == FALSE)
+	{
+	    error_code_index = ERR_API_INPUTNOTOPEN;
+	}
+	// Check if object index is within bounds
+	else if (index < 0 || index >= Nobjects[NODE])
+	{
+	    error_code_index = ERR_API_OBJECT_INDEX;
+	}
+	else
+	{
+		if (ExtPollutFlag == 0)
+		{
+			ExtPollutFlag = 1;
+		}
+		if (pollutant_index <= Nobjects[POLLUT])
+		{
+            switch(type)
+            {
+                case SM_NODEQUAL:
+                {
+                    Node[index].extQual[pollutant_index] = pollutant_value;
+	    		    Node[index].extPollutFlag[pollutant_index] = 1;
+                } break;
+                default: error_code_index = ERR_API_OUTBOUNDS; break;
+            }
+			
+		}
+	}
+	return error_getCode(error_code_index);
+}
+
+
+EXPORT_TOOLKIT int swmm_getLinkResult(int index, SM_LinkResult type, double *result)
 ///
 /// Input:   index = Index of desired ID
 ///          type = Result Type (SM_LinkResult)
@@ -1952,7 +2015,7 @@ int DLLEXPORT swmm_getLinkResult(int index, SM_LinkResult type, double *result)
         switch (type)
         {
             case SM_LINKFLOW:
-                *result = Link[index].newFlow * UCF(FLOW) ; break;
+                *result = Link[index].newFlow * (double) Link[index].direction * UCF(FLOW); break;
             case SM_LINKDEPTH:
                 *result = Link[index].newDepth * UCF(LENGTH); break;
             case SM_LINKVOL:
@@ -1973,7 +2036,7 @@ int DLLEXPORT swmm_getLinkResult(int index, SM_LinkResult type, double *result)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutArray, int *length)
+EXPORT_TOOLKIT int swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutArray, int *length)
 ///
 /// Input:   index = Index of desired ID
 ///          type = Result Type (SM_LinkPollut)
@@ -2002,6 +2065,8 @@ int DLLEXPORT swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutA
 
     else
     {
+        *length = Nobjects[POLLUT];
+
         switch (type)
         {
             case SM_LINKQUAL:
@@ -2009,9 +2074,8 @@ int DLLEXPORT swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutA
                 for (p = 0; p < Nobjects[POLLUT]; p++)
                 {
                     result[p] = Link[index].newQual[p];
-                } 
+                }
                 *pollutArray = result;
-                *length = Nobjects[POLLUT];
             } break;
             case SM_TOTALLOAD:
             {
@@ -2024,7 +2088,14 @@ int DLLEXPORT swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutA
                     }
                 } 
                 *pollutArray = result;
-                *length = Nobjects[POLLUT];
+            } break;
+            case SM_LINKREACTORC:
+            {
+                for (p = 0; p < Nobjects[POLLUT]; p++)
+                {
+                    result[p] = Link[index].reactorQual[p];
+                }
+                *pollutArray = result;
             } break;
             default: error_code_index = ERR_API_OUTBOUNDS; break;
         } 
@@ -2032,7 +2103,51 @@ int DLLEXPORT swmm_getLinkPollut(int index, SM_LinkPollut type, double **pollutA
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getSubcatchResult(int index, SM_SubcResult type, double* result)
+
+EXPORT_TOOLKIT int swmm_setLinkPollut(int index, SM_LinkPollut type, int pollutant_index, double pollutant_value)
+///
+///  Input: index = Index of the desired Link ID
+/// 	    type = SM_LINKQUAL - Sets link's qual and allows accounting for loss and mixing calculation
+///         pollutant_index = index of pollutant to set
+///         pollutant_value = concentration to set
+///  Return: API error
+///  Purponse: Set pollutant concentration in links 
+{
+	int error_code_index = 0;
+    
+	// Check if Open
+	if(swmm_IsOpenFlag() == FALSE)
+	{
+	    error_code_index = ERR_API_INPUTNOTOPEN;
+	}
+	// Check if object index is within bounds
+	else if (index < 0 || index >= Nobjects[LINK])
+	{
+	    error_code_index = ERR_API_OBJECT_INDEX;
+	}
+	else
+	{
+		if (ExtPollutFlag == 0)
+		{
+			ExtPollutFlag = 1;
+		}
+		if (pollutant_index <= Nobjects[POLLUT])
+		{
+			switch(type)
+			{
+				case SM_LINKQUAL:
+					{
+						Link[index].extQual[pollutant_index] = pollutant_value;
+						Link[index].extPollutFlag[pollutant_index] = 1;
+					} break;
+				default: error_code_index = ERR_API_OUTBOUNDS; break;
+			}
+		}
+	}
+	return error_getCode(error_code_index);
+}
+
+EXPORT_TOOLKIT int swmm_getSubcatchResult(int index, SM_SubcResult type, double* result)
 ///
 /// Input:   index = Index of desired ID
 ///          type = Result Type (SM_SubcResult)
@@ -2075,7 +2190,7 @@ int DLLEXPORT swmm_getSubcatchResult(int index, SM_SubcResult type, double* resu
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getSubcatchPollut(int index, SM_SubcPollut type, double **pollutArray, int *length)
+EXPORT_TOOLKIT int swmm_getSubcatchPollut(int index, SM_SubcPollut type, double **pollutArray, int *length)
 ///
 /// Input:   index = Index of desired ID
 ///          type = Result Type (SM_SubcPollut)
@@ -2156,7 +2271,7 @@ int DLLEXPORT swmm_getSubcatchPollut(int index, SM_SubcPollut type, double **pol
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getGagePrecip(int index, SM_GagePrecip type, double* result)
+EXPORT_TOOLKIT int swmm_getGagePrecip(int index, SM_GagePrecip type, double* result)
 ///
 /// Input:   index = Index of desired ID
 ///          type = Result type
@@ -2198,7 +2313,7 @@ int DLLEXPORT swmm_getGagePrecip(int index, SM_GagePrecip type, double* result)
 }
 
 
-int DLLEXPORT swmm_getNodeStats(int index, SM_NodeStats *nodeStats)
+EXPORT_TOOLKIT int swmm_getNodeStats(int index, SM_NodeStats *nodeStats)
 ///
 /// Output:  Node Stats Structure (SM_NodeStats)
 /// Return:  API Error
@@ -2227,7 +2342,7 @@ int DLLEXPORT swmm_getNodeStats(int index, SM_NodeStats *nodeStats)
     return error_getCode(error_index);
 }
 
-int DLLEXPORT swmm_getNodeTotalInflow(int index, double* value)
+EXPORT_TOOLKIT int swmm_getNodeTotalInflow(int index, double* value)
 ///
 /// Input:   Node Index
 /// Output:  Node Total inflow Volume.
@@ -2250,7 +2365,7 @@ int DLLEXPORT swmm_getNodeTotalInflow(int index, double* value)
     return error_getCode(error_index);
 }
 
-int DLLEXPORT swmm_getStorageStats(int index, SM_StorageStats *storageStats)
+EXPORT_TOOLKIT int swmm_getStorageStats(int index, SM_StorageStats *storageStats)
 ///
 /// Output:  Storage Node Stats Structure (SM_StorageStats)
 /// Return:  API Error
@@ -2283,7 +2398,7 @@ int DLLEXPORT swmm_getStorageStats(int index, SM_StorageStats *storageStats)
     return error_getCode(error_index);
 }
 
-int DLLEXPORT swmm_getOutfallStats(int index, SM_OutfallStats *outfallStats)
+EXPORT_TOOLKIT int swmm_getOutfallStats(int index, SM_OutfallStats *outfallStats)
 {
     int error_index = 0;
     
@@ -2313,7 +2428,7 @@ int DLLEXPORT swmm_getOutfallStats(int index, SM_OutfallStats *outfallStats)
 }
 
 
-int DLLEXPORT swmm_getLinkStats(int index, SM_LinkStats *linkStats)
+EXPORT_TOOLKIT int swmm_getLinkStats(int index, SM_LinkStats *linkStats)
 ///
 /// Output:  Link Stats Structure (SM_LinkStats)
 /// Return:  API Error
@@ -2343,7 +2458,7 @@ int DLLEXPORT swmm_getLinkStats(int index, SM_LinkStats *linkStats)
 }
 
 
-int DLLEXPORT swmm_getPumpStats(int index, SM_PumpStats *pumpStats)
+EXPORT_TOOLKIT int swmm_getPumpStats(int index, SM_PumpStats *pumpStats)
 ///
 /// Output:  Pump Link Stats Structure (SM_PumpStats)
 /// Return:  API Error
@@ -2377,7 +2492,7 @@ int DLLEXPORT swmm_getPumpStats(int index, SM_PumpStats *pumpStats)
 }
 
 
-int DLLEXPORT swmm_getSubcatchStats(int index, SM_SubcatchStats *subcatchStats)
+EXPORT_TOOLKIT int swmm_getSubcatchStats(int index, SM_SubcatchStats *subcatchStats)
 ///
 /// Output:  Subcatchment Stats Structure (SM_SubcatchStats)
 /// Return:  API Error
@@ -2407,7 +2522,7 @@ int DLLEXPORT swmm_getSubcatchStats(int index, SM_SubcatchStats *subcatchStats)
 }
 
 
-int DLLEXPORT swmm_getSystemRoutingTotals(SM_RoutingTotals *routingTotals)
+EXPORT_TOOLKIT int swmm_getSystemRoutingTotals(SM_RoutingTotals *routingTotals)
 ///
 /// Output:  System Routing Totals Structure (SM_RoutingTotals)
 /// Return:  API Error
@@ -2432,7 +2547,7 @@ int DLLEXPORT swmm_getSystemRoutingTotals(SM_RoutingTotals *routingTotals)
     return error_getCode(error_index);
 }
 
-int DLLEXPORT swmm_getSystemRunoffTotals(SM_RunoffTotals *runoffTotals)
+EXPORT_TOOLKIT int swmm_getSystemRunoffTotals(SM_RunoffTotals *runoffTotals)
 ///
 /// Output:  System Runoff Totals Structure (SM_RunoffTotals)
 /// Return:  API Error
@@ -2457,7 +2572,7 @@ int DLLEXPORT swmm_getSystemRunoffTotals(SM_RunoffTotals *runoffTotals)
     return error_getCode(error_index);
 }
 
-int DLLEXPORT swmm_getLidUFluxRates(int index, int lidIndex, SM_LidLayer layerIndex, double* result)
+EXPORT_TOOLKIT int swmm_getLidUFluxRates(int index, int lidIndex, SM_LidLayer layerIndex, double* result)
 //
 // Input:   index = Index of desired subcatchment
 //          lidIndex = Index of desired lid control (subcatchment allow for multiple lids)
@@ -2508,7 +2623,7 @@ int DLLEXPORT swmm_getLidUFluxRates(int index, int lidIndex, SM_LidLayer layerIn
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getLidGResult(int index, SM_LidResult type, double* result)
+EXPORT_TOOLKIT int swmm_getLidGResult(int index, SM_LidResult type, double* result)
 //
 // Input:   index = index of desired subcatchment
 //          type = type of result data desired
@@ -2557,7 +2672,7 @@ int DLLEXPORT swmm_getLidGResult(int index, SM_LidResult type, double* result)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_getLidUResult(int index, int lidIndex, SM_LidResult type, double* result)
+EXPORT_TOOLKIT int swmm_getLidUResult(int index, int lidIndex, SM_LidResult type, double* result)
 //
 // Input:   index = Index of desired subcatchment
 //          lidIndex = Index of desired lid control (subcatchment allow for multiple lids)
@@ -2660,7 +2775,7 @@ int DLLEXPORT swmm_getLidUResult(int index, int lidIndex, SM_LidResult type, dou
 // Setters API
 //-------------------------------
 
-int DLLEXPORT swmm_setLinkSetting(int index, double setting)
+EXPORT_TOOLKIT int swmm_setLinkSetting(int index, double setting)
 ///
 /// Input:   index = Index of desired ID
 ///          value = New Target Setting
@@ -2703,7 +2818,7 @@ int DLLEXPORT swmm_setLinkSetting(int index, double setting)
 }
 
 
-int DLLEXPORT swmm_setNodeInflow(int index, double flowrate)
+EXPORT_TOOLKIT int swmm_setNodeInflow(int index, double flowrate)
 ///
 /// Input:   index = Index of desired ID
 ///          value = New Inflow Rate
@@ -2764,7 +2879,7 @@ int DLLEXPORT swmm_setNodeInflow(int index, double flowrate)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_setOutfallStage(int index, double stage)
+EXPORT_TOOLKIT int swmm_setOutfallStage(int index, double stage)
 ///
 /// Input:   index = Index of desired outfall
 ///          stage = New outfall stage (head)
@@ -2799,7 +2914,7 @@ int DLLEXPORT swmm_setOutfallStage(int index, double stage)
     return error_getCode(error_code_index);
 }
 
-int DLLEXPORT swmm_setGagePrecip(int index, double total_precip)
+EXPORT_TOOLKIT int swmm_setGagePrecip(int index, double total_precip)
 ///
 /// Input:   index = Index of desired ID
 ///          total_precip = rainfall intensity to be set
@@ -2837,6 +2952,15 @@ int DLLEXPORT swmm_setGagePrecip(int index, double total_precip)
     return error_getCode(error_code_index);
 }
 
+EXPORT_TOOLKIT void swmm_freeMemory(void *memory)
+//
+//  Purpose: Frees memory allocated by API calls
+//
+{
+    free(memory);
+}
+
+
 //-------------------------------
 // Utility Functions
 //-------------------------------
@@ -2848,22 +2972,3 @@ double* newDoubleArray(int n)
 {
     return (double*) malloc((n)*sizeof(double));
 }
-
-
-//void DLLEXPORT freeArray(void** array)
-///
-/// Helper function used to free array allocated memory by API.
-///
-//{
-//    FREE(*array);
-//    *array = NULL;
-//}
-
-
-void DLLEXPORT swmm_freeMemory(void *memory)
-//
-//  Purpose: Frees memory allocated by API calls
-//
-{
-    free(memory);
-}
diff --git a/src/solver/treatmnt.c b/src/solver/treatmnt.c
index 0843b5f96..1b1491e49 100644
--- a/src/solver/treatmnt.c
+++ b/src/solver/treatmnt.c
@@ -208,7 +208,7 @@ void  treatmnt_treat(int j, double q, double v, double tStep)
     double cOut;                       // concentration after treatment
     double massLost;                   // mass lost by treatment per time step
     TTreatment* treatment;             // pointer to treatment object
-
+ 
     // --- set locally shared variables for node j
     if ( Node[j].treatment == NULL ) return;
     ErrCode = 0;
@@ -216,7 +216,6 @@ void  treatmnt_treat(int j, double q, double v, double tStep)
     Dt = tStep;                        // current time step
     Q  = q;                            // current inflow rate
     V  = v;                            // current node volume
-
     // --- initialze each removal to indicate no value 
     for ( p = 0; p < Nobjects[POLLUT]; p++) R[p] = -1.0;
 
@@ -228,7 +227,10 @@ void  treatmnt_treat(int j, double q, double v, double tStep)
         if ( treatment->equation == NULL ) R[p] = 0.0;
 
         // --- no removal for removal-type expression when there is no inflow 
-	    else if ( treatment->treatType == REMOVAL && q <= ZERO ) R[p] = 0.0;
+	else if ( treatment->treatType == REMOVAL && q <= ZERO ) R[p] = 0.0;
+
+	// --- check for external treatment
+	else if ( Node[j].extPollutFlag[p] == 1) R[p] = 0.0;
 
         // --- otherwise evaluate the treatment expression to find R[p]
         else getRemoval(p);
@@ -239,16 +241,16 @@ void  treatmnt_treat(int j, double q, double v, double tStep)
     {
          report_writeErrorMsg(ERR_CYCLIC_TREATMENT, Node[J].ID);
     }
-
+   
     // --- update nodal concentrations and mass balances
     else for ( p = 0; p < Nobjects[POLLUT]; p++ )
     {
-        if ( R[p] == 0.0 ) continue;
+        if ( R[p] == 0.0 && Node[j].extPollutFlag[p] != 1) continue;
         treatment = &Node[j].treatment[p];
 
         // --- removal-type treatment equations get applied to inflow stream
 
-        if ( treatment->treatType == REMOVAL )
+        if ( treatment->treatType == REMOVAL && Node[j].extPollutFlag[p] != 1)
         {
             // --- if no pollutant in inflow then cOut is current nodal concen.
             if ( Cin[p] == 0.0 ) cOut = Node[j].newQual[p];
@@ -261,16 +263,30 @@ void  treatmnt_treat(int j, double q, double v, double tStep)
             cOut = MIN(cOut, Node[j].newQual[p]);
         }
 
+	// --- water quality set externally 
+	else if( Node[j].extPollutFlag[p] == 1)
+	{
+	    cOut = Node[j].extQual[p];
+	}
+
         // --- concentration-type equations get applied to nodal concentration
         else
         {
             cOut = (1.0 - R[p]) * Node[j].newQual[p];
         }
+	
+       	// --- store inflow concentration for the timestep 	
+	Node[j].inQual[p] = Cin[p];
 
-        // --- mass lost must account for any initial mass in storage 
+ 	// --- mass lost must account for any initial mass in storage 
         massLost = (Cin[p]*q*tStep + Node[j].oldQual[p]*Node[j].oldVolume - 
-                   cOut*(q*tStep + Node[j].oldVolume)) / tStep; 
-        massLost = MAX(0.0, massLost); 
+                   cOut*(q*tStep + Node[j].oldVolume)) / tStep;
+
+	// --- mass can be gained in external treatment
+	if (Node[j].extPollutFlag[p] != 1) massLost = MAX(0.0, massLost);
+
+	// --- reset the flag to default to swmm treatment
+	if (Node[j].extPollutFlag[p] == 1) Node[j].extPollutFlag[p] = 0;
 
         // --- add mass loss to mass balance totals and revise nodal concentration
         massbal_addReactedMass(p, massLost);


Test patch:
diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml
index 0d8bff3ec..41e7c5020 100644
--- a/.github/workflows/build-test.yml
+++ b/.github/workflows/build-test.yml
@@ -2,7 +2,7 @@
 #  build-and-test.yml - GitHub Actions CI for swmm-solver
 #
 #  Created: May 19, 2020
-#  Updated: Aug 13, 2020
+#  Updated: Jun 22, 2021
 #
 #  Author: Michael E. Tryby
 #          US EPA - ORD/CESER
@@ -14,40 +14,39 @@
 name: Build and Test
 
 on: [push, pull_request]
-#  push:
-#    branches: [master release develop]
-#    tags:
-#      - 'v*.*.*'
-#  pull_request:
-#    branches: [master release develop]
 
 jobs:
   build:
     strategy:
       fail-fast: false
       matrix:
-        os: [windows-2016, ubuntu-16.04, macos-10.15]
+        os: [windows-2022, ubuntu-20.04, macos-10.15]
         requirements: [requirements-swmm.txt]
         include:
-          - os: windows-2016
+          - os: windows-2022
             sys_pkgs: choco install boost-msvc-14.1
-            generator: Visual Studio 15 2017 Win64
-            experimental: true
-            script_extension: cmd
+            build_unit_test: make.cmd /g "Visual Studio 17 2022" /A "x64" /t
+            build_reg_test: make.cmd /g "Visual Studio 17 2022" /A "x64"
+            before_reg_test: before-nrtest.cmd
+            run_reg_test: run-nrtests.cmd
+            build_id: "%GITHUB_RUN_ID%_%GITHUB_RUN_NUMBER%"
+            experimental: false
             artifacts_ext: zip
             artifact_content_type: zip
-            gh_run_number: "%GITHUB_RUN_ID%_%GITHUB_RUN_NUMBER%"
             defaults:
               run:
                 shell: cmd
                 working-directory: ./ci-tools/windows
 
-          - os: ubuntu-16.04
+          - os: ubuntu-20.04
             sys_pkgs: sudo apt install libboost-dev libboost-all-dev
-            generator: "Unix Makefiles"
+            # Statically link libraries with -s switch to address GitHub Ubuntu 20.04 symbol errors (issue #340)
+            build_unit_test: make.sh -s -t -g "Unix Makefiles"
+            build_reg_test: make.sh -s -g "Unix Makefiles"
+            before_reg_test: before-nrtest.sh
+            run_reg_test: run-nrtests.sh
+            build_id: ${GITHUB_RUN_ID}_${GITHUB_RUN_NUMBER}
             experimental: true
-            script_extension: sh
-            gh_run_number: ${GITHUB_RUN_ID}_${GITHUB_RUN_NUMBER}
             artifacts_ext: tar.gz
             artifact_content_type: tar
             defaults:
@@ -57,11 +56,12 @@ jobs:
 
           - os: macos-10.15
             sys_pkgs: brew install libomp boost
-            generator: Xcode
+            build_unit_test: make.zsh -t -g "Xcode"
+            build_reg_test: make.zsh -g "Xcode"
+            before_reg_test: before-nrtest.zsh
+            run_reg_test: run-nrtests.zsh
+            build_id: ${GITHUB_RUN_ID}_${GITHUB_RUN_NUMBER}
             experimental: true
-            ci_tools_path: ci-tools/darwin
-            script_extension: zsh
-            gh_run_number: ${GITHUB_RUN_ID}_${GITHUB_RUN_NUMBER}
             artifacts_ext: tar.gz
             artifact_content_type: tar
             defaults:
@@ -80,8 +80,6 @@ jobs:
       PROJECT: swmm
       BUILD_HOME: build
       TEST_HOME: nrtests
-      NRTESTS_URL: https://github.com/OpenWaterAnalytics/swmm-nrtestsuite
-      # ACTIONS_ALLOW_UNSECURE_COMMANDS: true
 
     steps:
       - name: Checkout repo
@@ -102,26 +100,25 @@ jobs:
       - name: Install requirements
         run: |
           python -m pip install --upgrade pip
-          python -m pip install -r ${{ matrix.requirements }}
+          python -m pip install -r requirements-swmm.txt
 
       - name: Install required system packages
         run: ${{ matrix.sys_pkgs }}
 
       - name: Build and unit test
-        run: |
-          ./make.${{ matrix.script_extension }} -t -g "${{ matrix.generator }}"
+        run: ./${{ matrix.build_unit_test }}
 
       - name: Build for reg test
-        run: |
-          ./make.${{ matrix.script_extension }} -g "${{ matrix.generator }}"
+        run: ./${{ matrix.build_reg_test }}
 
       - name: Before reg test
-        run: |
-          ./before-nrtest.${{ matrix.script_extension }} v1.0.3-dev
+        env:
+          NRTESTS_URL: https://github.com/OpenWaterAnalytics/swmm-nrtestsuite
+          BENCHMARK_TAG: v2.0.1
+        run: ./${{ matrix.before_reg_test }} ${{ env.BENCHMARK_TAG }}
 
       - name: Run reg test
-        run: |
-          ./run-nrtests.${{ matrix.script_extension }} ${{ matrix.gh_run_number }}
+        run: ./${{ matrix.run_reg_test }} ${{ matrix.build_id }}
 
       - name: Upload artifacts
         if: ${{ always() }}
@@ -129,25 +126,3 @@ jobs:
         with:
           name: build-test-artifacts
           path: upload/*.*
-
-      # - name: Create release
-      #   id: create_release
-      #   uses: actions/create-release@v1
-      #   env:
-      #     GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-      #   with:
-      #     tag_name: ${{ github.ref }}
-      #     release_name: Release ${{ github.ref }}
-      #     draft: true
-      #     prerelease: true
-
-      # - name: Upload release assets
-      #   id: upload-release-asset
-      #   uses: actions/upload-release-asset@v1
-      #   env:
-      #     GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-      #   with:
-      #     upload_url: ${{ steps.create_release.outputs.upload_url }}
-      #     asset_path: upload/${PROJECT}*.${{ matrix.artifacts_ext }}
-      #     asset_name: owa-${PROJECT}-${{ matrix.os }}-${{ github.ref }}.${{ matrix.artifacts_ext }}
-      #     asset_content_type: application/${{ matrix.artifact_content_type }}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 4cbe5698c..17f17d546 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -2,12 +2,14 @@
 # CMakeLists.txt - CMake configuration file for swmm-solver/tests
 #
 # Created: Jul 7, 2020
+# Updated: Jan 14, 2021
 #
 # Author: Michael E. Tryby
 #         US EPA ORD/CESER
 #
 
 
+
 #Prep ourselves for compiling with boost
 include(../extern/boost.cmake)
 
diff --git a/tests/outfile/test_output.cpp b/tests/outfile/test_output.cpp
index e0b901bd6..1d44400ad 100644
--- a/tests/outfile/test_output.cpp
+++ b/tests/outfile/test_output.cpp
@@ -1,7 +1,7 @@
 /*
  ******************************************************************************
  Project:      OWA SWMM
- Version:      5.1.13
+ Version:      5.1.14
  Module:       test_output.cpp
  Description:  tests for output library functions
  Authors:      see AUTHORS
@@ -257,7 +257,7 @@ BOOST_FIXTURE_TEST_CASE(test_getSubcatchSeries, Fixture) {
     const int ref_dim            = 10;
     float     ref_array[ref_dim] = {
         0.0f, 1.2438242f, 2.5639679f, 4.524055f, 2.5115132f, 0.69808137f,
-        0.040894926f, 0.011605669f, 0.00509294f, 0.0027438672f};
+		0.040894926f, 0.011605669f, 0.00509294f, 0.0027438672f};
 
     std::vector<float> ref_vec;
     ref_vec.assign(ref_array, ref_array + 10);
@@ -274,7 +274,7 @@ BOOST_FIXTURE_TEST_CASE(test_getSubcatchResult, Fixture) {
 
     const int ref_dim            = 10;
     float     ref_array[ref_dim] = {
-        0.5f, 0.0f, 0.0f, 0.125f, 1.2438242f,
+		0.5f, 0.0f, 0.0f, 0.125f, 1.2438242f,
         0.0f, 0.0f, 0.0f, 33.481991f, 6.6963983f};
 
     std::vector<float> ref_vec;
@@ -292,8 +292,8 @@ BOOST_FIXTURE_TEST_CASE(test_getNodeResult, Fixture) {
 
     const int ref_dim        = 8;
     float ref_array[ref_dim] = {
-        0.296234f, 995.296204f, 0.0f, 1.302650f, 1.302650f, 0.0f,
-        15.361463f, 3.072293f};
+		0.296234f, 995.296204f, 0.0f, 1.302650f, 1.302650f, 0.0f,
+		15.361463f, 3.072293f};
 
     std::vector<float> ref_vec;
     ref_vec.assign(ref_array, ref_array + ref_dim);
@@ -310,8 +310,8 @@ BOOST_FIXTURE_TEST_CASE(test_getLinkResult, Fixture) {
 
     const int ref_dim        = 7;
     float ref_array[ref_dim] = {
-        4.631762f, 1.0f, 5.8973422f, 314.15927f, 1.0f, 19.070757f,
-        3.8141515f};
+		4.631762f, 1.0f, 5.8973422f, 314.15927f, 1.0f, 19.070757f,
+		3.8141515f};
 
     std::vector<float> ref_vec;
     ref_vec.assign(ref_array, ref_array + ref_dim);
@@ -329,7 +329,7 @@ BOOST_FIXTURE_TEST_CASE(test_getSystemResult, Fixture) {
     const int ref_dim            = 14;
     float     ref_array[ref_dim] = {
         70.0f, 0.1f, 0.0f, 0.19042271f, 14.172027f, 0.0f, 0.0f, 0.0f,
-        0.0f, 14.172027f, 0.55517411f, 13.622702f, 2913.0793f, 0.0f};
+		0.0f, 14.172027f, 0.55517411f, 13.622702f, 2913.0793f, 0.0f};
 
     std::vector<float> ref_vec;
     ref_vec.assign(ref_array, ref_array + ref_dim);
diff --git a/tests/solver/CMakeLists.txt b/tests/solver/CMakeLists.txt
index ae987411e..da8a5d375 100644
--- a/tests/solver/CMakeLists.txt
+++ b/tests/solver/CMakeLists.txt
@@ -48,7 +48,7 @@ target_compile_features(test_solver
     PUBLIC
       cxx_generalized_initializers
 )
-  
+
 target_link_libraries(test_solver
     ${Boost_LIBRARIES}
     swmm5
diff --git a/tests/solver/data/link_constantinflow.inp b/tests/solver/data/link_constantinflow.inp
new file mode 100644
index 000000000..77a1123d0
--- /dev/null
+++ b/tests/solver/data/link_constantinflow.inp
@@ -0,0 +1,165 @@
+[TITLE]
+;;Project Title/Notes
+Example 6
+Circular Culvert with Roadway Overtopping
+and Upstream Storage
+
+[OPTIONS]
+;;Option             Value
+FLOW_UNITS           CFS
+INFILTRATION         HORTON
+FLOW_ROUTING         DYNWAVE
+LINK_OFFSETS         DEPTH
+MIN_SLOPE            0
+ALLOW_PONDING        NO
+SKIP_STEADY_STATE    NO
+
+START_DATE           06/08/2015
+START_TIME           00:00:00
+REPORT_START_DATE    06/08/2015
+REPORT_START_TIME    00:00:00
+END_DATE             06/08/2015
+END_TIME             05:00:00
+SWEEP_START          01/01
+SWEEP_END            12/31
+DRY_DAYS             0
+REPORT_STEP          00:00:01
+WET_STEP             00:00:01
+DRY_STEP             00:00:01
+ROUTING_STEP         1
+RULE_STEP            00:00:00
+
+INERTIAL_DAMPING     PARTIAL
+NORMAL_FLOW_LIMITED  BOTH
+FORCE_MAIN_EQUATION  H-W
+VARIABLE_STEP        0.75
+LENGTHENING_STEP     0
+MIN_SURFAREA         12.557
+MAX_TRIALS           8
+HEAD_TOLERANCE       0.005
+SYS_FLOW_TOL         5
+LAT_FLOW_TOL         5
+MINIMUM_STEP         0.5
+THREADS              1
+
+[EVAPORATION]
+;;Data Source    Parameters
+;;-------------- ----------------
+CONSTANT         0.0
+DRY_ONLY         NO
+
+[JUNCTIONS]
+;;Name           Elevation  MaxDepth   InitDepth  SurDepth   Aponded   
+;;-------------- ---------- ---------- ---------- ---------- ----------
+J1               860        0          0          0          0         
+Outlet           868        0          0          0          0         
+
+[OUTFALLS]
+;;Name           Elevation  Type       Stage Data       Gated    Route To        
+;;-------------- ---------- ---------- ---------------- -------- ----------------
+TailWater        855        FIXED      859.5            NO                       
+
+[STORAGE]
+;;Name           Elev.    MaxDepth   InitDepth  Shape      Curve Name/Params            N/A      Fevap    Psi      Ksat     IMD     
+;;-------------- -------- ---------- ---------- ---------- ---------------------------- -------- --------          -------- --------
+Inlet            878      9          0          TABULAR    StorageCurve               0        0       
+
+[CONDUITS]
+;;Name           From Node        To Node          Length     Roughness  InOffset   OutOffset  InitFlow   MaxFlow   
+;;-------------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ----------
+C1               Outlet           J1               400        0.01       0          0          0          0         
+C2               J1               TailWater        400        0.01       0          0          0          0         
+Culvert          Inlet            Outlet           200        0.014      0          0          0          0         
+
+[WEIRS]
+;;Name           From Node        To Node          Type         CrestHt    Qcoeff     Gated    EndCon   EndCoeff   Surcharge  RoadWidth  RoadSurf   Coeff. Curve
+;;-------------- ---------------- ---------------- ------------ ---------- ---------- -------- -------- ---------- ---------- ---------- ---------- ----------------
+Roadway          Inlet            Outlet           ROADWAY      9          3.33       NO       0        0          NO         40         GRAVEL    
+
+[XSECTIONS]
+;;Link           Shape        Geom1            Geom2      Geom3      Geom4      Barrels    Culvert   
+;;-------------- ------------ ---------------- ---------- ---------- ---------- ---------- ----------
+C1               CIRCULAR     3                0          0          0          1                    
+C2               CIRCULAR     3                0          0          0          1                    
+Culvert          CIRCULAR     3                0          0          0          2          4         
+Roadway          RECT_OPEN    50               200        0          0         
+
+[LOSSES]
+;;Link           Kentry     Kexit      Kavg       Flap Gate  Seepage   
+;;-------------- ---------- ---------- ---------- ---------- ----------
+
+[POLLUTANTS]
+;;Name           Units  Crain      Cgw        Crdii      Kdecay     SnowOnly   Co-Pollutant     Co-Frac    Cdwf       Cinit     
+;;-------------- ------ ---------- ---------- ---------- ---------- ---------- ---------------- ---------- ---------- ----------
+P1               MG/L   0.0        0.0        0.0        0.0        NO         *                0.0        0.0        0.0       
+
+[INFLOWS]
+;;Node           Constituent      Time Series      Type     Mfactor  Sfactor  Baseline Pattern
+;;-------------- ---------------- ---------------- -------- -------- -------- -------- --------
+Inlet            FLOW             ""               FLOW     1.0      1.0      10.0             
+Inlet            P1               ""               CONCENTRATION 1.0      1.0      10.0               
+
+[CURVES]
+;;Name           Type       X-Value    Y-Value   
+;;-------------- ---------- ---------- ----------
+StorageCurve     Storage    0          0         
+StorageCurve                2          9583      
+StorageCurve                4          33977     
+StorageCurve                6          72310     
+StorageCurve                8          136778    
+
+[TIMESERIES]
+;;Name           Date       Time       Value     
+;;-------------- ---------- ---------- ----------
+Inflow                      0          0         
+Inflow                      .125       9         
+Inflow                      .25        10        
+Inflow                      .375       11        
+Inflow                      .5         13        
+Inflow                      .625       17        
+Inflow                      .75        28        
+Inflow                      .875       40        
+Inflow                      1          80        
+Inflow                      1.125      136       
+Inflow                      1.25       190       
+Inflow                      1.375      220       
+Inflow                      1.5        220       
+Inflow                      1.625      201       
+Inflow                      1.75       170       
+Inflow                      1.875      140       
+Inflow                      2          120       
+Inflow                      2.125      98        
+Inflow                      2.25       82        
+Inflow                      2.375      70        
+Inflow                      2.5        60        
+Inflow                      2.625      53        
+Inflow                      2.75       47        
+Inflow                      2.875      41        
+
+[REPORT]
+;;Reporting Options
+INPUT      NO
+CONTROLS   NO
+SUBCATCHMENTS ALL
+NODES ALL
+LINKS ALL
+
+[TAGS]
+
+[MAP]
+DIMENSIONS       1408.9383        6118.83065       6238.6797        7216.52835      
+UNITS            None
+
+[COORDINATES]
+;;Node           X-Coord            Y-Coord           
+;;-------------- ------------------ ------------------
+J1               5131.441           6259.528          
+Outlet           4206.542           6357.994          
+TailWater        6019.146           6168.726          
+Inlet            1628.472           6476.537          
+
+[VERTICES]
+;;Link           X-Coord            Y-Coord           
+;;-------------- ------------------ ------------------
+Roadway          2311.068           7166.633          
+Roadway          3762.491           7151.463          
diff --git a/tests/solver/data/link_flow_dir.inp b/tests/solver/data/link_flow_dir.inp
new file mode 100644
index 000000000..9600b1f51
--- /dev/null
+++ b/tests/solver/data/link_flow_dir.inp
@@ -0,0 +1,103 @@
+[TITLE]
+;;Project Title/Notes
+Example model with positive and negative sloped profiles
+to test that flow direction is accounted for in link flow getter.
+
+[OPTIONS]
+;;Option             Value
+FLOW_UNITS           CFS
+INFILTRATION         HORTON
+FLOW_ROUTING         DYNWAVE
+LINK_OFFSETS         DEPTH
+MIN_SLOPE            0
+ALLOW_PONDING        NO
+SKIP_STEADY_STATE    NO
+
+START_DATE           01/01/2022
+START_TIME           00:00:00
+REPORT_START_DATE    01/01/2022
+REPORT_START_TIME    00:00:00
+END_DATE             01/01/2022
+END_TIME             01:00:00
+SWEEP_START          01/01
+SWEEP_END            12/31
+DRY_DAYS             0
+REPORT_STEP          00:15:00
+WET_STEP             00:05:00
+DRY_STEP             01:00:00
+ROUTING_STEP         0:00:20 
+RULE_STEP            00:00:00
+
+INERTIAL_DAMPING     PARTIAL
+NORMAL_FLOW_LIMITED  BOTH
+FORCE_MAIN_EQUATION  H-W
+VARIABLE_STEP        0.75
+LENGTHENING_STEP     0
+MIN_SURFAREA         12.566
+MAX_TRIALS           8
+HEAD_TOLERANCE       0.005
+SYS_FLOW_TOL         5
+LAT_FLOW_TOL         5
+MINIMUM_STEP         0.5
+THREADS              1
+
+[EVAPORATION]
+;;Data Source    Parameters
+;;-------------- ----------------
+CONSTANT         0.0
+DRY_ONLY         NO
+
+[JUNCTIONS]
+;;Name           Elevation  MaxDepth   InitDepth  SurDepth   Aponded   
+;;-------------- ---------- ---------- ---------- ---------- ----------
+3                3          0          0          100        0         
+4                3          0          0          100        0         
+
+[OUTFALLS]
+;;Name           Elevation  Type       Stage Data       Gated    Route To        
+;;-------------- ---------- ---------- ---------------- -------- ----------------
+1                0          FREE                        NO                       
+2                0          FREE                        NO                       
+
+[CONDUITS]
+;;Name           From Node        To Node          Length     Roughness  InOffset   OutOffset  InitFlow   MaxFlow   
+;;-------------- ---------------- ---------------- ---------- ---------- ---------- ---------- ---------- ----------
+positive         3                1                100        0.013      0          0          0          0         
+negative         2                4                100        0.013      0          0          0          0         
+
+[XSECTIONS]
+;;Link           Shape        Geom1            Geom2      Geom3      Geom4      Barrels    Culvert   
+;;-------------- ------------ ---------------- ---------- ---------- ---------- ---------- ----------
+positive         CIRCULAR     1                0          0          0          1                    
+negative         CIRCULAR     1                0          0          0          1                    
+
+[INFLOWS]
+;;Node           Constituent      Time Series      Type     Mfactor  Sfactor  Baseline Pattern
+;;-------------- ---------------- ---------------- -------- -------- -------- -------- --------
+3                FLOW             ""               FLOW     1.0      1.0      5       
+4                FLOW             ""               FLOW     1.0      1.0      5       
+
+[REPORT]
+;;Reporting Options
+SUBCATCHMENTS ALL
+NODES ALL
+LINKS ALL
+
+[TAGS]
+
+[MAP]
+DIMENSIONS 0.000 0.000 10000.000 10000.000
+Units      None
+
+[COORDINATES]
+;;Node           X-Coord            Y-Coord           
+;;-------------- ------------------ ------------------
+3                1626.773           9202.128          
+4                3701.241           9148.936          
+1                1635.638           7375.887          
+2                3648.050           7304.965          
+
+[VERTICES]
+;;Link           X-Coord            Y-Coord           
+;;-------------- ------------------ ------------------
+
diff --git a/tests/solver/data/node_constantinflow_constanteffluent.inp b/tests/solver/data/node_constantinflow_constanteffluent.inp
new file mode 100644
index 000000000..dd164967c
--- /dev/null
+++ b/tests/solver/data/node_constantinflow_constanteffluent.inp
@@ -0,0 +1,133 @@
+[TITLE]
+;;Project Title/Notes
+
+[OPTIONS]
+;;Option             Value
+FLOW_UNITS           CMS
+INFILTRATION         HORTON
+FLOW_ROUTING         KINWAVE
+LINK_OFFSETS         DEPTH
+MIN_SLOPE            0
+ALLOW_PONDING        NO
+SKIP_STEADY_STATE    NO
+
+START_DATE           01/27/2020
+START_TIME           00:00:00
+REPORT_START_DATE    01/27/2020
+REPORT_START_TIME    00:00:00
+END_DATE             01/27/2020
+END_TIME             00:30:00
+SWEEP_START          01/01
+SWEEP_END            02/28
+DRY_DAYS             0
+REPORT_STEP          00:00:01
+WET_STEP             00:00:01
+DRY_STEP             00:00:01
+ROUTING_STEP         0:00:01 
+
+INERTIAL_DAMPING     PARTIAL
+NORMAL_FLOW_LIMITED  BOTH
+FORCE_MAIN_EQUATION  H-W
+VARIABLE_STEP        0.75
+LENGTHENING_STEP     0
+MIN_SURFAREA         1.14
+MAX_TRIALS           8
+HEAD_TOLERANCE       0.0015
+SYS_FLOW_TOL         5
+LAT_FLOW_TOL         5
+MINIMUM_STEP         0.5
+THREADS              1
+
+[EVAPORATION]
+;;Data Source    Parameters
+;;-------------- ----------------
+CONSTANT         0.0
+DRY_ONLY         NO
+
+[OUTFALLS]
+;;Name           Elevation  Type       Stage Data       Gated    Route To        
+;;-------------- ---------- ---------- ---------------- -------- ----------------
+Outfall          0          FREE                        NO                       
+
+[STORAGE]
+;;Name           Elev.    MaxDepth   InitDepth  Shape      Curve Name/Params            N/A      Fevap    Psi      Ksat     IMD     
+;;-------------- -------- ---------- ----------- ---------- ---------------------------- -------- --------          -------- --------
+Tank             10       5          0          TABULAR    Tank_Curve                   0        0       
+
+[ORIFICES]
+;;Name           From Node        To Node          Type         Offset     Qcoeff     Gated    CloseTime 
+;;-------------- ---------------- ---------------- ------------ ---------- ---------- -------- ----------
+Valve            Tank             Outfall          BOTTOM       0          1          NO       0         
+
+[XSECTIONS]
+;;Link           Shape        Geom1            Geom2      Geom3      Geom4      Barrels    Culvert   
+;;-------------- ------------ ---------------- ---------- ---------- ---------- ---------- ----------
+Valve            RECT_CLOSED  1                1          0          0    
+
+[POLLUTANTS]
+;;Name           Units  Crain      Cgw        Crdii      Kdecay     SnowOnly   Co-Pollutant     Co-Frac    Cdwf       Cinit     
+;;-------------- ------ ---------- ---------- ---------- ---------- ---------- ---------------- ---------- ---------- ----------
+P1               MG/L   0.0        0.0        0          0.0        NO         *                0.0        0.0        0         
+
+
+[INFLOWS]
+;;Node           Constituent      Time Series      Type     Mfactor  Sfactor  Baseline Pattern
+;;-------------- ---------------- ---------------- -------- -------- -------- -------- --------
+Tank             FLOW             ""               FLOW     1.0      1.0      5                
+Tank             P1               ""               CONCENTRATION     1.0      1.0	10                    
+
+[TREATMENT]
+;;Node           Pollutant        Function  
+;;-------------- ---------------- ----------
+Tank             P1               C = 2.0
+
+[CURVES]
+;;Name           Type       X-Value    Y-Value   
+;;-------------- ---------- ---------- ----------
+Tank_Curve       Storage    0          100       
+Tank_Curve                  1          100       
+Tank_Curve                  2          100       
+Tank_Curve                  3          100       
+Tank_Curve                  4          100       
+Tank_Curve                  5          100       
+
+[TIMESERIES]
+;;Name           Date       Time       Value     
+;;-------------- ---------- ---------- ----------
+TestRain                    1          0         
+TestRain                    2          0.5       
+TestRain                    3          0.75      
+TestRain                    4          1         
+TestRain                    5          0.75      
+TestRain                    6          0.5       
+TestRain                    7          0         
+
+[PATTERNS]
+;;Name           Type       Multipliers
+;;-------------- ---------- -----------
+DailyX1          DAILY      1.0   1.0   1.0   1.0   1.0   1.0   1.0  
+
+[REPORT]
+;;Reporting Options
+INPUT      NO
+CONTROLS   NO
+SUBCATCHMENTS ALL
+NODES ALL
+LINKS ALL
+
+[TAGS]
+
+[MAP]
+DIMENSIONS 0.000 0.000 10000.000 10000.000
+Units      None
+
+[COORDINATES]
+;;Node           X-Coord            Y-Coord           
+;;-------------- ------------------ ------------------
+Outfall          -178.777           6435.986          
+Tank             -1101.499          6828.143          
+
+[VERTICES]
+;;Link           X-Coord            Y-Coord           
+;;-------------- ------------------ ------------------
+
diff --git a/tests/solver/test_lid.hpp b/tests/solver/test_lid.hpp
index baa5986f9..a5c690557 100644
--- a/tests/solver/test_lid.hpp
+++ b/tests/solver/test_lid.hpp
@@ -18,8 +18,10 @@
 
 #include <vector>
 
+extern "C" {
 #include "swmm5.h"
 #include "toolkit.h"
+}
 
 #define ERR_NONE 0
 
diff --git a/tests/solver/test_pollut.cpp b/tests/solver/test_pollut.cpp
index c6cabed90..e1c978f95 100644
--- a/tests/solver/test_pollut.cpp
+++ b/tests/solver/test_pollut.cpp
@@ -60,6 +60,8 @@ BOOST_FIXTURE_TEST_CASE(get_pollut_values, FixtureBeforeStep){
         {
             // subcatchment buildup
             error = swmm_getSubcatchPollut(subc_ind, SM_BUILDUP, &buildup_array, &length);
+            // Check length is set correctly
+            BOOST_CHECK(length == 2);
             BOOST_REQUIRE(error == ERR_NONE);
             BOOST_CHECK_SMALL(buildup_array[TSS] - 31.906912, 0.0001);
             BOOST_CHECK_SMALL(buildup_array[Lead] - 0.0, 0.0001);
@@ -148,5 +150,341 @@ BOOST_FIXTURE_TEST_CASE(get_pollut_values, FixtureBeforeStep){
     swmm_end();
 }
 
+// Testing Node influent concentration- storage assets
+BOOST_FIXTURE_TEST_CASE(get_node_pollutant_values_cin, FixtureBeforeStep_Pollut_Node){
+
+    int error, step_ind;
+    double* node_qual;
+    double elapsedTime = 0.0;
+    double total_pollutant = 0.0;
+    int length;
+
+    // Pollutant IDs
+    int P1 = 0;
+    double cin = 10;
+
+    step_ind = 0;
+    do
+    {
+       
+    // Get inflow concentration
+	error = swmm_getNodePollut(1, SM_NODECIN, &node_qual, &length);
+    // Check length is set correctly
+    BOOST_CHECK(length == 1);
+	BOOST_REQUIRE(error == ERR_NONE);
+
+	// Check for constant influent
+	if (step_ind > 5)
+        BOOST_CHECK_CLOSE(cin, node_qual[P1], 0.001);
+
+	// Route Model Forward
+        error = swmm_step(&elapsedTime);
+        step_ind+=1;
+
+    }while (elapsedTime != 0 && !error);
+    BOOST_REQUIRE(error == ERR_NONE);
+
+    swmm_end();
+}
+
+// Testing Reactor Concentration in Node
+BOOST_FIXTURE_TEST_CASE(get_node_reactor_pollutant, FixtureBeforeStep_Pollut_Node){
+
+    int error, step_ind;
+    double* old_qual;
+    double* new_qual;
+    double elapsedTime = 0.0;
+    double total_pollutant = 0.0;
+    int length;
+
+    // Pollutant IDs
+    int P1 = 0;
+
+    step_ind = 0;
+    do
+    {
+    // Check for steady state after 1000 steps.
+	// 1000 is a aribitarly long time duration, it can be any value as long
+	// the system reaches a steady state
+
+	// Get reactor concentration
+	error = swmm_getNodePollut(1, SM_NODEREACTORC, &new_qual, &length);
+    // Check length is set correctly
+    BOOST_CHECK(length == 1);
+	BOOST_REQUIRE(error == ERR_NONE);
+
+	if (step_ind > 1000)
+	{
+		BOOST_CHECK_CLOSE(old_qual[P1], new_qual[P1], 0.001);
+	}
+
+	old_qual = new_qual;
+
+        // Route Model Forward
+        error = swmm_step(&elapsedTime);
+        step_ind+=1;
+    }while (elapsedTime != 0 && !error);
+    BOOST_REQUIRE(error == ERR_NONE);
+    swmm_end();
+}
+
+// Testing Reactor Concentration in Link
+BOOST_FIXTURE_TEST_CASE(get_link_reactor_pollutant, FixtureBeforeStep_Pollut_Link){
+
+    int error, step_ind;
+    double* old_qual;
+    double* new_qual;
+    double elapsedTime = 0.0;
+    double total_pollutant = 0.0;
+    int length;
+
+    // Pollutant IDs
+    int P1 = 0;
+
+    step_ind = 0;
+    do
+    {
+    // Check for steady state after 1000 steps.
+    // 1000 is a aribitarly long time duration, it can be any value as long
+    // the system reaches a steady state
+
+    // Get reactor concentration
+    error = swmm_getLinkPollut(1, SM_LINKREACTORC, &new_qual, &length);
+    // Check length is set correctly
+    BOOST_CHECK(length == 1);
+    BOOST_REQUIRE(error == ERR_NONE);
+
+    if (step_ind > 1500)
+    {
+        BOOST_CHECK_CLOSE(old_qual[P1], new_qual[P1], 0.001);
+    }
+
+    old_qual = new_qual;
+
+        // Route Model Forward
+        error = swmm_step(&elapsedTime);
+        step_ind+=1;
+    }while (elapsedTime != 0 && !error);
+    BOOST_REQUIRE(error == ERR_NONE);
+    swmm_end();
+}
+
+// Testing Pollutant Setter - Node - Cumulative and mass balance
+BOOST_FIXTURE_TEST_CASE(set_node_pollutant_cumulative_values, FixtureBeforeStep_Pollut_Node){
+
+    int error;
+    double* node_qual;
+    float runoff_error, flow_error, qual_error;
+    double elapsedTime = 0.0;
+    double total_pollutant = 0.0;
+    int length;
+
+    // Pollutant IDs
+    int P1 = 0;
+
+    do
+    {
+	// Set pollutant
+	error = swmm_setNodePollut(1, SM_NODEQUAL, P1, 0);
+	BOOST_REQUIRE(error == ERR_NONE);
+        // Route Model Forward
+        error = swmm_step(&elapsedTime);
+	// Get pollutant
+	error = swmm_getNodePollut(1, SM_NODEQUAL, &node_qual, &length);
+	BOOST_REQUIRE(error == ERR_NONE);
+	// Record cumulative pollutant
+	total_pollutant = total_pollutant + node_qual[P1];
+
+    }while (elapsedTime != 0 && !error);
+    BOOST_REQUIRE(error == ERR_NONE);
+
+    // Cumulative must be 0.00
+    BOOST_CHECK_SMALL(total_pollutant, 1.0e-06);
+    swmm_end();
+    // check mass balance error less than 5%
+    swmm_getMassBalErr(&runoff_error, &flow_error, &qual_error);
+    BOOST_CHECK(abs(qual_error) <= 1.0);
+}
+
+// Testing Pollutant Setter - Node - Stepwise and Mass balance less than inflow concentration of 10
+BOOST_FIXTURE_TEST_CASE(set_node_pollutant_stepwise_values, FixtureBeforeStep_Pollut_Node){
+
+    int error;
+    double* node_qual;
+    float runoff_error, flow_error, qual_error;
+    double elapsedTime = 0.0;
+    int length;
+
+    // Pollutant IDs
+    int P1 = 0;
+    do
+    {
+	// Set pollutant
+	error = swmm_setNodePollut(1, SM_NODEQUAL, P1, 1.234);
+	BOOST_REQUIRE(error == ERR_NONE);
+
+	// Route Model Forward
+        error = swmm_step(&elapsedTime);
+
+	// Get pollutant
+	error = swmm_getNodePollut(1, SM_NODEQUAL, &node_qual, &length);
+	BOOST_REQUIRE(error == ERR_NONE);
+
+	// Check
+    	BOOST_CHECK_CLOSE(node_qual[P1], 1.234, 0.001);
+
+    }while (elapsedTime != 0 && !error);
+    BOOST_REQUIRE(error == ERR_NONE);
+    swmm_end();
+
+    // check mass balance error less than 1%
+    swmm_getMassBalErr(&runoff_error, &flow_error, &qual_error);
+    BOOST_CHECK(abs(qual_error) <= 1.0);
+}
+
+
+// Testing Pollutant Setter - Node - Stepwise and Mass balance greater than inflow concentration of 10
+BOOST_FIXTURE_TEST_CASE(set_node_pollutant_stepwise_values_2, FixtureBeforeStep_Pollut_Node){
+
+    int error;
+    double* node_qual;
+    float runoff_error, flow_error, qual_error;
+    double elapsedTime = 0.0;
+    int length;
+
+    // Pollutant IDs
+    int P1 = 0;
+    do
+    {
+	// Set pollutant
+	error = swmm_setNodePollut(1, SM_NODEQUAL, P1, 50.0);
+	BOOST_REQUIRE(error == ERR_NONE);
+
+	// Route Model Forward
+        error = swmm_step(&elapsedTime);
+
+	// Get pollutant
+	error = swmm_getNodePollut(1, SM_NODEQUAL, &node_qual, &length);
+	BOOST_REQUIRE(error == ERR_NONE);
+
+	// Check
+    	BOOST_CHECK_CLOSE(node_qual[P1], 50.0, 0.001);
+
+    }while (elapsedTime != 0 && !error);
+    BOOST_REQUIRE(error == ERR_NONE);
+    swmm_end();
+
+    // check mass balance error less than 1%
+    swmm_getMassBalErr(&runoff_error, &flow_error, &qual_error);
+    BOOST_CHECK(abs(qual_error) <= 1.0);
+}
+
+
+
+// Testing Pollutant Setter - Link - Stepwise - mass balance concentation less than 10
+BOOST_FIXTURE_TEST_CASE(set_link_pollutant_stepwise_values, FixtureBeforeStep_Pollut_Link){
+
+    int error, link_ind, node_ind;
+    int step = 0;
+    double* link_qual;
+    double* node_qual;
+    double elapsedTime = 0.0;
+    double node_inflow;
+    float runoff_error, flow_error, qual_error;
+    char linkid[] = "C1";
+    char nodeid[] = "J1";
+    int length;
+
+    // Pollutant ID
+    int P1 = 0;
+
+    error = swmm_getObjectIndex(SM_LINK, linkid, &link_ind);
+    BOOST_REQUIRE(error == ERR_NONE);
+    error = swmm_getObjectIndex(SM_NODE, nodeid, &node_ind);
+    BOOST_REQUIRE(error == ERR_NONE);
+
+    do{	    
+	    if (step > 1000 && step < 2000){
+	    	// Set pollutant in link and check the pollutant in the node
+	    	error = swmm_setLinkPollut(link_ind, SM_LINKQUAL, P1, 1.0);
+	    	BOOST_REQUIRE(error == ERR_NONE);
+	    }
+	    // Route Model Forward
+            error = swmm_step(&elapsedTime);
+	    BOOST_REQUIRE(error == ERR_NONE);
+	    if (step > 1500 && step < 2000) // Wait for water to reach node
+            {
+	    // Get infows concentration in node
+            error = swmm_getNodePollut(node_ind,  SM_NODEQUAL, &node_qual, &length);
+	    BOOST_REQUIRE(error == ERR_NONE);
+
+	    error = swmm_getLinkPollut(link_ind, SM_LINKQUAL, &link_qual, &length);
+
+	    // Check
+            BOOST_CHECK_CLOSE(node_qual[P1], link_qual[P1], 0.01);
+    	    }step += 1;
+
+    }while (elapsedTime != 0 && !error);
+    BOOST_REQUIRE(error == ERR_NONE);
+    swmm_end();
+
+    // check mass balance error less than 5%
+    swmm_getMassBalErr(&runoff_error, &flow_error, &qual_error);
+    BOOST_CHECK(abs(qual_error) <= 5.0);
+}
+
+
+// Testing Pollutant Setter - Link - Stepwise - mass balance concentation greater than 10
+BOOST_FIXTURE_TEST_CASE(set_link_pollutant_stepwise_values_2, FixtureBeforeStep_Pollut_Link){
+
+    int error, link_ind, node_ind;
+    int step = 0;
+    double* link_qual;
+    double* node_qual;
+    double elapsedTime = 0.0;
+    double node_inflow;
+    float runoff_error, flow_error, qual_error;
+    char linkid[] = "C1";
+    char nodeid[] = "J1";
+    int length;
+
+    // Pollutant ID
+    int P1 = 0;
+
+    error = swmm_getObjectIndex(SM_LINK, linkid, &link_ind);
+    BOOST_REQUIRE(error == ERR_NONE);
+    error = swmm_getObjectIndex(SM_NODE, nodeid, &node_ind);
+    BOOST_REQUIRE(error == ERR_NONE);
+
+    do{	    
+	    if (step > 1000 & step < 2000){
+	    	// Set pollutant in link and check the pollutant in the node
+	    	error = swmm_setLinkPollut(link_ind, SM_LINKQUAL, P1, 20.0);
+	    	BOOST_REQUIRE(error == ERR_NONE);
+	    }
+	    // Route Model Forward
+            error = swmm_step(&elapsedTime);
+	    BOOST_REQUIRE(error == ERR_NONE);
+
+	     // Wait for water to reach node
+	    if (step > 1500 & step < 2000){
+	    // Get infows concentration in node
+            error = swmm_getNodePollut(node_ind,  SM_NODEQUAL, &node_qual, &length);
+	    BOOST_REQUIRE(error == ERR_NONE);
+
+	    error = swmm_getLinkPollut(link_ind, SM_LINKQUAL, &link_qual, &length);
+
+	    // Check
+            BOOST_CHECK_CLOSE(node_qual[P1], link_qual[P1], 0.01);
+    	    }step += 1;
+
+    }while (elapsedTime != 0 && !error);
+    BOOST_REQUIRE(error == ERR_NONE);
+    swmm_end();
+
+    swmm_getMassBalErr(&runoff_error, &flow_error, &qual_error);
+    BOOST_CHECK(abs(qual_error) <= 5.0);
+}
+
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/solver/test_solver.hpp b/tests/solver/test_solver.hpp
index 1d52b21dc..c2617ae9b 100644
--- a/tests/solver/test_solver.hpp
+++ b/tests/solver/test_solver.hpp
@@ -14,12 +14,16 @@
 #ifndef TEST_SOLVER_HPP
 #define TEST_SOLVER_HPP
 
+extern "C" {
 #include "swmm5.h"
 #include "toolkit.h"
-
+}
 
 // Add shared data paths here
 #define DATA_PATH_INP "test_example1.inp"
+#define DATA_PATH_INP_POLLUT_NODE "node_constantinflow_constanteffluent.inp"
+#define DATA_PATH_INP_POLLUT_LINK "link_constantinflow.inp"
+#define DATA_PATH_INP_LINK_DIR "link_flow_dir.inp"
 #define DATA_PATH_RPT "tmp.rpt"
 #define DATA_PATH_OUT "tmp.out"
 
@@ -68,6 +72,37 @@ struct FixtureBeforeEnd{
     }
 };
 
+struct FixtureBeforeStep_Pollut_Node{
+    FixtureBeforeStep_Pollut_Node() {
+        swmm_open(DATA_PATH_INP_POLLUT_NODE, DATA_PATH_RPT, DATA_PATH_OUT);
+        swmm_start(0);
+    }
+    ~FixtureBeforeStep_Pollut_Node() {
+        swmm_close();
+    }
+};
+
+struct FixtureBeforeStep_Pollut_Link{
+    FixtureBeforeStep_Pollut_Link() {
+        swmm_open(DATA_PATH_INP_POLLUT_LINK, DATA_PATH_RPT, DATA_PATH_OUT);
+        swmm_start(0);
+    }
+    ~FixtureBeforeStep_Pollut_Link() {
+        swmm_close();
+    }
+};
+
+struct FixtureBeforeStep_Flow_Dir{
+    FixtureBeforeStep_Flow_Dir() {
+        swmm_open(DATA_PATH_INP_LINK_DIR, DATA_PATH_RPT, DATA_PATH_OUT);
+        swmm_start(0);
+    }
+    ~FixtureBeforeStep_Flow_Dir() {
+        swmm_close();
+    }
+};
+
+
 // Declare shared test predicates here
 boost::test_tools::predicate_result check_cdd_double(std::vector<double>& test,
     std::vector<double>& ref, long cdd_tol);
diff --git a/tests/solver/test_toolkit.cpp b/tests/solver/test_toolkit.cpp
index 0ed1f013e..6ffd015c6 100644
--- a/tests/solver/test_toolkit.cpp
+++ b/tests/solver/test_toolkit.cpp
@@ -946,7 +946,43 @@ BOOST_FIXTURE_TEST_CASE(get_result_during_sim, FixtureBeforeStep){
     swmm_end();
 }
 
+// Testing link flow direction is accounted for in link result getter
+BOOST_FIXTURE_TEST_CASE(test_flow_dir_during_sim, FixtureBeforeStep_Flow_Dir){
+    int error, step_ind;
+    int neg_lnk_ind, pos_lnk_ind;
+    double val;
+    double elapsedTime = 0.0;
+
+    char neglnkid[] = "negative";
+    char poslnkid[] = "positive";
+
+    error = swmm_getObjectIndex(SM_LINK, poslnkid, &pos_lnk_ind);
+    BOOST_REQUIRE(error == ERR_NONE);
 
+    error = swmm_getObjectIndex(SM_LINK, neglnkid, &neg_lnk_ind);
+    BOOST_REQUIRE(error == ERR_NONE);
+
+    step_ind = 0;
+
+    do
+    {
+        error = swmm_step(&elapsedTime);
+
+        if (step_ind == 200) // (Jan 1, 1998 3:20am)
+        {
+            error = swmm_getLinkResult(pos_lnk_ind, SM_LINKFLOW, &val);
+            BOOST_REQUIRE(error == ERR_NONE);
+            BOOST_CHECK_CLOSE(val,5.0,0.001);
+
+            error = swmm_getLinkResult(neg_lnk_ind, SM_LINKFLOW, &val);
+            BOOST_REQUIRE(error == ERR_NONE);
+            BOOST_CHECK_CLOSE(val,-5.0,0.001);
+        }
+        step_ind+=1;
+    }while (elapsedTime != 0 && !error);
+    BOOST_REQUIRE(error == ERR_NONE);
+    swmm_end();
+}
 // Testing Results Getters (Before End Simulation)
 // BOOST_FIXTURE_TEST_CASE(get_results_after_sim, FixtureBeforeEnd){
 //     int error;