rtc-tools 2.6.1__py3-none-any.whl → 2.7.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.
- {rtc_tools-2.6.1.dist-info → rtc_tools-2.7.0a2.dist-info}/METADATA +1 -1
- {rtc_tools-2.6.1.dist-info → rtc_tools-2.7.0a2.dist-info}/RECORD +11 -11
- {rtc_tools-2.6.1.dist-info → rtc_tools-2.7.0a2.dist-info}/WHEEL +1 -1
- rtctools/_version.py +3 -3
- rtctools/optimization/modelica_mixin.py +15 -3
- rtctools/optimization/pi_mixin.py +13 -0
- rtctools/simulation/pi_mixin.py +13 -0
- rtctools/simulation/simulation_problem.py +91 -15
- {rtc_tools-2.6.1.dist-info → rtc_tools-2.7.0a2.dist-info}/COPYING.LESSER +0 -0
- {rtc_tools-2.6.1.dist-info → rtc_tools-2.7.0a2.dist-info}/entry_points.txt +0 -0
- {rtc_tools-2.6.1.dist-info → rtc_tools-2.7.0a2.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
rtctools/__init__.py,sha256=91hvS2-ryd2Pvw0COpsUzTwJwSnTZ035REiej-1hNI4,107
|
|
2
|
-
rtctools/_version.py,sha256=
|
|
2
|
+
rtctools/_version.py,sha256=khi7aLWt95iU8AN9lfjGJYvYFy3VrtunF5V_MRtL7tI,499
|
|
3
3
|
rtctools/rtctoolsapp.py,sha256=UnkuiJhv0crEEVs8H6PYvMuc2y_q6V_xLuyKEgXj9GM,4200
|
|
4
4
|
rtctools/util.py,sha256=PaeKfDUA174ODZbY5fZjCTf-F-TdhW7yEuP189Ro190,9075
|
|
5
5
|
rtctools/_internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -30,21 +30,21 @@ rtctools/optimization/io_mixin.py,sha256=AsZQ7YOUcUbWoczmjTXaSje5MUEsPNbQyZBJ6qz
|
|
|
30
30
|
rtctools/optimization/linearization_mixin.py,sha256=mG5S7uwvwDydw-eBPyQKnLyKoy08EBjQh25vu97afhY,1049
|
|
31
31
|
rtctools/optimization/linearized_order_goal_programming_mixin.py,sha256=LQ2qpYt0YGLpEoerif4FJ5wwzq16q--27bsRjcqIU5A,9087
|
|
32
32
|
rtctools/optimization/min_abs_goal_programming_mixin.py,sha256=WMOv9EF8cfDJgTunzXfI_cUmBSQK26u1HJB_9EAarfM,14031
|
|
33
|
-
rtctools/optimization/modelica_mixin.py,sha256=
|
|
33
|
+
rtctools/optimization/modelica_mixin.py,sha256=6rotTEge4l2oDib4tnG2ccXqG1ryEzNxbRkk_StFAHg,17769
|
|
34
34
|
rtctools/optimization/netcdf_mixin.py,sha256=-zkXh3sMYE50c3kHsrmUVGWMSFm-0cXQpGrCm0yn-Tc,7563
|
|
35
35
|
rtctools/optimization/optimization_problem.py,sha256=qzpc81NaZMeoXKuayFmBF15iXYuNAk5yxmaER_Gcz_A,44131
|
|
36
|
-
rtctools/optimization/pi_mixin.py,sha256=
|
|
36
|
+
rtctools/optimization/pi_mixin.py,sha256=n_ZyifuNPxcRoJXKR6Ks7DgK_b7-EToYJ23_khOwpzo,11786
|
|
37
37
|
rtctools/optimization/planning_mixin.py,sha256=O_Y74X8xZmaNZR4iYOe7BR06s9hnmcapbuHYHQTBPPQ,724
|
|
38
38
|
rtctools/optimization/single_pass_goal_programming_mixin.py,sha256=Zb9szg3PGT2o6gkGsXluSfEaAswkw3TKfPQDzUrj_Y4,25784
|
|
39
39
|
rtctools/optimization/timeseries.py,sha256=nCrsGCJThBMh9lvngEpbBDa834_QvklVvkxJqwX4a1M,1734
|
|
40
40
|
rtctools/simulation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
41
41
|
rtctools/simulation/csv_mixin.py,sha256=rGDUFPsqGHmF0_dWdXeWzWzMpkPmwCNweTBVrwSh31g,6704
|
|
42
42
|
rtctools/simulation/io_mixin.py,sha256=SJasNGI--OQ9Y-Z61oeeaGCxSrNddYz4AOVfJYbmf74,6209
|
|
43
|
-
rtctools/simulation/pi_mixin.py,sha256=
|
|
44
|
-
rtctools/simulation/simulation_problem.py,sha256=
|
|
45
|
-
rtc_tools-2.
|
|
46
|
-
rtc_tools-2.
|
|
47
|
-
rtc_tools-2.
|
|
48
|
-
rtc_tools-2.
|
|
49
|
-
rtc_tools-2.
|
|
50
|
-
rtc_tools-2.
|
|
43
|
+
rtctools/simulation/pi_mixin.py,sha256=vcizArZsOn7tGlSFCsUmkjmRFA1A1kMNqUllLlkVc9Y,9831
|
|
44
|
+
rtctools/simulation/simulation_problem.py,sha256=TAG8J8td-23UgRz_I0Nz7yp9v_HT8ayblyYPtqbLyZo,48647
|
|
45
|
+
rtc_tools-2.7.0a2.dist-info/COPYING.LESSER,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
|
|
46
|
+
rtc_tools-2.7.0a2.dist-info/METADATA,sha256=OISYetGzEVCx1AWcMEcqOZpd-HT-0p6CftZd3uicWx4,1494
|
|
47
|
+
rtc_tools-2.7.0a2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
48
|
+
rtc_tools-2.7.0a2.dist-info/entry_points.txt,sha256=-x622IB_l1duw2M6t6syfQ4yzOiQTp0IZxKGcYRgWgk,151
|
|
49
|
+
rtc_tools-2.7.0a2.dist-info/top_level.txt,sha256=pnBrb58PFPd1kp1dqa-JHU7R55h3alDNJIJnF3Jf9Dw,9
|
|
50
|
+
rtc_tools-2.7.0a2.dist-info/RECORD,,
|
rtctools/_version.py
CHANGED
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2024-
|
|
11
|
+
"date": "2024-05-14T15:15:45+0200",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "2.
|
|
14
|
+
"full-revisionid": "6d06af067e4be71ea3b47593feb9be8ee7c37adc",
|
|
15
|
+
"version": "2.7.0a2"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -48,9 +48,21 @@ class ModelicaMixin(OptimizationProblem):
|
|
|
48
48
|
else:
|
|
49
49
|
model_name = self.__class__.__name__
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
compiler_options = self.compiler_options()
|
|
52
|
+
logger.info(f"Loading/compiling model {model_name}.")
|
|
53
|
+
try:
|
|
54
|
+
self.__pymoca_model = pymoca.backends.casadi.api.transfer_model(
|
|
55
|
+
kwargs["model_folder"], model_name, compiler_options
|
|
56
|
+
)
|
|
57
|
+
except RuntimeError as error:
|
|
58
|
+
if compiler_options.get("cache", False):
|
|
59
|
+
raise error
|
|
60
|
+
compiler_options["cache"] = False
|
|
61
|
+
logger.warning(f"Loading model {model_name} using a cache file failed: {error}.")
|
|
62
|
+
logger.info(f"Compiling model {model_name}.")
|
|
63
|
+
self.__pymoca_model = pymoca.backends.casadi.api.transfer_model(
|
|
64
|
+
kwargs["model_folder"], model_name, compiler_options
|
|
65
|
+
)
|
|
54
66
|
|
|
55
67
|
# Extract the CasADi MX variables used in the model
|
|
56
68
|
self.__mx = {}
|
|
@@ -277,3 +277,16 @@ class PIMixin(IOMixin):
|
|
|
277
277
|
:class:`pi.Timeseries` object for holding the output data.
|
|
278
278
|
"""
|
|
279
279
|
return self.__timeseries_export
|
|
280
|
+
|
|
281
|
+
def set_unit(self, variable: str, unit: str):
|
|
282
|
+
"""
|
|
283
|
+
Set the unit of a time series.
|
|
284
|
+
|
|
285
|
+
:param variable: Time series ID.
|
|
286
|
+
:param unit: Unit.
|
|
287
|
+
"""
|
|
288
|
+
assert hasattr(
|
|
289
|
+
self, "_PIMixin__timeseries_import"
|
|
290
|
+
), "set_unit can only be called after read() in pre() has finished."
|
|
291
|
+
self.__timeseries_import.set_unit(variable, unit, 0)
|
|
292
|
+
self.__timeseries_export.set_unit(variable, unit, 0)
|
rtctools/simulation/pi_mixin.py
CHANGED
|
@@ -240,3 +240,16 @@ class PIMixin(IOMixin):
|
|
|
240
240
|
def get_timeseries(self, variable):
|
|
241
241
|
_, values = self.io.get_timeseries(variable)
|
|
242
242
|
return values
|
|
243
|
+
|
|
244
|
+
def set_unit(self, variable: str, unit: str):
|
|
245
|
+
"""
|
|
246
|
+
Set the unit of a time series.
|
|
247
|
+
|
|
248
|
+
:param variable: Time series ID.
|
|
249
|
+
:param unit: Unit.
|
|
250
|
+
"""
|
|
251
|
+
assert hasattr(
|
|
252
|
+
self, "_PIMixin__timeseries_import"
|
|
253
|
+
), "set_unit can only be called after read() in pre() has finished."
|
|
254
|
+
self.__timeseries_import.set_unit(variable, unit, 0)
|
|
255
|
+
self.__timeseries_export.set_unit(variable, unit, 0)
|
|
@@ -82,9 +82,21 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
82
82
|
model_name = self.__class__.__name__
|
|
83
83
|
|
|
84
84
|
# Load model from pymoca backend
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
compiler_options = self.compiler_options()
|
|
86
|
+
logger.info(f"Loading/compiling model {model_name}.")
|
|
87
|
+
try:
|
|
88
|
+
self.__pymoca_model = pymoca.backends.casadi.api.transfer_model(
|
|
89
|
+
kwargs["model_folder"], model_name, compiler_options
|
|
90
|
+
)
|
|
91
|
+
except RuntimeError as error:
|
|
92
|
+
if compiler_options.get("cache", False):
|
|
93
|
+
raise error
|
|
94
|
+
compiler_options["cache"] = False
|
|
95
|
+
logger.warning(f"Loading model {model_name} using a cache file failed: {error}.")
|
|
96
|
+
logger.info(f"Compiling model {model_name}.")
|
|
97
|
+
self.__pymoca_model = pymoca.backends.casadi.api.transfer_model(
|
|
98
|
+
kwargs["model_folder"], model_name, compiler_options
|
|
99
|
+
)
|
|
88
100
|
|
|
89
101
|
# Extract the CasADi MX variables used in the model
|
|
90
102
|
self.__mx = {}
|
|
@@ -319,6 +331,17 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
319
331
|
"""
|
|
320
332
|
Initialize state vector with default values
|
|
321
333
|
|
|
334
|
+
Initial values are first read from the given Modelica files.
|
|
335
|
+
If an initial value equals zero or is not provided by a Modelica file,
|
|
336
|
+
and the variable is not marked as fixed,
|
|
337
|
+
then the initial value is tried to be set with the initial_state method.
|
|
338
|
+
When using CSVMixin, this method by default looks for initial values
|
|
339
|
+
in an initial_state.csv file.
|
|
340
|
+
Furthermore, if a variable is not marked as fixed
|
|
341
|
+
and no initial value is given by the initial_state method,
|
|
342
|
+
the initial value can be overwritten using the seed method.
|
|
343
|
+
When a variable is marked as fixed, the initial value is only read from the Modelica file.
|
|
344
|
+
|
|
322
345
|
:param config_file: Path to an initialization file.
|
|
323
346
|
"""
|
|
324
347
|
if config_file:
|
|
@@ -393,29 +416,33 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
393
416
|
for var in itertools.chain(self.__pymoca_model.states, self.__pymoca_model.alg_states):
|
|
394
417
|
var_name = var.symbol.name()
|
|
395
418
|
var_nominal = self.get_variable_nominal(var_name)
|
|
419
|
+
start_values = {}
|
|
396
420
|
|
|
397
421
|
# Attempt to cast var.start to python type
|
|
398
422
|
mx_start = ca.MX(var.start)
|
|
399
423
|
if mx_start.is_constant():
|
|
400
424
|
# cast var.start to python type
|
|
401
|
-
|
|
425
|
+
start_value_pymoca = var.python_type(mx_start.to_DM())
|
|
426
|
+
if start_value_pymoca is not None and start_value_pymoca != 0:
|
|
427
|
+
start_values["modelica"] = start_value_pymoca
|
|
402
428
|
else:
|
|
403
|
-
|
|
404
|
-
start_val = None
|
|
429
|
+
start_values["modelica"] = mx_start
|
|
405
430
|
|
|
406
|
-
if
|
|
431
|
+
if not var.fixed:
|
|
407
432
|
# To make initialization easier, we allow setting initial states by providing
|
|
408
433
|
# timeseries with names that match a symbol in the model. We only check for this
|
|
409
434
|
# matching if the start and fixed attributes were left as default
|
|
410
435
|
try:
|
|
411
|
-
|
|
436
|
+
start_values["initial_state"] = self.initial_state()[var_name]
|
|
412
437
|
except KeyError:
|
|
413
438
|
pass
|
|
414
439
|
else:
|
|
415
440
|
# An initial state was found- add it to the constrained residuals
|
|
416
441
|
logger.debug(
|
|
417
442
|
"Initialize: Added {} = {} to initial equations "
|
|
418
|
-
"(found matching timeseries).".format(
|
|
443
|
+
"(found matching timeseries).".format(
|
|
444
|
+
var_name, start_values["initial_state"]
|
|
445
|
+
)
|
|
419
446
|
)
|
|
420
447
|
# Set var to be fixed
|
|
421
448
|
var.fixed = True
|
|
@@ -425,36 +452,77 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
425
452
|
# timeseries with names that match a symbol in the model. We only check for this
|
|
426
453
|
# matching if the start and fixed attributes were left as default
|
|
427
454
|
try:
|
|
428
|
-
|
|
455
|
+
start_values["seed"] = self.seed()[var_name]
|
|
429
456
|
except KeyError:
|
|
430
457
|
pass
|
|
431
458
|
else:
|
|
432
459
|
# An initial state was found- add it to the constrained residuals
|
|
433
460
|
logger.debug(
|
|
434
461
|
"Initialize: Added {} = {} as initial guess "
|
|
435
|
-
"(found matching timeseries).".format(var_name,
|
|
462
|
+
"(found matching timeseries).".format(var_name, start_values["seed"])
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
# Set the start value based on the different inputs.
|
|
466
|
+
if "seed" in start_values:
|
|
467
|
+
input_source = "seed"
|
|
468
|
+
source_description = "seed method"
|
|
469
|
+
elif "modelica" in start_values:
|
|
470
|
+
input_source = "modelica"
|
|
471
|
+
source_description = "modelica file"
|
|
472
|
+
elif "initial_state" in start_values:
|
|
473
|
+
input_source = "initial_state"
|
|
474
|
+
source_description = "initial_state method (typically reads initial_state.csv)"
|
|
475
|
+
else:
|
|
476
|
+
start_values["modelica"] = start_value_pymoca
|
|
477
|
+
input_source = "modelica"
|
|
478
|
+
source_description = "modelica file or default value"
|
|
479
|
+
start_val = start_values.get(input_source, None)
|
|
480
|
+
start_is_numeric = start_val is not None and not isinstance(start_val, ca.MX)
|
|
481
|
+
numeric_start_val = start_val if start_is_numeric else 0.0
|
|
482
|
+
if len(start_values) > 1:
|
|
483
|
+
logger.warning(
|
|
484
|
+
"Initialize: Multiple initial values for {} are provided: {}.".format(
|
|
485
|
+
var_name, start_values
|
|
436
486
|
)
|
|
487
|
+
+ " Value from {} will be used to continue.".format(source_description)
|
|
488
|
+
)
|
|
437
489
|
|
|
438
490
|
# Attempt to set start_val in the state vector. Default to zero if unknown.
|
|
439
491
|
try:
|
|
440
|
-
self.set_var(var_name,
|
|
492
|
+
self.set_var(var_name, numeric_start_val)
|
|
441
493
|
except KeyError:
|
|
442
494
|
logger.warning(
|
|
443
495
|
"Initialize: {} not found in state vector. "
|
|
444
|
-
"Initial value of {} not set.".format(var_name,
|
|
496
|
+
"Initial value of {} not set.".format(var_name, numeric_start_val)
|
|
445
497
|
)
|
|
446
498
|
|
|
447
499
|
# Add a residual for the difference between the state and its starting expression
|
|
448
|
-
start_expr = start_val
|
|
500
|
+
start_expr = start_val
|
|
501
|
+
min_is_symbolic = isinstance(var.min, ca.MX)
|
|
502
|
+
max_is_symbolic = isinstance(var.max, ca.MX)
|
|
449
503
|
if var.fixed:
|
|
450
504
|
# Set bounds to be equal to each other, such that IPOPT can
|
|
451
505
|
# turn the decision variable into a parameter.
|
|
506
|
+
if min_is_symbolic or max_is_symbolic or var.min != -np.inf or var.max != np.inf:
|
|
507
|
+
logger.info(
|
|
508
|
+
"Initialize: bounds of {} will be overwritten".format(var_name)
|
|
509
|
+
+ " by the start value given by {}.".format(source_description)
|
|
510
|
+
)
|
|
452
511
|
var.min = start_expr
|
|
453
512
|
var.max = start_expr
|
|
454
513
|
else:
|
|
455
514
|
# minimize residual
|
|
456
515
|
minimized_residuals.append((var.symbol - start_expr) / var_nominal)
|
|
457
516
|
|
|
517
|
+
# Check that the start_value is in between the variable bounds.
|
|
518
|
+
if start_is_numeric and not min_is_symbolic and not max_is_symbolic:
|
|
519
|
+
if not (var.min <= start_val and start_val <= var.max):
|
|
520
|
+
logger.warning(
|
|
521
|
+
"Initialize: start value {} = {}".format(var_name, start_val)
|
|
522
|
+
+ " is not in between bounds {} and {}".format(var.min, var.max)
|
|
523
|
+
+ " and will be adjusted."
|
|
524
|
+
)
|
|
525
|
+
|
|
458
526
|
# Default start var for ders is zero
|
|
459
527
|
for der_var in self.__mx["derivatives"]:
|
|
460
528
|
self.set_var(der_var.name(), 0.0)
|
|
@@ -610,7 +678,15 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
610
678
|
# If unsuccessful, stop.
|
|
611
679
|
return_status = solver.stats()["return_status"]
|
|
612
680
|
if return_status not in {"Solve_Succeeded", "Solved_To_Acceptable_Level"}:
|
|
613
|
-
|
|
681
|
+
if return_status == "Infeasible_Problem_Detected":
|
|
682
|
+
message = (
|
|
683
|
+
"Initialization Failed with return status: {}. ".format(return_status)
|
|
684
|
+
+ "This means no initial state could be found "
|
|
685
|
+
+ "that satisfies all equations and constraints."
|
|
686
|
+
)
|
|
687
|
+
else:
|
|
688
|
+
message = "Initialization Failed with return status: {}. ".format(return_status)
|
|
689
|
+
raise Exception(message)
|
|
614
690
|
|
|
615
691
|
# Update state vector with initial conditions
|
|
616
692
|
self.__state_vector[: self.__n_states] = initial_state["x"][: self.__n_states].T
|
|
File without changes
|
|
File without changes
|
|
File without changes
|