From cdcb4d1732878f943b694c1fe9d15d19f9852e82 Mon Sep 17 00:00:00 2001 From: Katherine Klise Date: Fri, 10 Nov 2023 12:12:55 -0800 Subject: [PATCH] MSX docs update (#135) * Add scheduled testing to workflow * MSX documentation update * minor updates --------- Co-authored-by: Kirk Bonney <47759761+kbonney@users.noreply.github.com> --- .github/workflows/build_tests.yml | 2 + documentation/advancedsim.rst | 359 +++++++++++++++++++++++++++++ documentation/conf.py | 2 +- documentation/hydraulics.rst | 3 +- documentation/index.rst | 2 +- documentation/reference.rst | 4 + documentation/waterquality.rst | 12 +- documentation/waterquality_msx.rst | 93 ++++++++ 8 files changed, 471 insertions(+), 6 deletions(-) create mode 100644 documentation/waterquality_msx.rst diff --git a/.github/workflows/build_tests.yml b/.github/workflows/build_tests.yml index 06c3ce6a1..21509c083 100644 --- a/.github/workflows/build_tests.yml +++ b/.github/workflows/build_tests.yml @@ -8,6 +8,8 @@ on: branches: [ main, dev ] pull_request: branches: [ main, dev ] + schedule: + - cron: '0 0 1 * *' jobs: diff --git a/documentation/advancedsim.rst b/documentation/advancedsim.rst index 4a8be4fe7..1944c9c70 100644 --- a/documentation/advancedsim.rst +++ b/documentation/advancedsim.rst @@ -248,3 +248,362 @@ The solution for :math:`u` and :math:`v` is then returned and printed to four si 1.618 >>> np.round(m.v.value,4) 2.618 + +Building MSX models +------------------- + +The following two examples illustrate how to build :class:`~wntr.msx.model.MsxModel` objects in WNTR + +.. _msx_example1_lead: + +Plumbosolvency of lead +^^^^^^^^^^^^^^^^^^^^^^ + +The following example builds the plumbosolvency of lead model +described in [BWMS20]_. The model represents plumbosolvency +in lead pipes within a dwelling. +The MSX model is built without a specific water network model in mind. + +Model development starts by defining the model +name, +title, +description, and +reference. + +.. doctest:: + + >>> import wntr.msx + >>> msx = wntr.msx.MsxModel() + >>> msx.name = "lead_ppm" + >>> msx.title = "Lead Plumbosolvency Model (from Burkhardt et al 2020)" + >>> msx.desc = "Parameters for EPA HPS Simulator Model" + >>> msx.references.append( + ... """J. B. Burkhardt, et al. (2020) https://doi.org/10.1061/(asce)wr.1943-5452.0001304""" + ... ) + >>> msx + MultispeciesQualityModel(name='lead_ppm') + +Model options are added as follows: + +.. doctest:: + + >>> msx.options = { + ... "report": { + ... "species": {"PB2": "YES"}, + ... "species_precision": {"PB2": 5}, + ... "nodes": "all", + ... "links": "all", + ... }, + ... "timestep": 1, + ... "area_units": "M2", + ... "rate_units": "SEC", + ... "rtol": 1e-08, + ... "atol": 1e-08, + ... } + +There is only one species defined in this model, which is dissolved lead. + +======================== =============== ================================= ======================== +Name Type Units Note +------------------------ --------------- --------------------------------- ------------------------ +:math:`Pb` bulk species :math:`\mathrm{μg}_\mathrm{(Pb)}` dissolved lead +======================== =============== ================================= ======================== + +The species is added to the MsxModel using the using the +:meth:`~wntr.msx.model.MsxModel.add_species` method. +This method adds the new species to the model and also return a copy of the new species object. + +.. doctest:: + + >>> msx.add_species(name="PB2", species_type='bulk', units="ug", note="dissolved lead (Pb)") + Species(name='PB2', species_type=, units='ug', atol=None, rtol=None, note='dissolved lead (Pb)') + +The new species can be accessed by using the item's name and indexing on the model's +:attr:`~wntr.msx.model.MsxModel.reaction_system` attribute. + + >>> PB2 = msx.reaction_system['PB2'] + >>> PB2 + Species(name='PB2', species_type=, units='ug', atol=None, rtol=None, note='dissolved lead (Pb)') + +The model also includes two constants and one parameter. + +=============== =============== =============== ================================= ======================== +Type Name Value Units Note +--------------- --------------- --------------- --------------------------------- ------------------------ +constant :math:`M` 0.117 :math:`\mathrm{μg~m^{-2}~s^{-1}}` desorption rate +constant :math:`E` 140.0 :math:`\mathrm{μg~L^{-1}}` saturation level +parameter :math:`F` 0 `n/a` is pipe made of lead? +=============== =============== =============== ================================= ======================== + +These are added to the MsxModel using the using the +:meth:`~wntr.msx.model.MsxModel.add_constant` and +:meth:`~wntr.msx.model.MsxModel.add_parameter` methods. +methods. + +.. doctest:: + + >>> msx.add_constant("M", value=0.117, note="Desorption rate (ug/m^2/s)", units="ug * m^(-2) * s^(-1)") + >>> msx.add_constant("E", value=140.0, note="saturation/plumbosolvency level (ug/L)", units="ug/L") + >>> msx.add_parameter("F", global_value=0, note="determines which pipes have reactions") + +Note that all models must include both pipe and tank reactions. +Since the model only has reactions within +pipes, tank reactions need to be unchanging. +The system of equations defined as follows: + +.. math:: + + \frac{d}{dt}Pb_p &= F_p \, Av_p \, M \frac{\left( E - Pb_p \right)}{E}, &\quad\text{for all pipes}~p~\text{in network} \\ + \frac{d}{dt}Pb_t &= 0, & \quad\text{for all tanks}~t~\text{in network} + +Note that the pipe reaction has a variable that has not been defined, :math:`Av`; +this variable is a pre-defined hydraulic variable. The list of these variables can be found in +the EPANET-MSX documentation, and also in the :attr:`~wntr.msx.base.HYDRAULIC_VARIABLES` +documentation. The reactions are defined as follows: + +================ ============== ========================================================================== +Reaction type Dynamics type Reaction expression +---------------- -------------- -------------------------------------------------------------------------- +pipe rate :math:`F \cdot Av \cdot M \cdot \left( E - Pb \right) / E` +tank rate :math:`0` +================ ============== ========================================================================== + +The reactions are added to the MsxModel using the :meth:`~wntr.msx.model.MsxModel.add_reaction` +method. + +.. doctest:: + + >>> msx.add_reaction("PB2", "pipe", "RATE", expression="F * Av * M * (E - PB2) / E") + >>> msx.add_reaction(PB2, "tank", "rate", expression="0") + +Arsenic oxidation and adsorption +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This example models monochloramine oxidation of arsenite/arsenate and wall +adsorption/desorption, as given in section 3 of the EPANET-MSX user manual [SRU23]_. + +The system of equations for the reaction in pipes is given in Eq. (2.4) through (2.7) +in [SRU23]_. This is a simplified model, taken from [GSCL94]_. + +.. math:: + + \frac{d}{dt}{(\mathsf{As}^\mathrm{III})} &= -k_a ~ {(\mathsf{As}^\mathrm{III})} ~ {(\mathsf{NH_2Cl})} \\ + \frac{d}{dt}{(\mathsf{As}^\mathrm{V})} &= k_a ~ {(\mathsf{As}^\mathrm{III})} ~ {(\mathsf{NH_2CL})} - Av \left( k_1 \left(S_\max - {(\mathsf{As}^\mathrm{V}_s)} \right) {(\mathsf{As}^\mathrm{V})} - k_2 ~ {(\mathsf{As}^\mathrm{V}_s)} \right) \\ + \frac{d}{dt}{(\mathsf{NH_2Cl})} &= -k_b ~ {(\mathsf{NH_2Cl})} \\ + {(\mathsf{As}^\mathrm{V}_s)} &= \frac{k_s ~ S_\max ~ {(\mathsf{As}^\mathrm{V})}}{1 + k_s {(\mathsf{As}^\mathrm{V})}} + + +where the various species, coefficients, and expressions are described in the tables below. + + +.. list-table:: Options + :header-rows: 1 + :widths: 3 3 10 + + * - Option + - Code + - Description + * - Rate units + - "HR" + - :math:`\mathrm{h}^{-1}` + * - Area units + - "M2" + - :math:`\mathrm{m}^2` + + +.. list-table:: Species + :header-rows: 1 + :widths: 2 2 2 3 4 6 + + * - Name + - Type + - Value + - Symbol + - Units + - Note + * - AS3 + - Bulk + - "UG" + - :math:`{\mathsf{As}^\mathrm{III}}` + - :math:`\require{upgreek}\upmu\mathrm{g~L^{-1}}` + - dissolved arsenite + * - AS5 + - Bulk + - "UG" + - :math:`{\mathsf{As}^\mathrm{V}}` + - :math:`\require{upgreek}\upmu\mathrm{g~L^{-1}}` + - dissolved arsenate + * - AStot + - Bulk + - "UG" + - :math:`{\mathsf{As}^\mathrm{tot}}` + - :math:`\require{upgreek}\upmu\mathrm{g~L^{-1}}` + - dissolved arsenic (total) + * - NH2CL + - Bulk + - "MG" + - :math:`{\mathsf{NH_2Cl}}` + - :math:`\mathrm{mg~L^{-1}}` + - dissolved monochloramine + * - AS5s + - Wall + - "UG" + - :math:`{\mathsf{As}^\mathrm{V}_{s}}` + - :math:`\require{upgreek}\upmu\mathrm{g}~\mathrm{m}^{-2}` + - adsorped arsenate (surface) + + +.. list-table:: Coefficients + :header-rows: 1 + :widths: 2 2 2 3 4 6 + + * - Name + - Type + - Value + - Symbol + - Units + - Note + * - Ka + - Const + - :math:`10` + - :math:`k_a` + - :math:`\mathrm{mg}^{-1}_{\left(\mathsf{NH_2Cl}\right)}~\mathrm{h}^{-1}` + - arsenite oxidation + * - Kb + - Const + - :math:`0.1` + - :math:`k_b` + - :math:`\mathrm{h}^{-1}` + - chloromine decay + * - K1 + - Const + - :math:`5.0` + - :math:`k_1` + - :math:`\require{upgreek}\textrm{L}~\upmu\mathrm{g}^{-1}_{\left(\mathsf{As}^\mathrm{V}\right)}~\mathrm{h}^{-1}` + - arsenate adsorption + * - K2 + - Const + - :math:`1.0` + - :math:`k_2` + - :math:`\textrm{L}~\mathrm{h}^{-1}` + - arsenate desorption + * - Smax + - Const + - :math:`50.0` + - :math:`S_{\max}` + - :math:`\require{upgreek}\upmu\mathrm{g}_{\left(\mathsf{As}^\mathrm{V}\right)}~\mathrm{m}^{-2}` + - arsenate adsorption limit + + +.. list-table:: Other terms + :header-rows: 1 + :widths: 3 3 2 3 10 + + * - Name + - Symbol + - Expression + - Units + - Note + * - Ks + - :math:`k_s` + - :math:`{k_1}/{k_2}` + - :math:`\require{upgreek}\upmu\mathrm{g}^{-1}_{\left(\mathsf{As}^\mathrm{V}\right)}` + - equilibrium adsorption coefficient + + +.. list-table:: Pipe reactions + :header-rows: 1 + :widths: 3 3 16 + + * - Species + - Type + - Expression + * - AS3 + - Rate + - :math:`-k_a \, {\mathsf{As}^\mathrm{III}} \, {\mathsf{NH_2Cl}}` + * - AS5 + - Rate + - :math:`k_a \, {\mathsf{As}^\mathrm{III}} \, {\mathsf{NH_2Cl}} -Av \left( k_1 \left(S_{\max}-{\mathsf{As}^\mathrm{V}_{s}} \right) {\mathsf{As}^\mathrm{V}} - k_2 \, {\mathsf{As}^\mathrm{V}_{s}} \right)` + * - NH2CL + - Rate + - :math:`-k_b \, {\mathsf{NH_2Cl}}` + * - AStot + - Formula + - :math:`{\mathsf{As}^\mathrm{III}} + {\mathsf{As}^\mathrm{V}}` + * - AS5s + - Equil + - :math:`k_s \, S_{\max} \frac{{\mathsf{As}^\mathrm{V}}}{1 + k_s \, {\mathsf{As}^\mathrm{V}}} - {\mathsf{As}^\mathrm{V}_{s}}` + + +.. list-table:: Tank reactions + :header-rows: 1 + :widths: 3 3 16 + + * - Species + - Type + - Expression + * - AS3 + - Rate + - :math:`-k_a \, {\mathsf{As}^\mathrm{III}} \, {\mathsf{NH_2Cl}}` + * - AS5 + - Rate + - :math:`k_a \, {\mathsf{As}^\mathrm{III}} \, {\mathsf{NH_2Cl}}` + * - NH2CL + - Rate + - :math:`-k_b \, {\mathsf{NH_2Cl}}` + * - AStot + - Formula + - :math:`{\mathsf{As}^\mathrm{III}} + {\mathsf{As}^\mathrm{V}}` + * - AS5s + - Equil + - :math:`0` (`not present in tanks`) + + +The model is created in WTNR as shown below. + +.. doctest:: + + >>> msx = wntr.msx.MsxModel() + >>> msx.name = "arsenic_chloramine" + >>> msx.title = "Arsenic Oxidation/Adsorption Example" + >>> msx.references.append(wntr.msx.library.cite_msx()) + + >>> AS3 = msx.add_species(name="AS3", species_type="BULK", units="UG", note="Dissolved arsenite") + >>> AS5 = msx.add_species(name="AS5", species_type="BULK", units="UG", note="Dissolved arsenate") + >>> AStot = msx.add_species(name="AStot", species_type="BULK", units="UG", + ... note="Total dissolved arsenic") + >>> AS5s = msx.add_species(name="AS5s", species_type="WALL", units="UG", note="Adsorbed arsenate") + >>> NH2CL = msx.add_species(name="NH2CL", species_type="BULK", units="MG", note="Monochloramine") + + >>> Ka = msx.add_constant("Ka", 10.0, units="1 / (MG * HR)", note="Arsenite oxidation rate coeff") + >>> Kb = msx.add_constant("Kb", 0.1, units="1 / HR", note="Monochloramine decay rate coeff") + >>> K1 = msx.add_constant("K1", 5.0, units="M^3 / (UG * HR)", note="Arsenate adsorption coeff") + >>> K2 = msx.add_constant("K2", 1.0, units="1 / HR", note="Arsenate desorption coeff") + >>> Smax = msx.add_constant("Smax", 50.0, units="UG / M^2", note="Arsenate adsorption limit") + + >>> Ks = msx.add_term(name="Ks", expression="K1/K2", note="Equil. adsorption coeff") + + >>> _ = msx.add_reaction(species_name="AS3", reaction_type="pipes", expression_type="rate", + ... expression="-Ka*AS3*NH2CL", note="Arsenite oxidation") + >>> _ = msx.add_reaction("AS5", "pipes", "rate", "Ka*AS3*NH2CL - Av*(K1*(Smax-AS5s)*AS5 - K2*AS5s)", + ... note="Arsenate production less adsorption") + >>> _ = msx.add_reaction( + ... species_name="NH2CL", reaction_type="pipes", expression_type="rate", expression="-Kb*NH2CL", + ... note="Monochloramine decay") + >>> _ = msx.add_reaction("AS5s", "pipe", "equil", "Ks*Smax*AS5/(1+Ks*AS5) - AS5s", + ... note="Arsenate adsorption") + >>> _ = msx.add_reaction(species_name="AStot", reaction_type="pipes", expression_type="formula", + ... expression="AS3 + AS5", note="Total arsenic") + >>> _ = msx.add_reaction(species_name="AS3", reaction_type="tank", expression_type="rate", + ... expression="-Ka*AS3*NH2CL", note="Arsenite oxidation") + >>> _ = msx.add_reaction(species_name="AS5", reaction_type="tank", expression_type="rate", + ... expression="Ka*AS3*NH2CL", note="Arsenate production") + >>> _ = msx.add_reaction(species_name="NH2CL", reaction_type="tank", expression_type="rate", + ... expression="-Kb*NH2CL", note="Monochloramine decay") + >>> _ = msx.add_reaction(species_name="AStot", reaction_type="tanks", expression_type="formula", + ... expression="AS3 + AS5", note="Total arsenic") + + >>> msx.options.area_units = "M2" + >>> msx.options.rate_units = "HR" + >>> msx.options.rtol = 0.001 + >>> msx.options.atol = 0.0001 diff --git a/documentation/conf.py b/documentation/conf.py index f9eef5dfc..d45b8e778 100644 --- a/documentation/conf.py +++ b/documentation/conf.py @@ -108,7 +108,7 @@ # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True -autodoc_type_aliases = {'DataFrame': 'pandas DataFrame', 'MsxVariable': ':class:`~wntr.msx.model.MsxVariable`', 'NoteType': ':class:`~wntr.epanet.util.NoteType`'} +#autodoc_type_aliases = {'DataFrame': 'pandas DataFrame', 'MsxVariable': ':class:`~wntr.msx.model.MsxVariable`', 'NoteType': ':class:`~wntr.epanet.util.NoteType`'} # If true, the current module name will be prepended to all description # unit titles (such as .. function::). diff --git a/documentation/hydraulics.rst b/documentation/hydraulics.rst index 0c755bda5..f284024b7 100644 --- a/documentation/hydraulics.rst +++ b/documentation/hydraulics.rst @@ -9,10 +9,11 @@ Hydraulic simulation WNTR contains two simulators: the EpanetSimulator and the WNTRSimulator. See :ref:`software_framework` for more information on features and limitations of these simulators. +Additional hydraulic simulation options are discussed in :ref:`advanced_simulation`. EpanetSimulator ----------------- -The EpanetSimulator can be used to run EPANET 2.00.12 Programmer's Toolkit [Ross00]_ or EPANET 2.2.0 Programmer's Toolkit [RWTS20]_. +The EpanetSimulator can be used to run a hydraulic simulation using the EPANET 2.00.12 Programmer's Toolkit [Ross00]_ or EPANET 2.2.0 Programmer's Toolkit [RWTS20]_. EPANET 2.2.0 is used by default and runs demand-driven and pressure dependent hydraulic analysis. EPANET 2.00.12 runs demand-driven hydraulic analysis only. Both versions can also run water quality simulations, as described in :ref:`water_quality_simulation`. diff --git a/documentation/index.rst b/documentation/index.rst index f7d9e1c42..003bde8c1 100644 --- a/documentation/index.rst +++ b/documentation/index.rst @@ -21,6 +21,7 @@ designed to simulate and analyze resilience of water distribution networks. options hydraulics waterquality + waterquality_msx resultsobject disaster_models criticality @@ -30,7 +31,6 @@ designed to simulate and analyze resilience of water distribution networks. graphics gis advancedsim - advancedqual license whatsnew developers diff --git a/documentation/reference.rst b/documentation/reference.rst index 6d74bce38..3fadfd9d5 100644 --- a/documentation/reference.rst +++ b/documentation/reference.rst @@ -18,10 +18,14 @@ References .. [Bieni19] Bieniek, T., van Andel, B., and Bø, T.I. (2019). Bidirectional UTM-WGS84 converter for python, Retrieved on February 5, 2019 from https://github.com/Turbo87/utm. +.. [BWMS20] Burkhardt, J. B., Woo, J., Mason, J., Shang, F., Triantafyllidou, S., Schock, M.R., Lytle, D., and Murray, R. (2020). Framework for Modeling Lead in Premise Plumbing Systems Using EPANET. Journal of Water Resources Planning and Management, 146(12). https://doi.org/10.1061/(asce)wr.1943-5452.0001304 PMID:33627937. + .. [CrLo02] Crowl, D.A., and Louvar, J.F. (2011). Chemical Process Safety: Fundamentals with Applications, 3 edition. Upper Saddle River, NJ: Prentice Hall, 720p. .. [ELLT12] Eto, J.H., LaCommare, K.H., Larsen, P.H., Todd, A., and Fisher, E. (2012). An Examination of Temporal Trends in Electricity Reliability Based on Reports from U.S. Electric Utilities. Lawrence Berkeley National Laboratory Report Number LBNL-5268E. Berkeley, CA: Ernest Orlando Lawrence Berkeley National Laboratory, 68p. +.. [GSCL94] Gu, B., Schmitt, J., Chen, Z. Liang, L., and McCarthy, J.F. (1994) Adsorption and desorption of natural organic matter on iron oxide: mechanisms and models. Environmental Science and Technology, 28:38-46. + .. [JVFM21] Jordahl, K., Van den Bossche, J., Fleischmann, M, McBride, J. and others (2021) geopandas, 10.5281/zenodo.5573592. .. [Folium] python-visualization/folium. (n.d.). Retrieved on February 5, 2019 from https://github.com/python-visualization/folium. diff --git a/documentation/waterquality.rst b/documentation/waterquality.rst index fa784d531..8b8c6ee37 100644 --- a/documentation/waterquality.rst +++ b/documentation/waterquality.rst @@ -17,7 +17,12 @@ Water quality simulation ================================== Water quality simulations can only be run using the EpanetSimulator. - +This includes the ability to run +EPANET 2.00.12 Programmer's Toolkit [Ross00]_ or +EPANET 2.2.0 Programmer's Toolkit [RWTS20]_ for single species, water age, and tracer analysis. + +WNTR also includes the ability to run EPANET-MSX 2.0 [SRU23]_, see :ref:`msx_water_quality` for more information. + After defining water quality options and sources (described in the :ref:`wq_options` and :ref:`sources` sections below), a hydraulic and water quality simulation using the EpanetSimulator is run using the following code: @@ -34,7 +39,7 @@ The results include a quality value for each node (see :ref:`simulation_results` .. _wq_options: Water quality options ------------------------- +--------------------- Three types of water quality analysis are supported. These options include water age, tracer, and chemical concentration. * **Water age**: A water quality simulation can be used to compute water age at every node. @@ -83,7 +88,7 @@ More information on water network options can be found in :ref:`options`. .. _sources: Sources ------------- +------- Sources are required for CHEMICAL water quality analysis. Sources can still be defined, but *will not* be used if AGE, TRACE, or NONE water quality analysis is selected. Sources are added to the water network model using the :class:`~wntr.network.model.WaterNetworkModel.add_source` method. @@ -135,6 +140,7 @@ In the example below, the strength of the source is changed from 1000 to 1500. When creating a water network model from an EPANET INP file, the sources that are defined in the [SOURCES] section are added to the water network model. These sources are given the name 'INP#' where # is an integer representing the number of sources in the INP file. + .. The following is not shown in the UM _wq_pdd: diff --git a/documentation/waterquality_msx.rst b/documentation/waterquality_msx.rst new file mode 100644 index 000000000..d6314097c --- /dev/null +++ b/documentation/waterquality_msx.rst @@ -0,0 +1,93 @@ +.. raw:: latex + + \clearpage + +.. doctest:: + :hide: + + >>> import wntr + >>> try: + ... wn = wntr.network.model.WaterNetworkModel('../examples/networks/Net3.inp') + ... msx_filename = '../examples/data/something.msx' + ... except: + ... wn = wntr.network.model.WaterNetworkModel('examples/networks/Net3.inp') + ... msx_filename = 'examples/data/something.msx' + +.. _msx_water_quality: + +Multi-species water quality simulation +======================================= + +The EpanetSimulator can use EPANET-MSX 2.0 [SRU23]_ to run +multi-species water quality simulations. +Additional multi-species simulation options are discussed in :ref:`advanced_simulation`. + +A multi-species analysis is run if a :class:`~wntr.msx.model.MsxModel` is added to the +:class:`~wntr.network.model.WaterNetworkModel`, as shown below. +In this example, the MsxModel is created from a MSX file (see [SRU23]_ for more information on file format). + +.. doctest:: + + >>> msx_filename = 'data/something.msx') # doctest: +SKIP + >>> wn.msx = wntr.msx.MsxModel(msx_filename) + >>> sim = wntr.sim.EpanetSimulator(wn) + >>> results = sim.run_sim() +[TODO add an msx file that uses Net3 to the examples folder for documentation examples] + +The results include a quality value for each node, link, and species +(see :ref:`simulation_results` for more details). + +Multi-species model +------------------- +In addition to creating an MsxModel from a MSX file, the MsxModel +can be built from scratch and modified using WNTR. +For example, the user can +add and remove species using :class:`~wntr.msx.model.MsxModel.add_species` and :class:`~wntr.msx.model.MsxModel.remove_species`, or +add and remove reactions using :class:`~wntr.msx.model.MsxModel.add_reaction` and :class:`~wntr.msx.model.MsxModel.remove_reaction`. +See the API documentation for the :class:`~wntr.msx.model.MsxModel` for a complete list of methods. + +Variables +~~~~~~~~~ +Variables include **species**, **coefficients**, and **terms**. +These are used in **expressions** to define the dynamics of the reaction. All variables have at least two +attributes: a name and a note. +The variable name must be a valid EPANET-MSX id, which primarily +means no spaces are permitted. However, it may be useful to ensure that the name is a valid python +variable name, so that it can be used to identify the variable in your code as well. +The note can be a string, a dictionary with the keys "pre" and "post", or an :class:`~wntr.epanet.util.ENcomment` object +(which has a "pre" and "post" attribute). See the ENcomment documentation for details on the meaning; +in this example the string form of the note is used. + +There are two different types of coefficients that can be used in reaction expressions: **constants** +and **parameters**. Constants have a single value in every expression. Parameters have a global value +that is used by default, but which can be modified on a per-pipe or per-tank basis. + +Pre-defined hydraulic variable can be found in +the EPANET-MSX documentation, and are also defined in WNTR as :attr:`~wntr.msx.base.HYDRAULIC_VARIABLES`. + +Reactions +~~~~~~~~~ +All species must have two reactions defined for the model to be run successfully in EPANET-MSX by WNTR. +One is a **pipe reaction**, the other is a **tank reaction**. + +Examples that illustrate how to build MSX models in WNTR are included in :ref:`advanced_simulation`. + +Reaction library +----------------- +WNTR also contains a library of MSX models that are accessed through the :class:`~wntr.msx.library.ReactionLibrary`. +This includes the following models: + +* `Arsenic Chloramine model `_ [SRU23]_ +* `Lead Plumbosolvency model `_ [BWMS20]_ +[TODO change the 2 links to usepa, add other models if they are referenced] + +The models are stored in JSON format. +Additional models can be loaded into the library by setting a user specified path. +Additional models could also be added to the WNTR Reactions library. + +The following example loads a MsxModel from the ReactionLibrary. + +.. doctest:: + + >>> msx_model = ... +[TODO finish this example]