Commit 5f070024 authored by Jesse VanderWees's avatar Jesse VanderWees 🐘

added boolean submerged orifice and spelling fixes in docs

parent 1476a9c8
......@@ -11,7 +11,7 @@ The purpose of this example is to understand the technical setup of
an RTC-Tools model, how to run the model, and how to interpret the results.
The scenario is the following: A reservoir operator is trying to fill a
reservoir. They are given a six-day forcast of inflows given in 12-hour
reservoir. They are given a six-day forecast of inflows given in 12-hour
increments. The operator wants to save as much of the inflows as possible, but
does not want to end up with too much water at the end of the six days. They
have chosen to use RTC-Tools to calculate how much water to release and when
......@@ -34,10 +34,10 @@ The Model
---------
The first step is to develop a physical model of the system. The model can be
viewed and editied using the OpenModelica Connection Editor (OMEdit) program.
viewed and edited using the OpenModelica Connection Editor (OMEdit) program.
For how to download and start up OMEdit, see :ref:`getting-started-omedit`.
Make sure to load the Deltares libray before loading the example:
Make sure to load the Deltares library before loading the example:
#. Load the Deltares library into OMEdit
......@@ -58,7 +58,7 @@ this:
The model ``Example.mo`` represents a simple system with the following
elements:
* a reservoir, modelled as storage element
* a reservoir, modeled as storage element
``Deltares.ChannelFlow.SimpleRouting.Storage.Storage``,
* an inflow boundary condition
``Deltares.ChannelFlow.SimpleRouting.BoundaryConditions.Inflow``,
......@@ -66,7 +66,7 @@ elements:
``Deltares.ChannelFlow.SimpleRouting.BoundaryConditions.Terminal``,
* connectors (black lines) connecting the elements.
You can use the mouse-over feature help to identify the pre-defined models from
You can use the mouse-over feature help to identify the predefined models from
the Deltares library. You can also drag the elements around- the connectors will
move with the elements. Adding new elements is easy- just drag them in from the
Deltares Library on the sidebar. Connecting the elements is just as easy- click
......@@ -84,7 +84,7 @@ the ``model Example`` statement. The ``equation`` part connects these three
elements with the help of connections. Note that ``storage`` extends the partial
model ``QSISO`` which contains the connectors ``QIn`` and ``QOut``.
With ``QSISO``, ``storage`` can be connected on two sides. The ``storage``
element also has a variable ``Q_release``, which is the descision variable the
element also has a variable ``Q_release``, which is the decision variable the
operator controls.
OpenModelica Connection Editor will automatically generate the element and
......@@ -93,7 +93,7 @@ editing the text file directly. Relationships between the inputs and outputs and
the library elements must also be defined in the ``equation`` section.
In addition to elements, the input variables ``Q_in`` and ``Q_release`` are also
defined. ``Q_in`` is determined by the forecast and the operator cannot contol
defined. ``Q_in`` is determined by the forecast and the operator cannot control
it, so we set ``Q_in(fixed = true)``. The actual values of ``Q_in`` are stored
in ``timeseries_input.csv``. In the ``equation`` section, equations are defined
to relate the inputs to the appropriate water system elements.
......@@ -136,7 +136,7 @@ Optimization Problem
The next step is to define the optimization problem class. We construct the
class by declaring the class and inheriting the desired parent classes. The
parent classes each perform different tasks realted to importing and exporting
parent classes each perform different tasks related to importing and exporting
data and solving the optimization problem. Each imported class makes a set of
methods available to the our optimization class.
......@@ -154,9 +154,9 @@ the value that needs to be minimized.
:pyobject: Example.objective
:lineno-match:
Constraints can be declared by declairing the ``path_constraints`` method. Path
Constraints can be declared by declaring the ``path_constraints()`` method. Path
constraints are constraints that are applied every timestep. To set a constraint
at an individual timestep, we could define it inside the ``constraints`` method.
at an individual timestep, we could define it inside the ``constraints()`` method.
Other parent classes also declare this method, so we call the ``super()`` method
so that we don't overwrite their behaviour.
......@@ -208,5 +208,5 @@ This plot shows that the operator is able to keep the water level within the
bounds over the entire time horizon and end with a full reservoir.
Feel free to experiment with this example. See what happens if you change the
max of ``Q_release`` (in the modelica file) or if you make the objective
max of ``Q_release`` (in the Modelica file) or if you make the objective
function negative (in the python script).
......@@ -53,7 +53,7 @@ The Model
.. note::
This example uses the same hydraulic model as the basic example. For a
detalied explaination of the hydraulic model, see :doc:`basic`.
detailed explanation of the hydraulic model, see :doc:`basic`.
In OpenModelica Connection Editor, the model looks like this:
......@@ -269,7 +269,7 @@ between the two possible futures. This will cause the water level to diverge
from the ideal levels as time progresses. While this appears to be suboptimal,
it is preferable to simply gambling on one of the forecasts coming true and
ignoring the other. Once the branching time is reached, RTC-Tools is allowed
to optimize for each individual branch separately. Immidiately, RTC-Tools
to optimize for each individual branch separately. Immediately, RTC-Tools
applies the corrective control needed to get the water levels into the
acceptable range. If the operator simply picks a forecast to use and guesses
wrong, the corrective control will have to be much more drastic and
......
......@@ -3,7 +3,7 @@ Goal Programming: Defining Multiple Objectives
.. note::
This example focuses on how to implement multiobjective optimization in
This example focuses on how to implement multi-objective optimization in
RTC-Tools using Goal Programming. It assumes basic exposure to
RTC-Tools. If you are a first-time user of RTC-Tools, see
:doc:`basic`.
......@@ -24,7 +24,7 @@ roughly divided into two types:
allowing any change at all).
In this example, we will be specifying two goals, on for each type. The higher
priority goal will be to maintian the water level of the storage element between
priority goal will be to maintain the water level of the storage element between
two levels. The lower priority goal will be to minimize the total volume pumped.
The Model
......@@ -33,7 +33,7 @@ The Model
.. note::
This example uses the same hydraulic model as the MILP example. For a
detalied explaination of the hydraulic model, including how to to formulate
detailed explanation of the hydraulic model, including how to to formulate
mixed integers in your model, see :doc:`mixed_integer`.
For this example, the model represents a typical setup for the dewatering of
......@@ -115,12 +115,12 @@ of the variable over all the timesteps. This goal does not use a helper class:
:lineno-match:
We add a third goal minimizing the changes in``Q_pump``, and give it the
least priority. This goal smoothes out the operation of the pump so that it
least priority. This goal smooths out the operation of the pump so that it
changes state as few times as possible. To get an idea of what the pump would
have done without this goal, see Mixed Integer: :ref:`mixed-integer-results`.
The order of this goal must be 2, so that it penalizes both positive and
negative derivatives. Order of 2 is the default, but we include it here
explicity for the sake of clarity.
explicitly for the sake of clarity.
.. literalinclude:: ../../examples/goal_programming/src/example.py
:language: python
......@@ -139,13 +139,15 @@ classes.
:lineno-match:
:end-before: """
Constraints can be declared by declairing the ``path_constraints()`` method.
Constraints can be declared by declaring the ``path_constraints()`` method.
Path constraints are constraints that are applied every timestep. To set a
constraint at an individual timestep, define it inside the ``constraints()``
method.
Other parent classes also declare this method, so we call the ``super()`` method
so that we don't overwrite their behaviour.
The "orifice" requires special constraints to be set in order to work. They are
implemented below in the ``path_constraints()`` method. Other parent classes
also declare this method, so we call the ``super()`` method so that we don't
overwrite their behaviour.
.. literalinclude:: ../../examples/goal_programming/src/example.py
:language: python
......@@ -195,7 +197,7 @@ store our list of intermediate results:
:pyobject: Example.pre
:lineno-match:
Next, we define the ``priority_completed()`` method to inspect and summerize the
Next, we define the ``priority_completed()`` method to inspect and summarize the
results. These are appended to our intermediate results variable after each
priority is completed.
......@@ -269,7 +271,7 @@ minimize the number of states in violation of the water level goal.
After optimizing for the priority 2 goal, the solver was able to find a solution
that reduced the integral of ``Q_pump`` without increasing the number of
timesteps where the water level exceded the limit. However, this solution
timesteps where the water level exceeded the limit. However, this solution
induced additional variation into the operation of ``Q_pump``
After optimizing the priority 3 goal, the integral of ``Q_pump`` is the same and
......
......@@ -26,23 +26,22 @@ level at minimum costs. The expected result is that the model computes a control
pattern that makes use of gradient flow whenever possible and activates the pump
only when necessary.
The model can be viewed and editied using the OpenModelica Connection Editor
The model can be viewed and edited using the OpenModelica Connection Editor
program. First load the Deltares library into OpenModelica Connection Editor,
and then load the example model, located at
``RTCTools2\examples\mixed_integer\model\Example.mo``. The model ``Example.mo``
represents a simple water system with the following elements:
* a canal segment, modelled as storage element
* a canal segment, modeled as storage element
``Deltares.ChannelFlow.Hydraulic.Storage.Linear``,
* a discharge boundary condition
``Deltares.ChannelFlow.Hydraulic.BoundaryConditions.Discharge``,
* a water level boundary condition
``Deltares.ChannelFlow.Hydraulic.BoundaryConditions.Level``,
* two hydraulic structures, both modeled as
``Deltares.ChannelFlow.Hydraulic.Structures.Pump``:
* a pump,
* an orifice.
* a pump
``Deltares.ChannelFlow.Hydraulic.Structures.Pump``
* an orifice
``Deltares.ChannelFlow.Hydraulic.Structures.BooleanSubmergedOrifice``
.. image:: ../images/orifice_vs_pump_openmodelica.png
......@@ -124,12 +123,15 @@ volume pumped:
:pyobject: Example.objective
:lineno-match:
Constraints can be declared by declairing the ``path_constraints`` method. Path
constraints are constraints that are applied every timestep. To set a constraint
at an individual timestep, define it inside the ``constraints`` method.
Constraints can be declared by declaring the ``path_constraints()`` method.
Path constraints are constraints that are applied every timestep. To set a
constraint at an individual timestep, define it inside the ``constraints``
method.
Other parent classes also declare this method, so we call the ``super()`` method
so that we don't overwrite their behaviour.
The orifice ``BooleanSubmergedOrifice`` requires special constraints to be set
in order to work. They are implemented below in the ``path_constraints()``
method. their parent classes also declare this method, so we call the
``super()`` method so that we don't overwrite their behaviour.
.. literalinclude:: ../../examples/mixed_integer/src/example.py
:language: python
......
......@@ -3,7 +3,7 @@ model Example
Deltares.ChannelFlow.Hydraulic.BoundaryConditions.Discharge discharge annotation(Placement(visible = true, transformation(origin = {60, -0}, extent = {{10, -10}, {-10, 10}}, rotation = 270)));
Deltares.ChannelFlow.Hydraulic.BoundaryConditions.Level level annotation(Placement(visible = true, transformation(origin = {-52.7, 0}, extent = {{-10, -10}, {10, 10}}, rotation = -270)));
Deltares.ChannelFlow.Hydraulic.Structures.Pump pump annotation(Placement(visible = true, transformation(origin = {0, -20}, extent = {{10, -10}, {-10, 10}}, rotation = 0)));
Deltares.ChannelFlow.Hydraulic.Structures.Pump orifice annotation(Placement(visible = true, transformation(origin = {0, 20}, extent = {{10, -10}, {-10, 10}}, rotation = 0)));
Deltares.ChannelFlow.Hydraulic.Structures.BooleanSubmergedOrifice orifice(width = 3.0, height = 0.8) annotation(Placement(visible = true, transformation(origin = {0, 20}, extent = {{10, -10}, {-10, 10}}, rotation = 0)));
input Modelica.SIunits.VolumeFlowRate Q_in(fixed=true);
input Modelica.SIunits.Position H_sea(fixed=true);
input Modelica.SIunits.VolumeFlowRate Q_pump(fixed=false, min=0.0, max=7.0);
......@@ -24,4 +24,4 @@ equation
storage_level = storage.HQ.H;
sea_level = H_sea;
annotation(Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})));
end Example;
end Example;
\ No newline at end of file
......@@ -41,19 +41,14 @@ class Example(CSVMixin, ModelicaMixin, CollocatedIntegratedOptimizationProblem):
constraints.append((self.state('H_sea') - self.state('storage.HQ.H') +
self.state('is_downhill') * M, 0.0, inf))
# Orifice flow constraint. Uses the equation:
# Q(HUp, HDown, d) = width * C * d * (2 * g * (HUp - HDown)) ^ 0.5
# Note that this equation is only valid for orifices that are submerged
# units: description:
w = 3.0 # m width of orifice
d = 0.8 # m hight of orifice
C = 1.0 # none orifice constant
g = 9.8 # m/s^2 gravitational acceleration
# Orifice flow upper bound. Uses the equation:
# Q = width * C * height * (2 * g * (HQUp.H - HQDown.H)) ^ 0.5
# orifice.LHS is the left-hand-side of this equation in standard form:
# ((Q / (width * height * C)) ^ 2) / (g * 2) + HQDown.H - HQUp.H = 0
constraints.append(
(((self.state('Q_orifice') / (w * C * d)) ** 2) / (2 * g) +
self.state('orifice.HQDown.H') - self.state('orifice.HQUp.H') -
M * (1 - self.state('is_downhill')),
(self.state('orifice.LHS') - M * (1.0 - self.state('is_downhill')),
-inf, 0.0))
# Note that this element is only valid for orifices that are submerged!
return constraints
......@@ -65,4 +60,4 @@ class Example(CSVMixin, ModelicaMixin, CollocatedIntegratedOptimizationProblem):
return options
# Run
run_optimization_problem(Example)
run_optimization_problem(Example)
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment