Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Model JSON format #232

Merged
merged 24 commits into from Nov 11, 2021
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6e779e4
Updated todict methods to serialize as JSON
dbhart Oct 22, 2021
f126ea4
Update to add a fromdict function
dbhart Oct 29, 2021
27bfb9d
Finished fromdict method for WaterNetworkModel
dbhart Oct 29, 2021
e08c6ca
Added testing for todict and fromdict
dbhart Oct 30, 2021
cb9afed
Fix doctests and documentation
dbhart Oct 30, 2021
df58e0f
Adding aliases for from*() functions to wntr.network
dbhart Oct 30, 2021
bc2e41d
Ugh, doctests are so rigid. Fixed I think
dbhart Oct 30, 2021
cd0d1f7
Doctests should be whitespace forgiving!
dbhart Oct 30, 2021
070f077
Added some additional documentation.
dbhart Oct 31, 2021
b12cee3
Documentation doctest error
dbhart Oct 31, 2021
151cdcf
Update the names of the functions to be consistent
dbhart Nov 5, 2021
8820501
Too agressive changing tolist->to_list; corrected
dbhart Nov 5, 2021
41f3849
Too agressive changing tolist->to_list; corrected
dbhart Nov 5, 2021
86e03b5
Format json examples for human readability
dbhart Nov 5, 2021
494739d
Added additional tests to the to/from_dict section
dbhart Nov 5, 2021
4fc35c5
Making the demand pattern name and category explicit in the json object
dbhart Nov 8, 2021
6be528b
Doc updates
kaklise Nov 8, 2021
0b998b6
Merge pull request #117 from kaklise/json-model
dbhart Nov 8, 2021
f7bc015
Allow passing of arguments to json dumper/loader
dbhart Nov 9, 2021
b549a60
Put source registry back in
dbhart Nov 10, 2021
f02a028
Adding tests for SourceRegistry
dbhart Nov 10, 2021
ce9a5e8
Update to create a wntr.network.io separate from model
dbhart Nov 11, 2021
d03b38b
updated release notes
kaklise Nov 11, 2021
1d2dff4
Merge pull request #118 from kaklise/json-model
dbhart Nov 11, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 11 additions & 11 deletions documentation/controls.rst
Expand Up @@ -64,7 +64,7 @@ The following example creates an action that opens pipe 330, in which a status o
>>> pipe = wn.get_link('330')
>>> act1 = controls.ControlAction(pipe, 'status', 1)
>>> print(act1)
set Pipe('330').status to Open
PIPE 330 STATUS IS OPEN

Conditions
----------
Expand Down Expand Up @@ -112,11 +112,11 @@ The action `act1` from above is used in the control.
>>> tank = wn.get_node('1')
>>> cond1 = controls.ValueCondition(tank, 'level', '>', 46.0248)
>>> print(cond1)
Tank('1').level > 46.0248
TANK 1 LEVEL ABOVE 46.0248

>>> ctrl1 = controls.Control(cond1, act1, name='control1')
>>> print(ctrl1)
Control control1 := if Tank('1').level > 46.0248 then set Pipe('330').status to Open with priority 3
IF TANK 1 LEVEL ABOVE 46.0248 THEN PIPE 330 STATUS IS OPEN PRIORITY 3

In the following example, a time-based control is defined that opens pump 10 at hour 121.
A new action is defined that opens the pump. The SimTimeCondition parameter can be specified as decimal hours
Expand All @@ -128,11 +128,11 @@ or as a string in ``[dd-]hh:mm[:ss]`` format. When printed, the output is conver
>>> act2 = controls.ControlAction(pump, 'status', 1)
>>> cond2 = controls.SimTimeCondition(wn, '=', '121:00:00')
>>> print(cond2)
sim_time = 435600 sec
SYSTEM TIME IS 121:00:00

>>> ctrl2 = controls.Control(cond2, act2, name='control2')
>>> print(ctrl2)
Control control2 := if sim_time = 435600 sec then set HeadPump('10').status to Open with priority 3
IF SYSTEM TIME IS 121:00:00 THEN PUMP 10 STATUS IS OPEN PRIORITY 3

Rules
--------------------------
Expand All @@ -153,12 +153,12 @@ The following examples illustrate the creation of rules, using conditions and ac

>>> rule1 = controls.Rule(cond1, [act1], name='rule1')
>>> print(rule1)
Rule rule1 := if Tank('1').level > 46.0248 then set Pipe('330').status to Open with priority 3
IF TANK 1 LEVEL ABOVE 46.0248 THEN PIPE 330 STATUS IS OPEN PRIORITY 3

>>> pri5 = controls.ControlPriority.high
>>> rule2 = controls.Rule(cond2, [act2], name='rule2', priority=pri5)
>>> print(rule2)
Rule rule2 := if sim_time >= 435600 sec then set HeadPump('10').status to Open with priority 5
IF SYSTEM TIME >= 121:00:00 THEN PUMP 10 STATUS IS OPEN PRIORITY 5

Since rules operate on a different timestep than controls, these rules might behave differently than the equivalent controls defined above.
Controls (or simple controls in EPANET) operate on the hydraulic timestep while Rules (or rule-based controls in EPANET) operate at a smaller timestep.
Expand All @@ -173,11 +173,11 @@ and otherwise it will open pump 10.

>>> cond3 = controls.AndCondition(cond1, cond2)
>>> print(cond3)
( Tank('1').level > 46.0248 && sim_time >= 435600 sec )
TANK 1 LEVEL ABOVE 46.0248 AND SYSTEM TIME >= 121:00:00

>>> rule3 = controls.Rule(cond3, [act1], [act2], priority=3, name='complex_rule')
>>> print(rule3)
Rule complex_rule := if ( Tank('1').level > 46.0248 && sim_time >= 435600 sec ) then set Pipe('330').status to Open else set HeadPump('10').status to Open with priority 3
IF TANK 1 LEVEL ABOVE 46.0248 AND SYSTEM TIME >= 121:00:00 THEN PIPE 330 STATUS IS OPEN ELSE PUMP 10 STATUS IS OPEN PRIORITY 3

Actions can also be combined, as shown in the following example.

Expand All @@ -186,7 +186,7 @@ Actions can also be combined, as shown in the following example.
>>> cond4 = controls.OrCondition(cond1, cond2)
>>> rule4 = controls.Rule(cond4, [act1, act2], name='rule4')
>>> print(rule4)
Rule rule4 := if ( Tank('1').level > 46.0248 || sim_time >= 435600 sec ) then set Pipe('330').status to Open and set HeadPump('10').status to Open with priority 3
IF TANK 1 LEVEL ABOVE 46.0248 OR SYSTEM TIME >= 121:00:00 THEN PIPE 330 STATUS IS OPEN AND PUMP 10 STATUS IS OPEN PRIORITY 3

The flexibility of rules provides an extremely powerful tool for defining complex network operations.

Expand All @@ -201,7 +201,7 @@ The control or rule should be named so that it can be retrieved and modified if

>>> wn.add_control('NewTimeControl', ctrl2)
>>> wn.get_control('NewTimeControl')
<Control: 'control2', <SimTimeCondition: model, 'Is', '5-01:00:00', False, 0>, [<ControlAction: 10, status, Open>], [], priority=3>
<Control: 'control2', <SimTimeCondition: model, 'Is', '5-01:00:00', False, 0>, [<ControlAction: 10, status, OPEN>], [], priority=3>

..
If a control of that name already exists, an error will occur. In this case, the control will need to be deleted first.
Expand Down
27 changes: 27 additions & 0 deletions documentation/waternetworkmodel.rst
Expand Up @@ -271,6 +271,33 @@ EPANET INP files can be saved in EPANET 2.00.12 or 2.2.0 format.

>>> wn.write_inpfile('filename.inp', version=2.2)

Read and write a model to a dictionary or JSON file
---------------------------------------------------

The water network model can be converted to a dictionary representation.
The dictionary contains keys for each of the following water network model objects:
nodes, links, patterns, curves, sources, controls, and options.
Each of these entries contains a dictionary or list of dictionaries with keys corresponding to the object attributes.
Dictionary representations of the model are always written in SI units (m, kg, s).
To create a dictionary, use the :class:`~wntr.network.model.WaterNetworkModel.to_dict` method on the water network model.
To create a water network model from a dictionary, use the :class:`~wntr.network.model.WaterNetworkModel.from_dict` method.

.. doctest::

>>> wn_dict = wn.to_dict()

The water network model can also be converted to a JSON (JavaScript Object Notation) file.
The JSON file is a formatted version of the dictionary representation.
The :class:`~wntr.network.model.WaterNetworkModel.write_json` and :class:`~wntr.network.model.WaterNetworkModel.read_json` methods wrap
the dictionary representation with the Python standard library JSON loader and dumper.

.. doctest::

>>> wn.write_json('Net3.json')

Note that these methods do not check for a valid dictionary/JSON schema prior to building a model.
They simply ignore extraneous or invalid dictionary keys.

Build a model from scratch
---------------------------------

Expand Down
10 changes: 8 additions & 2 deletions documentation/whatsnew/v0.4.1.rst
Expand Up @@ -3,12 +3,18 @@
v0.4.1 (main)
---------------------------------------------------

* Added a function to compute the modified resilience index, ``wntr.metrics.modified_resilience_index`. The modified resilience
* Added a function to compute the modified resilience index, ``wntr.metrics.modified_resilience_index``. The modified resilience
index is a measure of total surplus power. The metric can be computed as a timeseries for each junction or as a system average timeseries.

* Added a function to compute tank capacity, ``wntr.metrics.tank_capacity``. Tank capacity is the ratio of water volume to the maximum
water volume for each tank and is reported as a timeseries.

* Updated the WNTRSimulator to use ``wn.options.time.pattern_start``.

* Removed private attribute on pumps associated with power outage controls which is no longer needed.
* Removed private attribute on pumps associated with power outage controls which is no longer needed.

* Added a functionality to convert the water network model to a dictionary or JSON formatted file/stream.
Also added functionality to convert the dictionary or JSON representation back to a water network model.
The new functionality is located on the ``WaterNetworkModel`` class as ``to_dict``, ``from_dict``,
``write_json`` and ``read_json``, with aliases for the ``from_dict`` and ``read_json`` functions provided
at the ``wntr.network`` module level.