rtc-tools 2.8.0a1__py3-none-any.whl → 2.8.0a2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of rtc-tools might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rtc-tools
3
- Version: 2.8.0a1
3
+ Version: 2.8.0a2
4
4
  Summary: Toolbox for control and optimization of water systems.
5
5
  Project-URL: Homepage, https://oss.deltares.nl/web/rtc-tools/home
6
6
  Project-URL: Download, http://github.com/deltares/rtc-tools/
@@ -191,10 +191,10 @@ Requires-Python: >=3.9
191
191
  Requires-Dist: casadi!=3.6.6,<3.8,>=3.6.3
192
192
  Requires-Dist: defusedxml>=0.7.0
193
193
  Requires-Dist: importlib-metadata>=5.0.0; python_version < '3.10'
194
- Requires-Dist: numpy>=1.16.0
194
+ Requires-Dist: numpy>=1.20.0
195
195
  Requires-Dist: pymoca==0.9.*,>=0.9.1
196
196
  Requires-Dist: rtc-tools-channel-flow>=1.2.0
197
- Requires-Dist: scipy>=1.0.0
197
+ Requires-Dist: scipy>=1.6.0
198
198
  Provides-Extra: all
199
199
  Requires-Dist: netcdf4; extra == 'all'
200
200
  Provides-Extra: netcdf
@@ -219,13 +219,11 @@ RTC-Tools offers the following functionalities:
219
219
 
220
220
  - **Model building using extensible libraries**: Build complex system models using extensible libraries of model components. Modelers can also implement their custom modeling components, for instance, using the [Modelica language](https://modelica.org/language/) or Python script.
221
221
 
222
- RTC-Tools can be used with the following libraries and packages for specific applications:
222
+ RTC-Tools can be used with the following libraries and packages for specific applications. Please note that this list is not exhaustive. Users can also create libraries for other types of applications.
223
223
  - [rtc-tools-channel-flow](https://gitlab.com/deltares/rtc-tools-channel-flow): water system models
224
224
  - [rtc-tools-hydraulic-structures](https://gitlab.com/deltares/rtc-tools-channel-flow): hydraulic assets, such as weirs and pumps
225
225
  - [rtc-tools-heat-network](https://github.com/Nieuwe-Warmte-Nu/rtc-tools-heat-network): heat networks
226
-
227
- Please note that this list is not exhaustive. Users can also create libraries for other types of applications.
228
-
226
+
229
227
  - **Running simulations**: Simulate a given model.
230
228
 
231
229
  - **Specifying and solving optimization problems**: Define optimization goals, constraints and decision variables to specify the optimization problem for a given model. RTC-Tools supports both open-source solvers (CBC, HiGHS, Ipopt) and commercial solvers (Gurobi, CPLEX) for solving several types of optimization problems:
@@ -5,7 +5,7 @@ rtctools/version.py,sha256=xvbTWTq6B21t4hw5bi2hdOVaIBeDBQtqEEHe0kxYZsc,1995
5
5
  rtctools/_internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  rtctools/_internal/alias_tools.py,sha256=XuQSAhhFuVtwn0yrAObZWIKPsSF4j2axXRtEmitIFPs,5310
7
7
  rtctools/_internal/caching.py,sha256=p4gqSL7kCI7Hff-KjMEP7mhJCQSiU_lYm2MR7E18gBM,905
8
- rtctools/_internal/casadi_helpers.py,sha256=UcVSBsOs9f8gAGk4s3CQRS7TSE1CIvKt0uhrD4gLwu4,1727
8
+ rtctools/_internal/casadi_helpers.py,sha256=vN1H7D_6otY6stVD0Dw2b2UapCJ6T2r8QuscNT8OJOw,2309
9
9
  rtctools/_internal/debug_check_helpers.py,sha256=UgQTEPw4PyR7MbYLewSSWQqTwQj7xr5yUBk820O9Kk4,1084
10
10
  rtctools/_internal/ensemble_bounds_decorator.py,sha256=-eMSvkgKQ0Ew3EBDzsikQjIOlEP_iZOpbGGuX8R0F_A,2917
11
11
  rtctools/data/__init__.py,sha256=EllgSmCdrlvQZSd1VilvjPaeYJGhY9ErPiQtedmuFoA,157
@@ -19,7 +19,7 @@ rtctools/data/interpolation/bspline.py,sha256=qevB842XWCH3fWlWMBqKMy1mw37ust-0Yt
19
19
  rtctools/data/interpolation/bspline1d.py,sha256=HAh7m5xLBuiFKzMzuYEqZX_GmCPChKjV7ynTS6iRZOc,6166
20
20
  rtctools/data/interpolation/bspline2d.py,sha256=ScmX0fPDxbUVtj3pbUE0L7UJocqroD_6fUT-4cvdRMc,1693
21
21
  rtctools/optimization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- rtctools/optimization/collocated_integrated_optimization_problem.py,sha256=cmcjcrv5EdVcZfAZNB8V-BwPC7M1IJYnalvPaP8BhYo,133037
22
+ rtctools/optimization/collocated_integrated_optimization_problem.py,sha256=eiBh9kxbD7W-KgG44rwOhygKD6yJqAFvCisZIJRK7No,135509
23
23
  rtctools/optimization/control_tree_mixin.py,sha256=6OMvjT5rFvvXU3_O6Uwz8xvBQpRH9d5z4mMOtOQ4-a4,9036
24
24
  rtctools/optimization/csv_lookup_table_mixin.py,sha256=TUYAT-u-mzH6HLP0iJHnLBVqV5tWnhYAqDC4Aj17MJg,17399
25
25
  rtctools/optimization/csv_mixin.py,sha256=_6iPVK_EJ8PxnukepzkhFtidceucsozRML_DDEycYik,12453
@@ -43,10 +43,10 @@ rtctools/simulation/csv_mixin.py,sha256=rGDUFPsqGHmF0_dWdXeWzWzMpkPmwCNweTBVrwSh
43
43
  rtctools/simulation/io_mixin.py,sha256=WIKOQxr3fS-aNbgjet9iWoUayuD22zLIYmqlWEqxXHo,6215
44
44
  rtctools/simulation/pi_mixin.py,sha256=_TU2DrK2MQqVsyrHBD9W4SDEuot9dYmgTDNiXkDAJfk,9833
45
45
  rtctools/simulation/simulation_problem.py,sha256=v5Lk2x-yuVb5s7ne5fFgxONxGniLHTyTR0XRzYRl1fw,50005
46
- rtc_tools-2.8.0a1.dist-info/METADATA,sha256=HXC5wG6m5tOfAZQ2xdllrW2S17p4Ni3puH2vddtxe08,15024
47
- rtc_tools-2.8.0a1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
48
- rtc_tools-2.8.0a1.dist-info/entry_points.txt,sha256=DVS8sWf3b9ph9h8srEr6zmQ7ZKGwblwgZgGPZg-jRNQ,150
49
- rtc_tools-2.8.0a1.dist-info/licenses/AUTHORS,sha256=PlDXG1ipmYrbNMR93XVp4_bcvcz30__pEi7mxvl9TWk,155
50
- rtc_tools-2.8.0a1.dist-info/licenses/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
51
- rtc_tools-2.8.0a1.dist-info/licenses/COPYING.LESSER,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
52
- rtc_tools-2.8.0a1.dist-info/RECORD,,
46
+ rtc_tools-2.8.0a2.dist-info/METADATA,sha256=nKu420Qtu40T8fhGyBihzZD3UEx_ZZmL9ewiN6B468c,15035
47
+ rtc_tools-2.8.0a2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
48
+ rtc_tools-2.8.0a2.dist-info/entry_points.txt,sha256=DVS8sWf3b9ph9h8srEr6zmQ7ZKGwblwgZgGPZg-jRNQ,150
49
+ rtc_tools-2.8.0a2.dist-info/licenses/AUTHORS,sha256=al_VX-S8aXSvAt0PNBikE_KWq0ovofK54qTW_JLr9TA,201
50
+ rtc_tools-2.8.0a2.dist-info/licenses/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
51
+ rtc_tools-2.8.0a2.dist-info/licenses/COPYING.LESSER,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
52
+ rtc_tools-2.8.0a2.dist-info/RECORD,,
@@ -1,10 +1,13 @@
1
+ Farid Alavi
1
2
  Jorn Baayen
2
3
  Joris Bentvelsen
3
4
  Olav van Duin
4
5
  Sjoerd Geevers
6
+ Joris Gillis
5
7
  Klaudia Horváth
6
8
  Ailbhe Mitchell
7
9
  Teresa Piovesan
10
+ Jesús A. Rodríguez
8
11
  Matthijs den Toom
9
12
  Jesse VanderWees
10
13
  Tjerk Vreeken
@@ -1,9 +1,15 @@
1
1
  import logging
2
+ from typing import Union
2
3
 
3
4
  import casadi as ca
4
5
 
5
6
  logger = logging.getLogger("rtctools")
6
7
 
8
+ # Limit the number of times we try to substitute in external functions, e.g. in
9
+ # case of infinite recursion. Generally unlikely that we will hit this limit for
10
+ # any reasonable use case.
11
+ MAX_SUBSTITUTE_DEPTH = 10
12
+
7
13
 
8
14
  def is_affine(expr, symbols):
9
15
  try:
@@ -37,12 +43,24 @@ def reduce_matvec(e, v):
37
43
  return ca.reshape(ca.mtimes(A, v), e.shape)
38
44
 
39
45
 
40
- def substitute_in_external(expr, symbols, values):
41
- if len(symbols) == 0 or all(isinstance(x, ca.DM) for x in expr):
46
+ def substitute_in_external(
47
+ expr: list[ca.MX], symbols: list[ca.MX], values: list[Union[ca.MX, ca.DM, float]]
48
+ ):
49
+ # We expect expr to be a list of (at most) length 1
50
+ assert len(expr) <= 1
51
+
52
+ if not expr or len(symbols) == 0 or all(isinstance(x, ca.DM) for x in expr):
42
53
  return expr
54
+ elif not expr:
55
+ return []
43
56
  else:
44
- f = ca.Function("f", symbols, expr)
45
- return f.call(values, True, False)
57
+ for _ in range(MAX_SUBSTITUTE_DEPTH):
58
+ f = ca.Function("f", symbols, expr).expand()
59
+ expr = f.call(values, True, False)
60
+ if expr[0].is_constant():
61
+ break
62
+
63
+ return expr
46
64
 
47
65
 
48
66
  def interpolate(ts, xs, t, equidistant, mode=0):
@@ -45,11 +45,17 @@ class CollocatedIntegratedOptimizationProblem(OptimizationProblem, metaclass=ABC
45
45
 
46
46
  :cvar check_collocation_linearity:
47
47
  If ``True``, check whether collocation constraints are linear. Default is ``True``.
48
+ :cvar inline_delay_expressions:
49
+ If ``True``, delay expressions are inlined into constraints and objectives instead of
50
+ being added as separate equality constraints. Default is ``False``.
48
51
  """
49
52
 
50
53
  #: Check whether the collocation constraints are linear
51
54
  check_collocation_linearity = True
52
55
 
56
+ #: Inline delay expressions instead of adding them as separate equality constraints
57
+ inline_delay_expressions = False
58
+
53
59
  #: Whether or not the collocation constraints are linear (affine)
54
60
  linear_collocation = None
55
61
 
@@ -386,7 +392,9 @@ class CollocatedIntegratedOptimizationProblem(OptimizationProblem, metaclass=ABC
386
392
  ):
387
393
  parameter_values = nullvertcat(*parameter_values)
388
394
  [parameter_values] = substitute_in_external(
389
- [parameter_values], self.dae_variables["parameters"], parameter_values
395
+ [parameter_values],
396
+ self.dae_variables["parameters"],
397
+ ca.vertsplit(parameter_values),
390
398
  )
391
399
  else:
392
400
  parameter_values = nullvertcat(*parameter_values)
@@ -1789,6 +1797,12 @@ class CollocatedIntegratedOptimizationProblem(OptimizationProblem, metaclass=ABC
1789
1797
  + [constant_inputs[v.name()] for v in self.dae_variables["constant_inputs"]]
1790
1798
  )
1791
1799
 
1800
+ # If inlining delay expressions, prepare for the single call to ca.substitute()
1801
+ # at the end
1802
+ if self.inline_delay_expressions:
1803
+ delayed_feedback_variable_replacement = ca.MX.zeros(X.numel())
1804
+ delayed_feedback_variable_replacement[:] = X
1805
+
1792
1806
  for i in range(len(delayed_feedback_expressions)):
1793
1807
  in_variable_name = delayed_feedback_states[i]
1794
1808
  expression = delayed_feedback_expressions[i]
@@ -1855,10 +1869,38 @@ class CollocatedIntegratedOptimizationProblem(OptimizationProblem, metaclass=ABC
1855
1869
 
1856
1870
  nominal = nominal_delayed_feedback[i]
1857
1871
 
1858
- g.append((x_in - x_out_delayed) / nominal)
1859
- zeros = np.zeros(n_collocation_times)
1860
- lbg.extend(zeros)
1861
- ubg.extend(zeros)
1872
+ if self.inline_delay_expressions:
1873
+ # Get the indices for the delayed feedback variable in the optimization
1874
+ # vector
1875
+ indices = self.__indices[ensemble_member][in_canonical]
1876
+
1877
+ # Insert replacement values into appropriate slot
1878
+ delayed_feedback_variable_replacement[indices] = (
1879
+ x_out_delayed / in_nominal / in_sign
1880
+ )
1881
+
1882
+ # Equate delayed feedback variable to zero so that the numerical solver can
1883
+ # remove it from the problem.
1884
+ #
1885
+ # Note: The alternative approach would be to shrink self.solver_input=X,
1886
+ # self.__indices, and any other variables that directly or indirectly
1887
+ # depend on the size and order of 'X'. This would be a complex operation,
1888
+ # which would however be redundant for solvers that (like Ipopt) already
1889
+ # automatically detect and remove variables where lbx==ubx.
1890
+ lbx[indices] = 0.0
1891
+ ubx[indices] = 0.0
1892
+ else:
1893
+ # Default behavior: add delay expressions as equality constraints
1894
+ g.append((x_in - x_out_delayed) / nominal)
1895
+ zeros = np.zeros(n_collocation_times)
1896
+ lbg.extend(zeros)
1897
+ ubg.extend(zeros)
1898
+
1899
+ # If inlining delay expressions, carry out the single call to ca.substitute()
1900
+ # A single call is more efficient as it constructs a single ca.Function internally,
1901
+ # rather than one for each element of the list.
1902
+ if self.inline_delay_expressions:
1903
+ g = [ca.substitute(ca.vertcat(*g), X, delayed_feedback_variable_replacement)]
1862
1904
 
1863
1905
  # Objective
1864
1906
  f_member = self.objective(ensemble_member)