rtc-tools 2.7.0a3__py3-none-any.whl → 2.7.0b1__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.
- {rtc_tools-2.7.0a3.dist-info → rtc_tools-2.7.0b1.dist-info}/METADATA +26 -16
- {rtc_tools-2.7.0a3.dist-info → rtc_tools-2.7.0b1.dist-info}/RECORD +24 -24
- {rtc_tools-2.7.0a3.dist-info → rtc_tools-2.7.0b1.dist-info}/WHEEL +1 -1
- {rtc_tools-2.7.0a3.dist-info → rtc_tools-2.7.0b1.dist-info}/entry_points.txt +0 -1
- rtctools/_internal/casadi_helpers.py +5 -5
- rtctools/_version.py +4 -4
- rtctools/data/csv.py +18 -7
- rtctools/data/interpolation/bspline1d.py +5 -1
- rtctools/data/netcdf.py +16 -15
- rtctools/data/pi.py +17 -17
- rtctools/data/rtc.py +3 -3
- rtctools/optimization/collocated_integrated_optimization_problem.py +10 -11
- rtctools/optimization/csv_lookup_table_mixin.py +4 -3
- rtctools/optimization/csv_mixin.py +3 -0
- rtctools/optimization/goal_programming_mixin.py +11 -2
- rtctools/optimization/goal_programming_mixin_base.py +5 -3
- rtctools/optimization/modelica_mixin.py +15 -7
- rtctools/optimization/pi_mixin.py +3 -3
- rtctools/rtctoolsapp.py +12 -10
- rtctools/simulation/io_mixin.py +1 -1
- rtctools/simulation/pi_mixin.py +3 -3
- rtctools/simulation/simulation_problem.py +25 -12
- {rtc_tools-2.7.0a3.dist-info → rtc_tools-2.7.0b1.dist-info/licenses}/COPYING.LESSER +0 -0
- {rtc_tools-2.7.0a3.dist-info → rtc_tools-2.7.0b1.dist-info}/top_level.txt +0 -0
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: rtc-tools
|
|
3
|
-
Version: 2.7.
|
|
3
|
+
Version: 2.7.0b1
|
|
4
4
|
Summary: Toolbox for control and optimization of water systems.
|
|
5
5
|
Home-page: https://oss.deltares.nl/web/rtc-tools/home
|
|
6
|
+
Download-URL: http://github.com/deltares/rtc-tools/
|
|
6
7
|
Author: Deltares
|
|
7
8
|
Maintainer: Deltares
|
|
8
|
-
License: UNKNOWN
|
|
9
|
-
Download-URL: http://gitlab.com/deltares/rtc-tools/
|
|
10
9
|
Platform: Windows
|
|
11
10
|
Platform: Linux
|
|
12
11
|
Platform: Mac OS-X
|
|
@@ -24,20 +23,31 @@ Classifier: Operating System :: Microsoft :: Windows
|
|
|
24
23
|
Classifier: Operating System :: POSIX
|
|
25
24
|
Classifier: Operating System :: Unix
|
|
26
25
|
Classifier: Operating System :: MacOS
|
|
27
|
-
Requires-Python: >=3.
|
|
26
|
+
Requires-Python: >=3.9
|
|
28
27
|
License-File: COPYING.LESSER
|
|
29
|
-
Requires-Dist: casadi
|
|
30
|
-
Requires-Dist: numpy
|
|
31
|
-
Requires-Dist: scipy
|
|
32
|
-
Requires-Dist: pymoca
|
|
33
|
-
Requires-Dist: rtc-tools-channel-flow
|
|
34
|
-
Requires-Dist: defusedxml
|
|
35
|
-
|
|
36
|
-
Requires-Dist: netCDF4 ; extra == 'all'
|
|
28
|
+
Requires-Dist: casadi!=3.6.6,==3.6.*,>=3.6.3
|
|
29
|
+
Requires-Dist: numpy>=1.16.0
|
|
30
|
+
Requires-Dist: scipy>=1.0.0
|
|
31
|
+
Requires-Dist: pymoca==0.9.*,>=0.9.1
|
|
32
|
+
Requires-Dist: rtc-tools-channel-flow>=1.2.0
|
|
33
|
+
Requires-Dist: defusedxml>=0.7.0
|
|
34
|
+
Requires-Dist: importlib_metadata>=5.0.0; python_version < "3.10"
|
|
37
35
|
Provides-Extra: netcdf
|
|
38
|
-
Requires-Dist: netCDF4
|
|
36
|
+
Requires-Dist: netCDF4; extra == "netcdf"
|
|
37
|
+
Provides-Extra: all
|
|
38
|
+
Requires-Dist: netCDF4; extra == "all"
|
|
39
|
+
Dynamic: author
|
|
40
|
+
Dynamic: classifier
|
|
41
|
+
Dynamic: description
|
|
42
|
+
Dynamic: download-url
|
|
43
|
+
Dynamic: home-page
|
|
44
|
+
Dynamic: license-file
|
|
45
|
+
Dynamic: maintainer
|
|
46
|
+
Dynamic: platform
|
|
47
|
+
Dynamic: provides-extra
|
|
48
|
+
Dynamic: requires-dist
|
|
49
|
+
Dynamic: requires-python
|
|
50
|
+
Dynamic: summary
|
|
39
51
|
|
|
40
52
|
RTC-Tools is the Deltares toolbox for control and optimization of water systems.
|
|
41
53
|
|
|
42
|
-
|
|
43
|
-
|
|
@@ -1,50 +1,50 @@
|
|
|
1
|
+
rtc_tools-2.7.0b1.dist-info/licenses/COPYING.LESSER,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
|
|
1
2
|
rtctools/__init__.py,sha256=91hvS2-ryd2Pvw0COpsUzTwJwSnTZ035REiej-1hNI4,107
|
|
2
|
-
rtctools/_version.py,sha256=
|
|
3
|
-
rtctools/rtctoolsapp.py,sha256=
|
|
3
|
+
rtctools/_version.py,sha256=qpi8lYqShCC9PmcMx5KMwsdJ9rzUpVeHLRvr9yxv_9E,499
|
|
4
|
+
rtctools/rtctoolsapp.py,sha256=VvoOgpu1R5vzaQsUzBjyB4uPenMv2yWukcA6N9KDEr8,4275
|
|
4
5
|
rtctools/util.py,sha256=PaeKfDUA174ODZbY5fZjCTf-F-TdhW7yEuP189Ro190,9075
|
|
5
6
|
rtctools/_internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
7
|
rtctools/_internal/alias_tools.py,sha256=XuQSAhhFuVtwn0yrAObZWIKPsSF4j2axXRtEmitIFPs,5310
|
|
7
8
|
rtctools/_internal/caching.py,sha256=p4gqSL7kCI7Hff-KjMEP7mhJCQSiU_lYm2MR7E18gBM,905
|
|
8
|
-
rtctools/_internal/casadi_helpers.py,sha256=
|
|
9
|
+
rtctools/_internal/casadi_helpers.py,sha256=q8j5h9XXXkZMUgjg6wbkcFj1mcHi5_SdEi8SrkM---M,1457
|
|
9
10
|
rtctools/_internal/debug_check_helpers.py,sha256=UgQTEPw4PyR7MbYLewSSWQqTwQj7xr5yUBk820O9Kk4,1084
|
|
10
11
|
rtctools/data/__init__.py,sha256=EllgSmCdrlvQZSd1VilvjPaeYJGhY9ErPiQtedmuFoA,157
|
|
11
|
-
rtctools/data/csv.py,sha256=
|
|
12
|
-
rtctools/data/netcdf.py,sha256=
|
|
13
|
-
rtctools/data/pi.py,sha256=
|
|
14
|
-
rtctools/data/rtc.py,sha256=
|
|
12
|
+
rtctools/data/csv.py,sha256=hEpoTH3nhZaAvRN4r-9-nYeAjaFiNDRoiZWg8GxM3yo,5539
|
|
13
|
+
rtctools/data/netcdf.py,sha256=tMs-zcSlOR0HhajUKJVbXGNoi3GeKCM3X4DjuW8FDo8,19130
|
|
14
|
+
rtctools/data/pi.py,sha256=D2r9gaYu6qMpgWRqiWpWPSPJXWgqCVV0bz6ewgM78mc,46701
|
|
15
|
+
rtctools/data/rtc.py,sha256=tYPOzZSFE02bAXX3lgcGR1saoQNIv6oWVWH8CS0dl5Q,9079
|
|
15
16
|
rtctools/data/storage.py,sha256=67J4BRTl0AMEzlKNZ8Xdpy_4cGtwx8Lo_tL2n0G4S9w,13206
|
|
16
17
|
rtctools/data/interpolation/__init__.py,sha256=GBubCIT5mFoSTV-lOk7cpwvZekNMEe5bvqSQJ9HE34M,73
|
|
17
18
|
rtctools/data/interpolation/bspline.py,sha256=qevB842XWCH3fWlWMBqKMy1mw37ust-0YtSnb9PKCEc,948
|
|
18
|
-
rtctools/data/interpolation/bspline1d.py,sha256=
|
|
19
|
+
rtctools/data/interpolation/bspline1d.py,sha256=HAh7m5xLBuiFKzMzuYEqZX_GmCPChKjV7ynTS6iRZOc,6166
|
|
19
20
|
rtctools/data/interpolation/bspline2d.py,sha256=ScmX0fPDxbUVtj3pbUE0L7UJocqroD_6fUT-4cvdRMc,1693
|
|
20
21
|
rtctools/optimization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
-
rtctools/optimization/collocated_integrated_optimization_problem.py,sha256=
|
|
22
|
+
rtctools/optimization/collocated_integrated_optimization_problem.py,sha256=qr_Ii_K71zzX48cDwYFD37QpQsh5CsBBiC88uroIEqI,131270
|
|
22
23
|
rtctools/optimization/control_tree_mixin.py,sha256=CC6TWp3kFQgMokx6213pRLx9iY17Fd0VcwG4Wpwa0Uo,8974
|
|
23
|
-
rtctools/optimization/csv_lookup_table_mixin.py,sha256=
|
|
24
|
-
rtctools/optimization/csv_mixin.py,sha256=
|
|
25
|
-
rtctools/optimization/goal_programming_mixin.py,sha256=
|
|
26
|
-
rtctools/optimization/goal_programming_mixin_base.py,sha256=
|
|
24
|
+
rtctools/optimization/csv_lookup_table_mixin.py,sha256=JUAwYiOd0FPh-jLmPkfeT2i_3j8VLuBfi3i5UtwfVoU,17325
|
|
25
|
+
rtctools/optimization/csv_mixin.py,sha256=_6iPVK_EJ8PxnukepzkhFtidceucsozRML_DDEycYik,12453
|
|
26
|
+
rtctools/optimization/goal_programming_mixin.py,sha256=vdnKnz1Ov3OFN-J9KQiiAwHbrLjWH6o_PeZz2YfLz6k,33320
|
|
27
|
+
rtctools/optimization/goal_programming_mixin_base.py,sha256=qJQQcJlJdio4GTcrKfuBi6Nho9u16pDuuprzK0LUyhA,43835
|
|
27
28
|
rtctools/optimization/homotopy_mixin.py,sha256=Kh0kMfxB-Fo1FBGW5tPOQk24Xx_Mmw_p0YuSQotdkMU,6905
|
|
28
29
|
rtctools/optimization/initial_state_estimation_mixin.py,sha256=74QYfG-VYYTNVg-kAnCG6QoY3_sUmaID0ideF7bPkkY,3116
|
|
29
30
|
rtctools/optimization/io_mixin.py,sha256=AsZQ7YOUcUbWoczmjTXaSje5MUEsPNbQyZBJ6qzSjzU,11821
|
|
30
31
|
rtctools/optimization/linearization_mixin.py,sha256=mG5S7uwvwDydw-eBPyQKnLyKoy08EBjQh25vu97afhY,1049
|
|
31
32
|
rtctools/optimization/linearized_order_goal_programming_mixin.py,sha256=LQ2qpYt0YGLpEoerif4FJ5wwzq16q--27bsRjcqIU5A,9087
|
|
32
33
|
rtctools/optimization/min_abs_goal_programming_mixin.py,sha256=WMOv9EF8cfDJgTunzXfI_cUmBSQK26u1HJB_9EAarfM,14031
|
|
33
|
-
rtctools/optimization/modelica_mixin.py,sha256=
|
|
34
|
+
rtctools/optimization/modelica_mixin.py,sha256=b_VsEcg_VsAnODnTQybrY0GbuZUNQ3uugQmML6FlklE,18037
|
|
34
35
|
rtctools/optimization/netcdf_mixin.py,sha256=-zkXh3sMYE50c3kHsrmUVGWMSFm-0cXQpGrCm0yn-Tc,7563
|
|
35
36
|
rtctools/optimization/optimization_problem.py,sha256=qzpc81NaZMeoXKuayFmBF15iXYuNAk5yxmaER_Gcz_A,44131
|
|
36
|
-
rtctools/optimization/pi_mixin.py,sha256=
|
|
37
|
+
rtctools/optimization/pi_mixin.py,sha256=G_6RPlXO-IOjqYxNsMZGY4fmnfxVpwN-_T5Ka3rDwK4,11788
|
|
37
38
|
rtctools/optimization/planning_mixin.py,sha256=O_Y74X8xZmaNZR4iYOe7BR06s9hnmcapbuHYHQTBPPQ,724
|
|
38
39
|
rtctools/optimization/single_pass_goal_programming_mixin.py,sha256=Zb9szg3PGT2o6gkGsXluSfEaAswkw3TKfPQDzUrj_Y4,25784
|
|
39
40
|
rtctools/optimization/timeseries.py,sha256=nCrsGCJThBMh9lvngEpbBDa834_QvklVvkxJqwX4a1M,1734
|
|
40
41
|
rtctools/simulation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
41
42
|
rtctools/simulation/csv_mixin.py,sha256=rGDUFPsqGHmF0_dWdXeWzWzMpkPmwCNweTBVrwSh31g,6704
|
|
42
|
-
rtctools/simulation/io_mixin.py,sha256=
|
|
43
|
-
rtctools/simulation/pi_mixin.py,sha256=
|
|
44
|
-
rtctools/simulation/simulation_problem.py,sha256=
|
|
45
|
-
rtc_tools-2.7.
|
|
46
|
-
rtc_tools-2.7.
|
|
47
|
-
rtc_tools-2.7.
|
|
48
|
-
rtc_tools-2.7.
|
|
49
|
-
rtc_tools-2.7.
|
|
50
|
-
rtc_tools-2.7.0a3.dist-info/RECORD,,
|
|
43
|
+
rtctools/simulation/io_mixin.py,sha256=WIKOQxr3fS-aNbgjet9iWoUayuD22zLIYmqlWEqxXHo,6215
|
|
44
|
+
rtctools/simulation/pi_mixin.py,sha256=_TU2DrK2MQqVsyrHBD9W4SDEuot9dYmgTDNiXkDAJfk,9833
|
|
45
|
+
rtctools/simulation/simulation_problem.py,sha256=v5Lk2x-yuVb5s7ne5fFgxONxGniLHTyTR0XRzYRl1fw,50005
|
|
46
|
+
rtc_tools-2.7.0b1.dist-info/METADATA,sha256=8hM5-9gf_vYP6z514La_JRMsPIbT5qIhSxSTUgKc-Jc,1776
|
|
47
|
+
rtc_tools-2.7.0b1.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
48
|
+
rtc_tools-2.7.0b1.dist-info/entry_points.txt,sha256=DVS8sWf3b9ph9h8srEr6zmQ7ZKGwblwgZgGPZg-jRNQ,150
|
|
49
|
+
rtc_tools-2.7.0b1.dist-info/top_level.txt,sha256=pnBrb58PFPd1kp1dqa-JHU7R55h3alDNJIJnF3Jf9Dw,9
|
|
50
|
+
rtc_tools-2.7.0b1.dist-info/RECORD,,
|
|
@@ -5,12 +5,12 @@ import casadi as ca
|
|
|
5
5
|
logger = logging.getLogger("rtctools")
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
def is_affine(
|
|
8
|
+
def is_affine(expr, symbols):
|
|
9
9
|
try:
|
|
10
|
-
Af = ca.Function("f", [
|
|
11
|
-
except RuntimeError as
|
|
12
|
-
if "'eval_sx' not defined for" in str(
|
|
13
|
-
Af = ca.Function("f", [
|
|
10
|
+
Af = ca.Function("f", [symbols], [ca.jacobian(expr, symbols)]).expand()
|
|
11
|
+
except RuntimeError as error:
|
|
12
|
+
if "'eval_sx' not defined for" in str(error):
|
|
13
|
+
Af = ca.Function("f", [symbols], [ca.jacobian(expr, symbols)])
|
|
14
14
|
else:
|
|
15
15
|
raise
|
|
16
16
|
return Af.sparsity_jac(0, 0).nnz() == 0
|
rtctools/_version.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
# This file was generated by 'versioneer.py' (0.
|
|
2
|
+
# This file was generated by 'versioneer.py' (0.29) from
|
|
3
3
|
# revision-control system data, or from the parent directory name of an
|
|
4
4
|
# unpacked source archive. Distribution tarballs contain a pre-generated copy
|
|
5
5
|
# of this file.
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "
|
|
11
|
+
"date": "2025-04-15T16:04:52+0200",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "2.7.
|
|
14
|
+
"full-revisionid": "941763cc3e1c0ee1b9644aaa5dee37d25fd3b02c",
|
|
15
|
+
"version": "2.7.0b1"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
rtctools/data/csv.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import sys
|
|
3
3
|
from datetime import datetime
|
|
4
|
+
from typing import Union
|
|
4
5
|
|
|
5
6
|
import numpy as np
|
|
6
7
|
|
|
@@ -41,6 +42,21 @@ def _boolean_to_nan(data, fname):
|
|
|
41
42
|
return data
|
|
42
43
|
|
|
43
44
|
|
|
45
|
+
def _string_to_datetime(string: Union[str, bytes]) -> datetime:
|
|
46
|
+
"""Convert a string to a datetime object."""
|
|
47
|
+
if isinstance(string, bytes):
|
|
48
|
+
string = string.decode("utf-8")
|
|
49
|
+
return datetime.strptime(string, "%Y-%m-%d %H:%M:%S")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _string_to_float(string: Union[str, bytes]) -> float:
|
|
53
|
+
"""Convert a string to a float."""
|
|
54
|
+
if isinstance(string, bytes):
|
|
55
|
+
string = string.decode("utf-8")
|
|
56
|
+
string = string.replace(",", ".")
|
|
57
|
+
return float(string)
|
|
58
|
+
|
|
59
|
+
|
|
44
60
|
def load(fname, delimiter=",", with_time=False):
|
|
45
61
|
"""
|
|
46
62
|
Check delimiter of csv and read contents to an array. Assumes no date-time conversion needed.
|
|
@@ -53,7 +69,7 @@ def load(fname, delimiter=",", with_time=False):
|
|
|
53
69
|
"""
|
|
54
70
|
c = {}
|
|
55
71
|
if with_time:
|
|
56
|
-
c.update({0:
|
|
72
|
+
c.update({0: _string_to_datetime})
|
|
57
73
|
|
|
58
74
|
# Check delimiter of csv file. If semicolon, check if decimal separator is
|
|
59
75
|
# a comma.
|
|
@@ -73,12 +89,7 @@ def load(fname, delimiter=",", with_time=False):
|
|
|
73
89
|
# If commas are used as decimal separator, we need additional
|
|
74
90
|
# converters.
|
|
75
91
|
if n_comma_decimal:
|
|
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
|
-
)
|
|
92
|
+
c.update({i + len(c): _string_to_float for i in range(1 + n_semicolon - len(c))})
|
|
82
93
|
|
|
83
94
|
# Read the csv file and convert to array
|
|
84
95
|
try:
|
|
@@ -55,6 +55,7 @@ class BSpline1D(BSpline):
|
|
|
55
55
|
epsilon=1e-7,
|
|
56
56
|
delta=1e-4,
|
|
57
57
|
interior_pts=None,
|
|
58
|
+
ipopt_options=None,
|
|
58
59
|
):
|
|
59
60
|
"""
|
|
60
61
|
fit() returns a tck tuple like scipy.interpolate.splrep, but adjusts
|
|
@@ -153,7 +154,10 @@ class BSpline1D(BSpline):
|
|
|
153
154
|
nlp = {"x": c, "f": f, "g": g}
|
|
154
155
|
my_solver = "ipopt"
|
|
155
156
|
solver = nlpsol(
|
|
156
|
-
"solver",
|
|
157
|
+
"solver",
|
|
158
|
+
my_solver,
|
|
159
|
+
nlp,
|
|
160
|
+
{"print_time": 0, "expand": True, "ipopt": ipopt_options},
|
|
157
161
|
)
|
|
158
162
|
sol = solver(lbg=lbg, ubg=ubg)
|
|
159
163
|
stats = solver.stats()
|
rtctools/data/netcdf.py
CHANGED
|
@@ -401,20 +401,21 @@ class ExportDataset:
|
|
|
401
401
|
"""
|
|
402
402
|
assert len(set(variable_names)) == len(variable_names)
|
|
403
403
|
|
|
404
|
-
assert (
|
|
405
|
-
|
|
406
|
-
)
|
|
407
|
-
assert (
|
|
408
|
-
|
|
409
|
-
)
|
|
404
|
+
assert self.__time_dim is not None, (
|
|
405
|
+
"First call write_times to ensure the time dimension has been created."
|
|
406
|
+
)
|
|
407
|
+
assert self.__station_dim is not None, (
|
|
408
|
+
"First call write_station_data to ensure the station dimension has been created"
|
|
409
|
+
)
|
|
410
410
|
assert (
|
|
411
411
|
self.__station_id_to_index_mapping is not None
|
|
412
412
|
) # should also be created in write_station_data
|
|
413
413
|
|
|
414
414
|
if ensemble_size > 1:
|
|
415
|
-
assert (
|
|
416
|
-
|
|
417
|
-
|
|
415
|
+
assert self.__ensemble_member_dim is not None, (
|
|
416
|
+
"First call write_ensemble_data to ensure "
|
|
417
|
+
"the realization dimension has been created"
|
|
418
|
+
)
|
|
418
419
|
|
|
419
420
|
for variable_name in variable_names:
|
|
420
421
|
self.__dataset.createVariable(
|
|
@@ -446,15 +447,15 @@ class ExportDataset:
|
|
|
446
447
|
:param values: The values that are to be written to the file
|
|
447
448
|
:param ensemble_size: the number of members in the ensemble
|
|
448
449
|
"""
|
|
449
|
-
assert (
|
|
450
|
-
|
|
451
|
-
)
|
|
450
|
+
assert self.__station_id_to_index_mapping is not None, (
|
|
451
|
+
"First call write_station_data and create_variables."
|
|
452
|
+
)
|
|
452
453
|
|
|
453
454
|
station_index = self.__station_id_to_index_mapping[station_id]
|
|
454
455
|
if ensemble_size > 1:
|
|
455
|
-
self.__dataset.variables[variable_name][
|
|
456
|
-
|
|
457
|
-
|
|
456
|
+
self.__dataset.variables[variable_name][:, station_index, ensemble_member_index] = (
|
|
457
|
+
values
|
|
458
|
+
)
|
|
458
459
|
else:
|
|
459
460
|
self.__dataset.variables[variable_name][:, station_index] = values
|
|
460
461
|
|
rtctools/data/pi.py
CHANGED
|
@@ -333,8 +333,11 @@ class ParameterConfig:
|
|
|
333
333
|
|
|
334
334
|
parameters = group.findall("pi:parameter", ns)
|
|
335
335
|
for parameter in parameters:
|
|
336
|
-
yield
|
|
337
|
-
|
|
336
|
+
yield (
|
|
337
|
+
location_id,
|
|
338
|
+
model_id,
|
|
339
|
+
parameter.attrib["id"],
|
|
340
|
+
self.__parse_parameter(parameter),
|
|
338
341
|
)
|
|
339
342
|
|
|
340
343
|
|
|
@@ -881,29 +884,26 @@ class Timeseries:
|
|
|
881
884
|
events = series.findall("pi:event", ns)
|
|
882
885
|
|
|
883
886
|
t = self.__start_datetime
|
|
884
|
-
for i in
|
|
887
|
+
for i, value in enumerate(values):
|
|
885
888
|
if self.dt is None:
|
|
886
889
|
t = self.times[i]
|
|
887
|
-
# Set the date/time, so that any date/time steps that
|
|
888
|
-
# are wrong in the placeholder file are corrected.
|
|
889
|
-
events[i].set("date", t.strftime("%Y-%m-%d"))
|
|
890
|
-
events[i].set("time", t.strftime("%H:%M:%S"))
|
|
891
890
|
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
891
|
+
if i < len(events):
|
|
892
|
+
event = events[i]
|
|
893
|
+
else:
|
|
894
|
+
event = ET.Element("pi:event")
|
|
895
|
+
series.append(event)
|
|
896
|
+
|
|
897
|
+
# Always set the date/time, so that any date/time steps
|
|
898
|
+
# that are wrong in the placeholder file are corrected.
|
|
900
899
|
event.set("date", t.strftime("%Y-%m-%d"))
|
|
901
900
|
event.set("time", t.strftime("%H:%M:%S"))
|
|
901
|
+
|
|
902
902
|
if nans[i]:
|
|
903
903
|
event.set("value", miss_val)
|
|
904
904
|
else:
|
|
905
|
-
event.set("value", str(
|
|
906
|
-
|
|
905
|
+
event.set("value", str(value))
|
|
906
|
+
|
|
907
907
|
if self.dt:
|
|
908
908
|
t += self.dt
|
|
909
909
|
|
rtctools/data/rtc.py
CHANGED
|
@@ -60,9 +60,9 @@ class DataConfig:
|
|
|
60
60
|
logger.error(message)
|
|
61
61
|
raise Exception(message)
|
|
62
62
|
else:
|
|
63
|
-
self.__location_parameter_ids[
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
self.__location_parameter_ids[internal_id] = (
|
|
64
|
+
self.__pi_location_parameter_id(pi_timeseries, "fews")
|
|
65
|
+
)
|
|
66
66
|
self.__variable_map[external_id] = internal_id
|
|
67
67
|
|
|
68
68
|
for k in ["import", "export"]:
|
|
@@ -898,11 +898,11 @@ class CollocatedIntegratedOptimizationProblem(OptimizationProblem, metaclass=ABC
|
|
|
898
898
|
function_options,
|
|
899
899
|
)
|
|
900
900
|
|
|
901
|
+
# Expand the residual function if possible.
|
|
901
902
|
try:
|
|
902
903
|
dae_residual_function_integrated = dae_residual_function_integrated.expand()
|
|
903
904
|
except RuntimeError as e:
|
|
904
|
-
|
|
905
|
-
if "'eval_sx' not defined for External" in str(e):
|
|
905
|
+
if "'eval_sx' not defined for" in str(e):
|
|
906
906
|
pass
|
|
907
907
|
else:
|
|
908
908
|
raise
|
|
@@ -933,13 +933,13 @@ class CollocatedIntegratedOptimizationProblem(OptimizationProblem, metaclass=ABC
|
|
|
933
933
|
[dae_residual_collocated],
|
|
934
934
|
function_options,
|
|
935
935
|
)
|
|
936
|
+
# Expand the residual function if possible.
|
|
936
937
|
try:
|
|
937
938
|
self.__dae_residual_function_collocated = (
|
|
938
939
|
self.__dae_residual_function_collocated.expand()
|
|
939
940
|
)
|
|
940
941
|
except RuntimeError as e:
|
|
941
|
-
|
|
942
|
-
if "'eval_sx' not defined for External" in str(e):
|
|
942
|
+
if "'eval_sx' not defined for" in str(e):
|
|
943
943
|
pass
|
|
944
944
|
else:
|
|
945
945
|
raise
|
|
@@ -1028,8 +1028,8 @@ class CollocatedIntegratedOptimizationProblem(OptimizationProblem, metaclass=ABC
|
|
|
1028
1028
|
+ len(self.dae_variables["constant_inputs"])
|
|
1029
1029
|
]
|
|
1030
1030
|
constant_inputs_1 = accumulated_U[
|
|
1031
|
-
2 * len(collocated_variables)
|
|
1032
|
-
|
|
1031
|
+
2 * len(collocated_variables) + len(self.dae_variables["constant_inputs"]) : 2
|
|
1032
|
+
* len(collocated_variables)
|
|
1033
1033
|
+ 2 * len(self.dae_variables["constant_inputs"])
|
|
1034
1034
|
]
|
|
1035
1035
|
|
|
@@ -1803,9 +1803,9 @@ class CollocatedIntegratedOptimizationProblem(OptimizationProblem, metaclass=ABC
|
|
|
1803
1803
|
# Cast delay from DM to np.array
|
|
1804
1804
|
delay = delay.toarray().flatten()
|
|
1805
1805
|
|
|
1806
|
-
assert np.all(
|
|
1807
|
-
|
|
1808
|
-
)
|
|
1806
|
+
assert np.all(np.isfinite(delay)), (
|
|
1807
|
+
"Delay duration must be resolvable to real values at transcribe()"
|
|
1808
|
+
)
|
|
1809
1809
|
|
|
1810
1810
|
out_times = np.concatenate([history_times, collocation_times])
|
|
1811
1811
|
out_values = ca.veccat(
|
|
@@ -2869,8 +2869,7 @@ class CollocatedIntegratedOptimizationProblem(OptimizationProblem, metaclass=ABC
|
|
|
2869
2869
|
|
|
2870
2870
|
# Check coefficient matrix
|
|
2871
2871
|
logger.info(
|
|
2872
|
-
"Sanity check on objective and constraints Jacobian matrix"
|
|
2873
|
-
"/constant coefficients values"
|
|
2872
|
+
"Sanity check on objective and constraints Jacobian matrix/constant coefficients values"
|
|
2874
2873
|
)
|
|
2875
2874
|
|
|
2876
2875
|
in_var = nlp["x"]
|
|
@@ -55,7 +55,7 @@ class LookupTable(LookupTableBase):
|
|
|
55
55
|
"This lookup table was not instantiated with tck metadata. \
|
|
56
56
|
Domain/Range information is unavailable."
|
|
57
57
|
)
|
|
58
|
-
if
|
|
58
|
+
if isinstance(t, tuple) and len(t) == 2:
|
|
59
59
|
raise NotImplementedError(
|
|
60
60
|
"Domain/Range information is not yet implemented for 2D LookupTables"
|
|
61
61
|
)
|
|
@@ -298,8 +298,9 @@ class CSVLookupTableMixin(OptimizationProblem):
|
|
|
298
298
|
def check_lookup_table(lookup_table):
|
|
299
299
|
if lookup_table in self.__lookup_tables:
|
|
300
300
|
raise Exception(
|
|
301
|
-
"Cannot add lookup table {},"
|
|
302
|
-
|
|
301
|
+
"Cannot add lookup table {},since there is already one with this name.".format(
|
|
302
|
+
lookup_table
|
|
303
|
+
)
|
|
303
304
|
)
|
|
304
305
|
|
|
305
306
|
# Read CSV files
|
|
@@ -98,6 +98,9 @@ class CSVMixin(IOMixin):
|
|
|
98
98
|
names=True,
|
|
99
99
|
encoding=None,
|
|
100
100
|
)
|
|
101
|
+
if len(self.__ensemble.shape) == 0:
|
|
102
|
+
# If there is only one ensemble member, the array is 0-dimensional.
|
|
103
|
+
self.__ensemble = np.expand_dims(self.__ensemble, 0)
|
|
101
104
|
|
|
102
105
|
logger.debug("CSVMixin: Read ensemble description")
|
|
103
106
|
|
|
@@ -351,8 +351,9 @@ class GoalProgrammingMixin(_GoalProgrammingMixinBase):
|
|
|
351
351
|
if goal.has_target_bounds:
|
|
352
352
|
# We use a violation variable formulation, with the violation
|
|
353
353
|
# variables epsilon bounded between 0 and 1.
|
|
354
|
-
m, M =
|
|
355
|
-
epsilon, np.inf, dtype=np.float64
|
|
354
|
+
m, M = (
|
|
355
|
+
np.full_like(epsilon, -np.inf, dtype=np.float64),
|
|
356
|
+
np.full_like(epsilon, np.inf, dtype=np.float64),
|
|
356
357
|
)
|
|
357
358
|
|
|
358
359
|
# A function range does not have to be specified for critical
|
|
@@ -667,6 +668,7 @@ class GoalProgrammingMixin(_GoalProgrammingMixinBase):
|
|
|
667
668
|
logger.info("Starting goal programming")
|
|
668
669
|
|
|
669
670
|
success = False
|
|
671
|
+
self.skip_priority = False
|
|
670
672
|
|
|
671
673
|
self.__constraint_store = [OrderedDict() for ensemble_member in range(self.ensemble_size)]
|
|
672
674
|
self.__path_constraint_store = [
|
|
@@ -691,6 +693,13 @@ class GoalProgrammingMixin(_GoalProgrammingMixinBase):
|
|
|
691
693
|
# Call the pre priority hook
|
|
692
694
|
self.priority_started(priority)
|
|
693
695
|
|
|
696
|
+
if self.skip_priority:
|
|
697
|
+
logger.info(
|
|
698
|
+
"priority {} was removed in priority_started. No optimization problem "
|
|
699
|
+
"is solved at this priority.".format(priority)
|
|
700
|
+
)
|
|
701
|
+
continue
|
|
702
|
+
|
|
694
703
|
(
|
|
695
704
|
self.__subproblem_epsilons,
|
|
696
705
|
self.__subproblem_objectives,
|
|
@@ -437,7 +437,7 @@ class _GoalConstraint:
|
|
|
437
437
|
):
|
|
438
438
|
assert isinstance(m, (float, np.ndarray, Timeseries))
|
|
439
439
|
assert isinstance(M, (float, np.ndarray, Timeseries))
|
|
440
|
-
assert type(m)
|
|
440
|
+
assert type(m) is type(M)
|
|
441
441
|
|
|
442
442
|
# NumPy arrays only allowed for vector goals
|
|
443
443
|
if isinstance(m, np.ndarray):
|
|
@@ -982,8 +982,9 @@ class _GoalProgrammingMixinBase(OptimizationProblem, metaclass=ABCMeta):
|
|
|
982
982
|
if goal.has_target_bounds:
|
|
983
983
|
# We use a violation variable formulation, with the violation
|
|
984
984
|
# variables epsilon bounded between 0 and 1.
|
|
985
|
-
m, M =
|
|
986
|
-
epsilon, np.inf, dtype=np.float64
|
|
985
|
+
m, M = (
|
|
986
|
+
np.full_like(epsilon, -np.inf, dtype=np.float64),
|
|
987
|
+
np.full_like(epsilon, np.inf, dtype=np.float64),
|
|
987
988
|
)
|
|
988
989
|
|
|
989
990
|
# A function range does not have to be specified for critical
|
|
@@ -1081,6 +1082,7 @@ class _GoalProgrammingMixinBase(OptimizationProblem, metaclass=ABCMeta):
|
|
|
1081
1082
|
|
|
1082
1083
|
:param priority: The priority level that was started.
|
|
1083
1084
|
"""
|
|
1085
|
+
self.skip_priority = False
|
|
1084
1086
|
pass
|
|
1085
1087
|
|
|
1086
1088
|
def priority_completed(self, priority: int) -> None:
|
|
@@ -1,10 +1,18 @@
|
|
|
1
|
+
import importlib.resources
|
|
1
2
|
import itertools
|
|
2
3
|
import logging
|
|
4
|
+
import sys
|
|
3
5
|
from typing import Dict, Union
|
|
4
6
|
|
|
7
|
+
# Python 3.9's importlib.metadata does not support the "group" parameter to
|
|
8
|
+
# entry_points yet.
|
|
9
|
+
if sys.version_info < (3, 10):
|
|
10
|
+
import importlib_metadata
|
|
11
|
+
else:
|
|
12
|
+
from importlib import metadata as importlib_metadata
|
|
13
|
+
|
|
5
14
|
import casadi as ca
|
|
6
15
|
import numpy as np
|
|
7
|
-
import pkg_resources
|
|
8
16
|
import pymoca
|
|
9
17
|
import pymoca.backends.casadi.api
|
|
10
18
|
|
|
@@ -54,8 +62,8 @@ class ModelicaMixin(OptimizationProblem):
|
|
|
54
62
|
self.__pymoca_model = pymoca.backends.casadi.api.transfer_model(
|
|
55
63
|
kwargs["model_folder"], model_name, compiler_options
|
|
56
64
|
)
|
|
57
|
-
except RuntimeError as error:
|
|
58
|
-
if compiler_options.get("cache", False):
|
|
65
|
+
except (RuntimeError, ModuleNotFoundError) as error:
|
|
66
|
+
if not compiler_options.get("cache", False):
|
|
59
67
|
raise error
|
|
60
68
|
compiler_options["cache"] = False
|
|
61
69
|
logger.warning(f"Loading model {model_name} using a cache file failed: {error}.")
|
|
@@ -174,9 +182,9 @@ class ModelicaMixin(OptimizationProblem):
|
|
|
174
182
|
# Where imported model libraries are located.
|
|
175
183
|
library_folders = self.modelica_library_folders.copy()
|
|
176
184
|
|
|
177
|
-
for ep in
|
|
185
|
+
for ep in importlib_metadata.entry_points(group="rtctools.libraries.modelica"):
|
|
178
186
|
if ep.name == "library_folder":
|
|
179
|
-
library_folders.append(
|
|
187
|
+
library_folders.append(str(importlib.resources.files(ep.module).joinpath(ep.attr)))
|
|
180
188
|
|
|
181
189
|
compiler_options["library_folders"] = library_folders
|
|
182
190
|
|
|
@@ -326,7 +334,7 @@ class ModelicaMixin(OptimizationProblem):
|
|
|
326
334
|
try:
|
|
327
335
|
(m, M) = bounds[sym_name]
|
|
328
336
|
except KeyError:
|
|
329
|
-
if self.__python_types.get(sym_name, float)
|
|
337
|
+
if self.__python_types.get(sym_name, float) is bool:
|
|
330
338
|
(m, M) = (0, 1)
|
|
331
339
|
else:
|
|
332
340
|
(m, M) = (-np.inf, np.inf)
|
|
@@ -400,7 +408,7 @@ class ModelicaMixin(OptimizationProblem):
|
|
|
400
408
|
return seed
|
|
401
409
|
|
|
402
410
|
def variable_is_discrete(self, variable):
|
|
403
|
-
return self.__python_types.get(variable, float)
|
|
411
|
+
return self.__python_types.get(variable, float) is not float
|
|
404
412
|
|
|
405
413
|
@property
|
|
406
414
|
@cached
|
|
@@ -285,8 +285,8 @@ class PIMixin(IOMixin):
|
|
|
285
285
|
:param variable: Time series ID.
|
|
286
286
|
:param unit: Unit.
|
|
287
287
|
"""
|
|
288
|
-
assert hasattr(
|
|
289
|
-
|
|
290
|
-
)
|
|
288
|
+
assert hasattr(self, "_PIMixin__timeseries_import"), (
|
|
289
|
+
"set_unit can only be called after read() in pre() has finished."
|
|
290
|
+
)
|
|
291
291
|
self.__timeseries_import.set_unit(variable, unit, 0)
|
|
292
292
|
self.__timeseries_export.set_unit(variable, unit, 0)
|
rtctools/rtctoolsapp.py
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
|
+
import importlib.resources
|
|
1
2
|
import logging
|
|
2
3
|
import os
|
|
3
4
|
import shutil
|
|
4
5
|
import sys
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
|
|
8
|
+
# Python 3.9's importlib.metadata does not support the "group" parameter to
|
|
9
|
+
# entry_points yet.
|
|
10
|
+
if sys.version_info < (3, 10):
|
|
11
|
+
import importlib_metadata
|
|
12
|
+
else:
|
|
13
|
+
from importlib import metadata as importlib_metadata
|
|
14
|
+
|
|
7
15
|
import rtctools
|
|
8
16
|
|
|
9
17
|
logging.basicConfig(format="%(asctime)s %(levelname)s %(message)s")
|
|
@@ -23,9 +31,6 @@ def copy_libraries(*args):
|
|
|
23
31
|
if not os.path.exists(path):
|
|
24
32
|
sys.exit("Folder '{}' does not exist".format(path))
|
|
25
33
|
|
|
26
|
-
# pkg_resources can be quite a slow import, so we do it here
|
|
27
|
-
import pkg_resources
|
|
28
|
-
|
|
29
34
|
def _copytree(src, dst, symlinks=False, ignore=None):
|
|
30
35
|
if not os.path.exists(dst):
|
|
31
36
|
os.makedirs(dst)
|
|
@@ -56,11 +61,10 @@ def copy_libraries(*args):
|
|
|
56
61
|
dst = Path(path)
|
|
57
62
|
|
|
58
63
|
library_folders = []
|
|
59
|
-
|
|
64
|
+
|
|
65
|
+
for ep in importlib_metadata.entry_points(group="rtctools.libraries.modelica"):
|
|
60
66
|
if ep.name == "library_folder":
|
|
61
|
-
library_folders.append(
|
|
62
|
-
Path(pkg_resources.resource_filename(ep.module_name, ep.attrs[0]))
|
|
63
|
-
)
|
|
67
|
+
library_folders.append(str(importlib.resources.files(ep.module).joinpath(ep.attr)))
|
|
64
68
|
|
|
65
69
|
tlds = {}
|
|
66
70
|
for lf in library_folders:
|
|
@@ -102,9 +106,7 @@ def download_examples(*args):
|
|
|
102
106
|
version = rtctools.__version__
|
|
103
107
|
rtc_full_name = "rtc-tools-{}".format(version)
|
|
104
108
|
try:
|
|
105
|
-
url = "https://
|
|
106
|
-
version, rtc_full_name
|
|
107
|
-
)
|
|
109
|
+
url = "https://github.com/deltares/rtc-tools/zipball/{}".format(version)
|
|
108
110
|
|
|
109
111
|
opener = urllib.request.build_opener()
|
|
110
112
|
urllib.request.install_opener(opener)
|
rtctools/simulation/io_mixin.py
CHANGED
|
@@ -94,7 +94,7 @@ class IOMixin(SimulationProblem, metaclass=ABCMeta):
|
|
|
94
94
|
self.__cache_loop_timeseries = {}
|
|
95
95
|
|
|
96
96
|
timeseries_names = set(self.io.get_timeseries_names(0))
|
|
97
|
-
for v in self.
|
|
97
|
+
for v in self.get_input_variables():
|
|
98
98
|
if v in timeseries_names:
|
|
99
99
|
_, values = self.io.get_timeseries_sec(v)
|
|
100
100
|
self.__cache_loop_timeseries[v] = values
|
rtctools/simulation/pi_mixin.py
CHANGED
|
@@ -248,8 +248,8 @@ class PIMixin(IOMixin):
|
|
|
248
248
|
:param variable: Time series ID.
|
|
249
249
|
:param unit: Unit.
|
|
250
250
|
"""
|
|
251
|
-
assert hasattr(
|
|
252
|
-
|
|
253
|
-
)
|
|
251
|
+
assert hasattr(self, "_PIMixin__timeseries_import"), (
|
|
252
|
+
"set_unit can only be called after read() in pre() has finished."
|
|
253
|
+
)
|
|
254
254
|
self.__timeseries_import.set_unit(variable, unit, 0)
|
|
255
255
|
self.__timeseries_export.set_unit(variable, unit, 0)
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import copy
|
|
2
|
+
import importlib.resources
|
|
2
3
|
import itertools
|
|
3
4
|
import logging
|
|
4
5
|
import math
|
|
6
|
+
import sys
|
|
5
7
|
from collections import OrderedDict
|
|
6
8
|
from typing import List, Union
|
|
7
9
|
|
|
10
|
+
# Python 3.9's importlib.metadata does not support the "group" parameter to
|
|
11
|
+
# entry_points yet.
|
|
12
|
+
if sys.version_info < (3, 10):
|
|
13
|
+
import importlib_metadata
|
|
14
|
+
else:
|
|
15
|
+
from importlib import metadata as importlib_metadata
|
|
16
|
+
|
|
8
17
|
import casadi as ca
|
|
9
18
|
import numpy as np
|
|
10
|
-
import pkg_resources
|
|
11
19
|
import pymoca
|
|
12
20
|
import pymoca.backends.casadi.api
|
|
13
21
|
|
|
@@ -492,8 +500,9 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
492
500
|
self.set_var(var_name, numeric_start_val)
|
|
493
501
|
except KeyError:
|
|
494
502
|
logger.warning(
|
|
495
|
-
"Initialize: {} not found in state vector. "
|
|
496
|
-
|
|
503
|
+
"Initialize: {} not found in state vector. Initial value of {} not set.".format(
|
|
504
|
+
var_name, numeric_start_val
|
|
505
|
+
)
|
|
497
506
|
)
|
|
498
507
|
|
|
499
508
|
# Add a residual for the difference between the state and its starting expression
|
|
@@ -517,10 +526,14 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
517
526
|
# Check that the start_value is in between the variable bounds.
|
|
518
527
|
if start_is_numeric and not min_is_symbolic and not max_is_symbolic:
|
|
519
528
|
if not (var.min <= start_val and start_val <= var.max):
|
|
520
|
-
logger.
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
529
|
+
logger.log(
|
|
530
|
+
(
|
|
531
|
+
logging.WARNING
|
|
532
|
+
if source_description != "modelica file or default value"
|
|
533
|
+
else logging.DEBUG
|
|
534
|
+
),
|
|
535
|
+
f"Initialize: start value {var_name} = {start_val} "
|
|
536
|
+
f"is not in between bounds {var.min} and {var.max} and will be adjusted.",
|
|
524
537
|
)
|
|
525
538
|
|
|
526
539
|
# Default start var for ders is zero
|
|
@@ -1059,9 +1072,9 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
1059
1072
|
:param dt: Timestep size of the simulation.
|
|
1060
1073
|
"""
|
|
1061
1074
|
if self._dt_is_fixed:
|
|
1062
|
-
assert math.isclose(
|
|
1063
|
-
|
|
1064
|
-
)
|
|
1075
|
+
assert math.isclose(self.__dt, dt), (
|
|
1076
|
+
"Timestep size dt is marked as constant and cannot be changed."
|
|
1077
|
+
)
|
|
1065
1078
|
else:
|
|
1066
1079
|
self.__dt = dt
|
|
1067
1080
|
|
|
@@ -1244,9 +1257,9 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
1244
1257
|
# Where imported model libraries are located.
|
|
1245
1258
|
library_folders = self.modelica_library_folders.copy()
|
|
1246
1259
|
|
|
1247
|
-
for ep in
|
|
1260
|
+
for ep in importlib_metadata.entry_points(group="rtctools.libraries.modelica"):
|
|
1248
1261
|
if ep.name == "library_folder":
|
|
1249
|
-
library_folders.append(
|
|
1262
|
+
library_folders.append(str(importlib.resources.files(ep.module).joinpath(ep.attr)))
|
|
1250
1263
|
|
|
1251
1264
|
compiler_options["library_folders"] = library_folders
|
|
1252
1265
|
|
|
File without changes
|
|
File without changes
|