rtc-tools 2.5.2rc4__tar.gz → 2.6.0__tar.gz

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.

Files changed (61) hide show
  1. {rtc-tools-2.5.2rc4/src/rtc_tools.egg-info → rtc-tools-2.6.0}/PKG-INFO +2 -2
  2. rtc-tools-2.6.0/README.md +53 -0
  3. rtc-tools-2.6.0/pyproject.toml +22 -0
  4. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/setup.cfg +0 -6
  5. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/setup.py +28 -24
  6. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0/src/rtc_tools.egg-info}/PKG-INFO +2 -2
  7. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtc_tools.egg-info/SOURCES.txt +2 -0
  8. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtc_tools.egg-info/requires.txt +3 -3
  9. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/__init__.py +2 -1
  10. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/_internal/alias_tools.py +12 -10
  11. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/_internal/caching.py +5 -3
  12. rtc-tools-2.6.0/src/rtctools/_internal/casadi_helpers.py +55 -0
  13. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/_version.py +3 -3
  14. rtc-tools-2.6.0/src/rtctools/data/__init__.py +4 -0
  15. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/data/csv.py +54 -33
  16. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/data/interpolation/bspline.py +3 -3
  17. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/data/interpolation/bspline1d.py +42 -29
  18. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/data/interpolation/bspline2d.py +10 -4
  19. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/data/netcdf.py +137 -93
  20. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/data/pi.py +304 -210
  21. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/data/rtc.py +64 -53
  22. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/data/storage.py +91 -51
  23. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/collocated_integrated_optimization_problem.py +1244 -696
  24. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/control_tree_mixin.py +68 -66
  25. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/csv_lookup_table_mixin.py +107 -74
  26. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/csv_mixin.py +83 -52
  27. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/goal_programming_mixin.py +237 -146
  28. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/goal_programming_mixin_base.py +204 -111
  29. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/homotopy_mixin.py +36 -27
  30. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/initial_state_estimation_mixin.py +8 -8
  31. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/io_mixin.py +48 -43
  32. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/linearization_mixin.py +3 -1
  33. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/linearized_order_goal_programming_mixin.py +57 -28
  34. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/min_abs_goal_programming_mixin.py +72 -29
  35. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/modelica_mixin.py +135 -81
  36. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/netcdf_mixin.py +32 -18
  37. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/optimization_problem.py +181 -127
  38. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/pi_mixin.py +68 -36
  39. rtc-tools-2.6.0/src/rtctools/optimization/planning_mixin.py +19 -0
  40. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/single_pass_goal_programming_mixin.py +159 -112
  41. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/timeseries.py +4 -6
  42. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/rtctoolsapp.py +18 -18
  43. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/simulation/csv_mixin.py +37 -30
  44. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/simulation/io_mixin.py +9 -5
  45. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/simulation/pi_mixin.py +62 -32
  46. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/simulation/simulation_problem.py +471 -180
  47. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/util.py +84 -56
  48. rtc-tools-2.5.2rc4/README.md +0 -23
  49. rtc-tools-2.5.2rc4/src/rtctools/_internal/casadi_helpers.py +0 -76
  50. rtc-tools-2.5.2rc4/src/rtctools/data/__init__.py +0 -4
  51. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/COPYING.LESSER +0 -0
  52. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/MANIFEST.in +0 -0
  53. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtc_tools.egg-info/dependency_links.txt +0 -0
  54. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtc_tools.egg-info/entry_points.txt +0 -0
  55. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtc_tools.egg-info/top_level.txt +0 -0
  56. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/_internal/__init__.py +0 -0
  57. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/_internal/debug_check_helpers.py +1 -1
  58. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/data/interpolation/__init__.py +0 -0
  59. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/optimization/__init__.py +0 -0
  60. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/src/rtctools/simulation/__init__.py +0 -0
  61. {rtc-tools-2.5.2rc4 → rtc-tools-2.6.0}/versioneer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: rtc-tools
3
- Version: 2.5.2rc4
3
+ Version: 2.6.0
4
4
  Summary: Toolbox for control and optimization of water systems.
5
5
  Home-page: https://oss.deltares.nl/web/rtc-tools/home
6
6
  Author: Deltares
@@ -24,7 +24,7 @@ Classifier: Operating System :: Microsoft :: Windows
24
24
  Classifier: Operating System :: POSIX
25
25
  Classifier: Operating System :: Unix
26
26
  Classifier: Operating System :: MacOS
27
- Requires-Python: >=3.5
27
+ Requires-Python: >=3.8
28
28
  Provides-Extra: netcdf
29
29
  Provides-Extra: all
30
30
  License-File: COPYING.LESSER
@@ -0,0 +1,53 @@
1
+ # Deltares RTC-Tools
2
+
3
+ [![Pipeline](https://gitlab.com/deltares/rtc-tools/badges/master/pipeline.svg)](https://gitlab.com/deltares/rtc-tools/commits/master)
4
+ [![Coverage](https://codecov.io/gl/deltares/rtc-tools/branch/master/graph/badge.svg)](https://codecov.io/gl/deltares/rtc-tools)
5
+
6
+
7
+ RTC-Tools is an open-source Python package for simulation and optimization of cyber-physical systems. It can be used for model-predictive control and operational decision making of water and energy systems. It is developed and maintained by Deltares, in collaboration with partners.
8
+
9
+ RTC-Tools offers the following functionalities:
10
+
11
+ - **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.
12
+
13
+ RTC-Tools can be used with the following libraries and packages for specific applications:
14
+ - [rtc-tools-channel-flow](https://gitlab.com/deltares/rtc-tools-channel-flow): water system models
15
+ - [rtc-tools-hydraulic-structures](https://gitlab.com/deltares/rtc-tools-channel-flow): hydraulic assets, such as weirs and pumps
16
+ - [rtc-tools-heat-network](https://github.com/Nieuwe-Warmte-Nu/rtc-tools-heat-network): heat networks
17
+
18
+ Please note that this list is not exhaustive. Users can also create libraries for other types of applications.
19
+
20
+ - **Running simulations**: Simulate a given model.
21
+
22
+ - **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:
23
+
24
+ - **Linear, non-linear**: RTC-Tools supports both linear and non-linear optimization problems.
25
+
26
+ - **Continuous and discrete**: RTC-Tools can handle both continuous and discrete decision variables. This makes it suitable for optimizing systems with a mix of continuous controls (such as pump speeds or gate positions) and discrete decisions (such as on/off states of equipment).
27
+
28
+ - **Goal programming**: When multiple, and perhaps conflicting, objectives are to be considered (e.g., minimize operational costs while minimizing deviations of water levels from a given range), RTC-Tools offers two approaches to multi-objective optimization: The **Weighting Method**, which assigns weights to each objective and optimizes them simultaneously, and the **Lexicographic Goal Programming method**, which optimizes different objectives sequentially.
29
+
30
+ - **Optimization under uncertainty**: RTC-Tools supports the use of ensemble forecasts for optimization under uncertainty. To reduce the size of the optimization problem, ensemble members can be automatically aggregated using a scenario tree reduction method.
31
+
32
+ To streamline the integration with user interfaces and data management systems (such as Delft-FEWS), RTC-Tools supports CSV and XML file formats for reading/writing timeseries and other model parameters. Support for other formats can be implemented using mixins.
33
+
34
+ RTC-Tools uses [CasADi](https://web.casadi.org/) as a symbolic framework for algorithmic differentiation, as well as for interfacing with numerical optimization solvers.
35
+
36
+
37
+ ## Install
38
+
39
+ ```bash
40
+ pip install rtc-tools
41
+ ```
42
+
43
+ ## Documentation
44
+
45
+ Documentation and examples can be found on [readthedocs](https://rtc-tools.readthedocs.io).
46
+
47
+
48
+ ## License
49
+ RTC-Tools is licensed under the **[GNU Lesser General Public License v3.0](https://gitlab.com/deltares/rtc-tools/-/blob/guidelines_contributions/COPYING)**, and can be used free of charge. Deltares offers support packages for users who require assistance.
50
+
51
+
52
+ ## Acknowledgment
53
+ If you use RTC-Tools in your work, please acknowledge it in any resulting publications. You can do this by citing RTC-Tools and providing a link to our [website](https://oss.deltares.nl/web/rtc-tools/home) or [Gitlab repository](https://gitlab.com/deltares/rtc-tools).
@@ -0,0 +1,22 @@
1
+ [tool.black]
2
+ line-length = 100
3
+ target-version = ['py38', 'py39', 'py310', 'py311']
4
+ exclude = '''
5
+ (
6
+ src/rtctools/_version.py
7
+ )
8
+ '''
9
+
10
+ [tool.ruff]
11
+ ignore = [
12
+ "B904", # Fix someday: raising exceptions within except
13
+ ]
14
+ line-length = 100
15
+ select = [
16
+ "B", # flake8-bugbear
17
+ "C4", # flake8-comprehensions
18
+ "E", # default / pycodestyle
19
+ "F", # default / pyflakes
20
+ "I", # isort
21
+ "W", # pycodestyle
22
+ ]
@@ -12,12 +12,6 @@ versionfile_build = rtctools/_version.py
12
12
  tag_prefix =
13
13
  parentdir_prefix = rtctools-
14
14
 
15
- [flake8]
16
- max-line-length = 120
17
- exclude =
18
- src/rtctools/_version.py
19
- src/rtctools/data/interpolation/__init__.py
20
-
21
15
  [egg_info]
22
16
  tag_build =
23
17
  tag_date = 0
@@ -3,12 +3,14 @@
3
3
  RTC-Tools is the Deltares toolbox for control and optimization of water systems.
4
4
 
5
5
  """
6
- from setuptools import setup, find_packages
7
- import versioneer
8
6
  import sys
9
7
 
10
- if sys.version_info < (3, 5):
11
- sys.exit("Sorry, Python 3.5 or newer is required.")
8
+ from setuptools import find_packages, setup
9
+
10
+ import versioneer
11
+
12
+ if sys.version_info < (3, 8):
13
+ sys.exit("Sorry, Python 3.8 or newer is required.")
12
14
 
13
15
  DOCLINES = __doc__.split("\n")
14
16
 
@@ -29,34 +31,36 @@ Operating System :: MacOS
29
31
  """
30
32
 
31
33
  setup(
32
- name='rtc-tools',
34
+ name="rtc-tools",
33
35
  version=versioneer.get_version(),
34
- maintainer='Deltares',
35
- author='Deltares',
36
+ maintainer="Deltares",
37
+ author="Deltares",
36
38
  description=DOCLINES[0],
37
- long_description='\n'.join(DOCLINES[2:]),
38
- url='https://oss.deltares.nl/web/rtc-tools/home',
39
- download_url='http://gitlab.com/deltares/rtc-tools/',
40
- classifiers=[_f for _f in CLASSIFIERS.split('\n') if _f],
41
- platforms=['Windows', 'Linux', 'Mac OS-X', 'Unix'],
39
+ long_description="\n".join(DOCLINES[2:]),
40
+ url="https://oss.deltares.nl/web/rtc-tools/home",
41
+ download_url="http://gitlab.com/deltares/rtc-tools/",
42
+ classifiers=[_f for _f in CLASSIFIERS.split("\n") if _f],
43
+ platforms=["Windows", "Linux", "Mac OS-X", "Unix"],
42
44
  packages=find_packages("src"),
43
45
  package_dir={"": "src"},
44
- install_requires=["casadi == 3.5.*",
45
- "numpy >= 1.16.0, <1.23",
46
- "scipy >= 1.0.0, <1.11",
47
- "pymoca == 0.9.*",
48
- "rtc-tools-channel-flow >= 1.1.0"],
49
- tests_require=['pytest', 'pytest-runner'],
46
+ install_requires=[
47
+ "casadi >= 3.6.3, == 3.6.*",
48
+ "numpy >= 1.16.0, <1.26",
49
+ "scipy >= 1.0.0, <1.11",
50
+ "pymoca == 0.9.1",
51
+ "rtc-tools-channel-flow >= 1.1.0",
52
+ ],
53
+ tests_require=["pytest", "pytest-runner", "netCDF4"],
50
54
  extras_require={
51
- 'netcdf': ["netCDF4"],
52
- 'all': ["netCDF4"],
55
+ "netcdf": ["netCDF4"],
56
+ "all": ["netCDF4"],
53
57
  },
54
- python_requires='>=3.5',
58
+ python_requires=">=3.8",
55
59
  cmdclass=versioneer.get_cmdclass(),
56
60
  entry_points={
57
- 'console_scripts': [
58
- 'rtc-tools-download-examples = rtctools.rtctoolsapp:download_examples',
59
- 'rtc-tools-copy-libraries = rtctools.rtctoolsapp:copy_libraries',
61
+ "console_scripts": [
62
+ "rtc-tools-download-examples = rtctools.rtctoolsapp:download_examples",
63
+ "rtc-tools-copy-libraries = rtctools.rtctoolsapp:copy_libraries",
60
64
  ]
61
65
  },
62
66
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: rtc-tools
3
- Version: 2.5.2rc4
3
+ Version: 2.6.0
4
4
  Summary: Toolbox for control and optimization of water systems.
5
5
  Home-page: https://oss.deltares.nl/web/rtc-tools/home
6
6
  Author: Deltares
@@ -24,7 +24,7 @@ Classifier: Operating System :: Microsoft :: Windows
24
24
  Classifier: Operating System :: POSIX
25
25
  Classifier: Operating System :: Unix
26
26
  Classifier: Operating System :: MacOS
27
- Requires-Python: >=3.5
27
+ Requires-Python: >=3.8
28
28
  Provides-Extra: netcdf
29
29
  Provides-Extra: all
30
30
  License-File: COPYING.LESSER
@@ -1,6 +1,7 @@
1
1
  COPYING.LESSER
2
2
  MANIFEST.in
3
3
  README.md
4
+ pyproject.toml
4
5
  setup.cfg
5
6
  setup.py
6
7
  versioneer.py
@@ -46,6 +47,7 @@ src/rtctools/optimization/modelica_mixin.py
46
47
  src/rtctools/optimization/netcdf_mixin.py
47
48
  src/rtctools/optimization/optimization_problem.py
48
49
  src/rtctools/optimization/pi_mixin.py
50
+ src/rtctools/optimization/planning_mixin.py
49
51
  src/rtctools/optimization/single_pass_goal_programming_mixin.py
50
52
  src/rtctools/optimization/timeseries.py
51
53
  src/rtctools/simulation/__init__.py
@@ -1,7 +1,7 @@
1
- casadi==3.5.*
2
- numpy<1.23,>=1.16.0
1
+ casadi==3.6.*,>=3.6.3
2
+ numpy<1.26,>=1.16.0
3
3
  scipy<1.11,>=1.0.0
4
- pymoca==0.9.*
4
+ pymoca==0.9.1
5
5
  rtc-tools-channel-flow>=1.1.0
6
6
 
7
7
  [all]
@@ -1,4 +1,5 @@
1
1
  # Get version
2
2
  from ._version import get_versions
3
- __version__ = get_versions()['version']
3
+
4
+ __version__ = get_versions()["version"]
4
5
  del get_versions
@@ -13,8 +13,8 @@ class OrderedSet(MutableSet):
13
13
 
14
14
  def __init__(self, iterable=None):
15
15
  self.end = end = []
16
- end += [None, end, end] # sentinel node for doubly linked list
17
- self.map = {} # key --> [key, prev, next]
16
+ end += [None, end, end] # sentinel node for doubly linked list
17
+ self.map = {} # key --> [key, prev, next]
18
18
  if iterable is not None:
19
19
  self |= iterable
20
20
 
@@ -25,11 +25,11 @@ class OrderedSet(MutableSet):
25
25
  return key in self.map
26
26
 
27
27
  def __getstate__(self):
28
- """ Avoids max depth RecursionError when using pickle """
28
+ """Avoids max depth RecursionError when using pickle"""
29
29
  return list(self)
30
30
 
31
31
  def __setstate__(self, state):
32
- """ Tells pickle how to restore instance """
32
+ """Tells pickle how to restore instance"""
33
33
  self.__init__(state)
34
34
 
35
35
  def __getitem__(self, index):
@@ -45,7 +45,7 @@ class OrderedSet(MutableSet):
45
45
  return curr[0]
46
46
  curr = curr[2]
47
47
  i += 1
48
- raise IndexError('set index {} out of range with length {}'.format(index, len(self)))
48
+ raise IndexError("set index {} out of range with length {}".format(index, len(self)))
49
49
 
50
50
  def add(self, key):
51
51
  if key not in self.map:
@@ -75,25 +75,27 @@ class OrderedSet(MutableSet):
75
75
 
76
76
  def pop(self, last=True):
77
77
  if not self:
78
- raise KeyError('set is empty')
78
+ raise KeyError("set is empty")
79
79
  key = self.end[1][0] if last else self.end[2][0]
80
80
  self.discard(key)
81
81
  return key
82
82
 
83
83
  def __repr__(self):
84
84
  if not self:
85
- return '%s()' % (self.__class__.__name__,)
86
- return '%s(%r)' % (self.__class__.__name__, list(self))
85
+ return "%s()" % (self.__class__.__name__,)
86
+ return "%s(%r)" % (self.__class__.__name__, list(self))
87
87
 
88
88
  def __eq__(self, other):
89
89
  if isinstance(other, OrderedSet):
90
90
  return len(self) == len(other) and list(self) == list(other)
91
91
  return set(self) == set(other)
92
+
93
+
92
94
  # End snippet
93
95
 
94
96
 
95
- KT = TypeVar('KT')
96
- VT = TypeVar('VT')
97
+ KT = TypeVar("KT")
98
+ VT = TypeVar("VT")
97
99
 
98
100
 
99
101
  class AliasDict(Generic[KT, VT]):
@@ -5,14 +5,15 @@ def cached(f):
5
5
  return f(self, ensemble_member)
6
6
  else:
7
7
  return f(self)
8
+
8
9
  # Add a check so that caching is applied to the 'toplevel'
9
10
  # method implementation in the class hierarchy only.
10
- call_in_progress = '__' + f.__name__ + '_in_progress'
11
+ call_in_progress = "__" + f.__name__ + "_in_progress"
11
12
  if hasattr(self, call_in_progress):
12
13
  return call()
13
- cache_name = '__' + f.__name__
14
+ cache_name = "__" + f.__name__
14
15
  if ensemble_member is not None:
15
- cache_name = '{}[{}]'.format(cache_name, ensemble_member)
16
+ cache_name = "{}[{}]".format(cache_name, ensemble_member)
16
17
  if hasattr(self, cache_name):
17
18
  return getattr(self, cache_name)
18
19
  setattr(self, call_in_progress, True)
@@ -20,4 +21,5 @@ def cached(f):
20
21
  setattr(self, cache_name, value)
21
22
  delattr(self, call_in_progress)
22
23
  return value
24
+
23
25
  return wrapper
@@ -0,0 +1,55 @@
1
+ import logging
2
+
3
+ import casadi as ca
4
+
5
+ logger = logging.getLogger("rtctools")
6
+
7
+
8
+ def is_affine(e, v):
9
+ try:
10
+ Af = ca.Function("f", [v], [ca.jacobian(e, v)]).expand()
11
+ except RuntimeError as e:
12
+ if "'eval_sx' not defined for" in str(e):
13
+ Af = ca.Function("f", [v], [ca.jacobian(e, v)])
14
+ else:
15
+ raise
16
+ return Af.sparsity_jac(0, 0).nnz() == 0
17
+
18
+
19
+ def nullvertcat(*L):
20
+ """
21
+ Like vertcat, but creates an MX with consistent dimensions even if L is empty.
22
+ """
23
+ if len(L) == 0:
24
+ return ca.DM(0, 1)
25
+ else:
26
+ return ca.vertcat(*L)
27
+
28
+
29
+ def reduce_matvec(e, v):
30
+ """
31
+ Reduces the MX graph e of linear operations on p into a matrix-vector product.
32
+
33
+ This reduces the number of nodes required to represent the linear operations.
34
+ """
35
+ Af = ca.Function("Af", [ca.MX()], [ca.jacobian(e, v)])
36
+ A = Af(ca.DM())
37
+ return ca.reshape(ca.mtimes(A, v), e.shape)
38
+
39
+
40
+ def substitute_in_external(expr, symbols, values):
41
+ if len(symbols) == 0 or all(isinstance(x, ca.DM) for x in expr):
42
+ return expr
43
+ else:
44
+ f = ca.Function("f", symbols, expr)
45
+ return f.call(values, True, False)
46
+
47
+
48
+ def interpolate(ts, xs, t, equidistant, mode=0):
49
+ if mode == 0:
50
+ mode_str = "linear"
51
+ elif mode == 1:
52
+ mode_str = "floor"
53
+ else:
54
+ mode_str = "ceil"
55
+ return ca.interp1d(ts, xs, t, mode_str, equidistant)
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2023-07-25T11:51:05+0200",
11
+ "date": "2024-01-30T12:56:46+0000",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "9fc120016a7880faa74859883466fade1d15ca08",
15
- "version": "2.5.2rc4"
14
+ "full-revisionid": "7f078d793396303774d150ae5ebabb7534420ace",
15
+ "version": "2.6.0"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -0,0 +1,4 @@
1
+ import xml.etree.ElementTree as ET
2
+
3
+ ET.register_namespace("fews", "http://www.wldelft.nl/fews")
4
+ ET.register_namespace("pi", "http://www.wldelft.nl/fews/PI")
@@ -22,15 +22,18 @@ def _boolean_to_nan(data, fname):
22
22
  convert_to_nan = []
23
23
  dtypes_out = []
24
24
  for i, name in enumerate(data.dtype.names):
25
- if dtypes_in[i][1][1] == 'b':
25
+ if dtypes_in[i][1][1] == "b":
26
26
  convert_to_nan.append(name)
27
- dtypes_out.append((dtypes_in[i][0], '<f8'))
27
+ dtypes_out.append((dtypes_in[i][0], "<f8"))
28
28
  else:
29
29
  dtypes_out.append(dtypes_in[i])
30
30
 
31
31
  if convert_to_nan:
32
- logger.warning("Column(s) {} were detected as boolean in '{}'; converting to NaN".format(
33
- ", ".join(["'{}'".format(name) for name in convert_to_nan]), fname))
32
+ logger.warning(
33
+ "Column(s) {} were detected as boolean in '{}'; converting to NaN".format(
34
+ ", ".join(["'{}'".format(name) for name in convert_to_nan]), fname
35
+ )
36
+ )
34
37
  data = data.astype(dtypes_out)
35
38
  for name in convert_to_nan:
36
39
  data[name] = np.nan
@@ -38,7 +41,7 @@ def _boolean_to_nan(data, fname):
38
41
  return data
39
42
 
40
43
 
41
- def load(fname, delimiter=',', with_time=False):
44
+ def load(fname, delimiter=",", with_time=False):
42
45
  """
43
46
  Check delimiter of csv and read contents to an array. Assumes no date-time conversion needed.
44
47
 
@@ -50,56 +53,68 @@ def load(fname, delimiter=',', with_time=False):
50
53
  """
51
54
  c = {}
52
55
  if with_time:
53
- c.update({0: lambda str: datetime.strptime(
54
- str.decode("utf-8"), '%Y-%m-%d %H:%M:%S')})
56
+ c.update({0: lambda str: datetime.strptime(str.decode("utf-8"), "%Y-%m-%d %H:%M:%S")})
55
57
 
56
58
  # Check delimiter of csv file. If semicolon, check if decimal separator is
57
59
  # a comma.
58
- if delimiter == ';':
59
- with open(fname, 'rb') as csvfile:
60
+ if delimiter == ";":
61
+ with open(fname, "rb") as csvfile:
60
62
  # Read the first line, this should be a header. Count columns by
61
63
  # counting separator.
62
64
  sample_csvfile = csvfile.readline()
63
- n_semicolon = sample_csvfile.count(b';')
64
- # We actually only need one number to evaluate if commas are used as decimal separator, but
65
- # certain csv writers don't use a decimal when the value has no meaningful decimal
66
- # (e.g. 12.0 becomes 12) so we read the next 1024 bytes to make sure we catch a number.
65
+ n_semicolon = sample_csvfile.count(b";")
66
+ # We actually only need one number to evaluate if commas are used as decimal
67
+ # separator, but certain csv writers don't use a decimal when the value has
68
+ # no meaningful decimal(e.g. 12.0 becomes 12) so we read the next 1024 bytes
69
+ # to make sure we catch a number.
67
70
  sample_csvfile = csvfile.read(1024)
68
71
  # Count the commas
69
- n_comma_decimal = sample_csvfile.count(b',')
72
+ n_comma_decimal = sample_csvfile.count(b",")
70
73
  # If commas are used as decimal separator, we need additional
71
74
  # converters.
72
75
  if n_comma_decimal:
73
- c.update({i + len(c): lambda str: float(str.decode("utf-8").replace(',', '.'))
74
- for i in range(1 + n_semicolon - len(c))})
76
+ c.update(
77
+ {
78
+ i + len(c): lambda str: float(str.decode("utf-8").replace(",", "."))
79
+ for i in range(1 + n_semicolon - len(c))
80
+ }
81
+ )
75
82
 
76
83
  # Read the csv file and convert to array
77
84
  try:
78
85
  if len(c): # Converters exist, so use them.
79
86
  try:
80
- data = np.genfromtxt(fname, delimiter=delimiter, deletechars='', dtype=None, names=True, converters=c)
87
+ data = np.genfromtxt(
88
+ fname, delimiter=delimiter, deletechars="", dtype=None, names=True, converters=c
89
+ )
81
90
  return _boolean_to_nan(data, fname)
82
- except np.lib._iotools.ConverterError: # value does not conform to expected date-time format
91
+ except (
92
+ np.lib._iotools.ConverterError
93
+ ): # value does not conform to expected date-time format
83
94
  type, value, traceback = sys.exc_info()
84
95
  logger.error(
85
- 'CSVMixin: converter of csv reader failed on {}: {}'.format(fname, value))
96
+ "CSVMixin: converter of csv reader failed on {}: {}".format(fname, value)
97
+ )
86
98
  raise ValueError(
87
- 'CSVMixin: wrong date time or value format in {}. '
88
- 'Should be %Y-%m-%d %H:%M:%S and numerical values everywhere.'.format(fname))
99
+ "CSVMixin: wrong date time or value format in {}. "
100
+ "Should be %Y-%m-%d %H:%M:%S and numerical values everywhere.".format(fname)
101
+ )
89
102
  else:
90
- data = np.genfromtxt(fname, delimiter=delimiter, deletechars='', dtype=None, names=True)
103
+ data = np.genfromtxt(fname, delimiter=delimiter, deletechars="", dtype=None, names=True)
91
104
  return _boolean_to_nan(data, fname)
92
- except ValueError: # can occur when delimiter changes after first 1024 bytes of file, or delimiter is not , or ;
105
+ except ValueError:
106
+ # can occur when delimiter changes after first 1024 bytes of file,
107
+ # or delimiter is not , or ;
93
108
  type, value, traceback = sys.exc_info()
94
- logger.error(
95
- 'CSV: Value reader of csv reader failed on {}: {}'.format(fname, value))
109
+ logger.error("CSV: Value reader of csv reader failed on {}: {}".format(fname, value))
96
110
  raise ValueError(
97
111
  "CSV: could not read all values from {}. Used delimiter '{}'. "
98
112
  "Please check delimiter (should be ',' or ';' throughout the file) "
99
- "and if all values are numbers.".format(fname, delimiter))
113
+ "and if all values are numbers.".format(fname, delimiter)
114
+ )
100
115
 
101
116
 
102
- def save(fname, data, delimiter=',', with_time=False):
117
+ def save(fname, data, delimiter=",", with_time=False):
103
118
  """
104
119
  Write the contents of an array to a csv file.
105
120
 
@@ -109,10 +124,16 @@ def save(fname, data, delimiter=',', with_time=False):
109
124
  :param with_time: Whether to output the first column of the data as time stamps.
110
125
  """
111
126
  if with_time:
112
- data['time'] = [t.strftime("%Y-%m-%d %H:%M:%S") for t in data['time']]
113
- fmt = ['%s'] + (len(data.dtype.names) - 1) * ['%f']
127
+ data["time"] = [t.strftime("%Y-%m-%d %H:%M:%S") for t in data["time"]]
128
+ fmt = ["%s"] + (len(data.dtype.names) - 1) * ["%f"]
114
129
  else:
115
- fmt = len(data.dtype.names) * ['%f']
116
-
117
- np.savetxt(fname, data, delimiter=delimiter, header=delimiter.join(
118
- data.dtype.names), fmt=fmt, comments='')
130
+ fmt = len(data.dtype.names) * ["%f"]
131
+
132
+ np.savetxt(
133
+ fname,
134
+ data,
135
+ delimiter=delimiter,
136
+ header=delimiter.join(data.dtype.names),
137
+ fmt=fmt,
138
+ comments="",
139
+ )
@@ -14,7 +14,8 @@ class BSpline:
14
14
  :param k: Order of the basis function.
15
15
  :param i: Knot number.
16
16
 
17
- :returns: The B-Spline basis function of the given order, at the given knot, evaluated at the given point.
17
+ :returns: The B-Spline basis function of the given order, at the given knot, evaluated at
18
+ the given point.
18
19
  """
19
20
  if k == 0:
20
21
  return if_else(logic_and(t[i] <= x, x < t[i + 1]), 1.0, 0.0)
@@ -24,8 +25,7 @@ class BSpline:
24
25
  else:
25
26
  a = 0.0
26
27
  if t[i + 1] < t[i + k + 1]:
27
- b = (t[i + k + 1] - x) / (t[i + k + 1] - t[i + 1]) * \
28
- self.basis(t, x, k - 1, i + 1)
28
+ b = (t[i + k + 1] - x) / (t[i + k + 1] - t[i + 1]) * self.basis(t, x, k - 1, i + 1)
29
29
  else:
30
30
  b = 0.0
31
31
  return a + b