rtc-tools 2.6.0b2__py3-none-any.whl → 2.7.0__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.0b2.dist-info → rtc_tools-2.7.0.dist-info}/METADATA +26 -15
- rtc_tools-2.7.0.dist-info/RECORD +50 -0
- {rtc_tools-2.6.0b2.dist-info → rtc_tools-2.7.0.dist-info}/WHEEL +1 -1
- {rtc_tools-2.6.0b2.dist-info → rtc_tools-2.7.0.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 +72 -41
- rtctools/data/rtc.py +6 -5
- rtctools/optimization/collocated_integrated_optimization_problem.py +14 -17
- rtctools/optimization/control_tree_mixin.py +8 -5
- rtctools/optimization/csv_lookup_table_mixin.py +15 -15
- 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 +28 -8
- rtctools/optimization/optimization_problem.py +18 -0
- rtctools/optimization/pi_mixin.py +13 -0
- rtctools/rtctoolsapp.py +17 -14
- rtctools/simulation/io_mixin.py +1 -1
- rtctools/simulation/pi_mixin.py +13 -0
- rtctools/simulation/simulation_problem.py +130 -22
- rtctools/util.py +1 -0
- rtc_tools-2.6.0b2.dist-info/RECORD +0 -50
- {rtc_tools-2.6.0b2.dist-info → rtc_tools-2.7.0.dist-info/licenses}/COPYING.LESSER +0 -0
- {rtc_tools-2.6.0b2.dist-info → rtc_tools-2.7.0.dist-info}/top_level.txt +0 -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
|
|
|
@@ -82,9 +90,21 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
82
90
|
model_name = self.__class__.__name__
|
|
83
91
|
|
|
84
92
|
# Load model from pymoca backend
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
93
|
+
compiler_options = self.compiler_options()
|
|
94
|
+
logger.info(f"Loading/compiling model {model_name}.")
|
|
95
|
+
try:
|
|
96
|
+
self.__pymoca_model = pymoca.backends.casadi.api.transfer_model(
|
|
97
|
+
kwargs["model_folder"], model_name, compiler_options
|
|
98
|
+
)
|
|
99
|
+
except RuntimeError as error:
|
|
100
|
+
if compiler_options.get("cache", False):
|
|
101
|
+
raise error
|
|
102
|
+
compiler_options["cache"] = False
|
|
103
|
+
logger.warning(f"Loading model {model_name} using a cache file failed: {error}.")
|
|
104
|
+
logger.info(f"Compiling model {model_name}.")
|
|
105
|
+
self.__pymoca_model = pymoca.backends.casadi.api.transfer_model(
|
|
106
|
+
kwargs["model_folder"], model_name, compiler_options
|
|
107
|
+
)
|
|
88
108
|
|
|
89
109
|
# Extract the CasADi MX variables used in the model
|
|
90
110
|
self.__mx = {}
|
|
@@ -319,6 +339,17 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
319
339
|
"""
|
|
320
340
|
Initialize state vector with default values
|
|
321
341
|
|
|
342
|
+
Initial values are first read from the given Modelica files.
|
|
343
|
+
If an initial value equals zero or is not provided by a Modelica file,
|
|
344
|
+
and the variable is not marked as fixed,
|
|
345
|
+
then the initial value is tried to be set with the initial_state method.
|
|
346
|
+
When using CSVMixin, this method by default looks for initial values
|
|
347
|
+
in an initial_state.csv file.
|
|
348
|
+
Furthermore, if a variable is not marked as fixed
|
|
349
|
+
and no initial value is given by the initial_state method,
|
|
350
|
+
the initial value can be overwritten using the seed method.
|
|
351
|
+
When a variable is marked as fixed, the initial value is only read from the Modelica file.
|
|
352
|
+
|
|
322
353
|
:param config_file: Path to an initialization file.
|
|
323
354
|
"""
|
|
324
355
|
if config_file:
|
|
@@ -393,29 +424,33 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
393
424
|
for var in itertools.chain(self.__pymoca_model.states, self.__pymoca_model.alg_states):
|
|
394
425
|
var_name = var.symbol.name()
|
|
395
426
|
var_nominal = self.get_variable_nominal(var_name)
|
|
427
|
+
start_values = {}
|
|
396
428
|
|
|
397
429
|
# Attempt to cast var.start to python type
|
|
398
430
|
mx_start = ca.MX(var.start)
|
|
399
431
|
if mx_start.is_constant():
|
|
400
432
|
# cast var.start to python type
|
|
401
|
-
|
|
433
|
+
start_value_pymoca = var.python_type(mx_start.to_DM())
|
|
434
|
+
if start_value_pymoca is not None and start_value_pymoca != 0:
|
|
435
|
+
start_values["modelica"] = start_value_pymoca
|
|
402
436
|
else:
|
|
403
|
-
|
|
404
|
-
start_val = None
|
|
437
|
+
start_values["modelica"] = mx_start
|
|
405
438
|
|
|
406
|
-
if
|
|
439
|
+
if not var.fixed:
|
|
407
440
|
# To make initialization easier, we allow setting initial states by providing
|
|
408
441
|
# timeseries with names that match a symbol in the model. We only check for this
|
|
409
442
|
# matching if the start and fixed attributes were left as default
|
|
410
443
|
try:
|
|
411
|
-
|
|
444
|
+
start_values["initial_state"] = self.initial_state()[var_name]
|
|
412
445
|
except KeyError:
|
|
413
446
|
pass
|
|
414
447
|
else:
|
|
415
448
|
# An initial state was found- add it to the constrained residuals
|
|
416
449
|
logger.debug(
|
|
417
450
|
"Initialize: Added {} = {} to initial equations "
|
|
418
|
-
"(found matching timeseries).".format(
|
|
451
|
+
"(found matching timeseries).".format(
|
|
452
|
+
var_name, start_values["initial_state"]
|
|
453
|
+
)
|
|
419
454
|
)
|
|
420
455
|
# Set var to be fixed
|
|
421
456
|
var.fixed = True
|
|
@@ -425,36 +460,82 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
425
460
|
# timeseries with names that match a symbol in the model. We only check for this
|
|
426
461
|
# matching if the start and fixed attributes were left as default
|
|
427
462
|
try:
|
|
428
|
-
|
|
463
|
+
start_values["seed"] = self.seed()[var_name]
|
|
429
464
|
except KeyError:
|
|
430
465
|
pass
|
|
431
466
|
else:
|
|
432
467
|
# An initial state was found- add it to the constrained residuals
|
|
433
468
|
logger.debug(
|
|
434
469
|
"Initialize: Added {} = {} as initial guess "
|
|
435
|
-
"(found matching timeseries).".format(var_name,
|
|
470
|
+
"(found matching timeseries).".format(var_name, start_values["seed"])
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
# Set the start value based on the different inputs.
|
|
474
|
+
if "seed" in start_values:
|
|
475
|
+
input_source = "seed"
|
|
476
|
+
source_description = "seed method"
|
|
477
|
+
elif "modelica" in start_values:
|
|
478
|
+
input_source = "modelica"
|
|
479
|
+
source_description = "modelica file"
|
|
480
|
+
elif "initial_state" in start_values:
|
|
481
|
+
input_source = "initial_state"
|
|
482
|
+
source_description = "initial_state method (typically reads initial_state.csv)"
|
|
483
|
+
else:
|
|
484
|
+
start_values["modelica"] = start_value_pymoca
|
|
485
|
+
input_source = "modelica"
|
|
486
|
+
source_description = "modelica file or default value"
|
|
487
|
+
start_val = start_values.get(input_source, None)
|
|
488
|
+
start_is_numeric = start_val is not None and not isinstance(start_val, ca.MX)
|
|
489
|
+
numeric_start_val = start_val if start_is_numeric else 0.0
|
|
490
|
+
if len(start_values) > 1:
|
|
491
|
+
logger.warning(
|
|
492
|
+
"Initialize: Multiple initial values for {} are provided: {}.".format(
|
|
493
|
+
var_name, start_values
|
|
436
494
|
)
|
|
495
|
+
+ " Value from {} will be used to continue.".format(source_description)
|
|
496
|
+
)
|
|
437
497
|
|
|
438
498
|
# Attempt to set start_val in the state vector. Default to zero if unknown.
|
|
439
499
|
try:
|
|
440
|
-
self.set_var(var_name,
|
|
500
|
+
self.set_var(var_name, numeric_start_val)
|
|
441
501
|
except KeyError:
|
|
442
502
|
logger.warning(
|
|
443
|
-
"Initialize: {} not found in state vector. "
|
|
444
|
-
|
|
503
|
+
"Initialize: {} not found in state vector. Initial value of {} not set.".format(
|
|
504
|
+
var_name, numeric_start_val
|
|
505
|
+
)
|
|
445
506
|
)
|
|
446
507
|
|
|
447
508
|
# Add a residual for the difference between the state and its starting expression
|
|
448
|
-
start_expr = start_val
|
|
509
|
+
start_expr = start_val
|
|
510
|
+
min_is_symbolic = isinstance(var.min, ca.MX)
|
|
511
|
+
max_is_symbolic = isinstance(var.max, ca.MX)
|
|
449
512
|
if var.fixed:
|
|
450
513
|
# Set bounds to be equal to each other, such that IPOPT can
|
|
451
514
|
# turn the decision variable into a parameter.
|
|
515
|
+
if min_is_symbolic or max_is_symbolic or var.min != -np.inf or var.max != np.inf:
|
|
516
|
+
logger.info(
|
|
517
|
+
"Initialize: bounds of {} will be overwritten".format(var_name)
|
|
518
|
+
+ " by the start value given by {}.".format(source_description)
|
|
519
|
+
)
|
|
452
520
|
var.min = start_expr
|
|
453
521
|
var.max = start_expr
|
|
454
522
|
else:
|
|
455
523
|
# minimize residual
|
|
456
524
|
minimized_residuals.append((var.symbol - start_expr) / var_nominal)
|
|
457
525
|
|
|
526
|
+
# Check that the start_value is in between the variable bounds.
|
|
527
|
+
if start_is_numeric and not min_is_symbolic and not max_is_symbolic:
|
|
528
|
+
if not (var.min <= start_val and start_val <= var.max):
|
|
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.",
|
|
537
|
+
)
|
|
538
|
+
|
|
458
539
|
# Default start var for ders is zero
|
|
459
540
|
for der_var in self.__mx["derivatives"]:
|
|
460
541
|
self.set_var(der_var.name(), 0.0)
|
|
@@ -610,7 +691,15 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
610
691
|
# If unsuccessful, stop.
|
|
611
692
|
return_status = solver.stats()["return_status"]
|
|
612
693
|
if return_status not in {"Solve_Succeeded", "Solved_To_Acceptable_Level"}:
|
|
613
|
-
|
|
694
|
+
if return_status == "Infeasible_Problem_Detected":
|
|
695
|
+
message = (
|
|
696
|
+
"Initialization Failed with return status: {}. ".format(return_status)
|
|
697
|
+
+ "This means no initial state could be found "
|
|
698
|
+
+ "that satisfies all equations and constraints."
|
|
699
|
+
)
|
|
700
|
+
else:
|
|
701
|
+
message = "Initialization Failed with return status: {}. ".format(return_status)
|
|
702
|
+
raise Exception(message)
|
|
614
703
|
|
|
615
704
|
# Update state vector with initial conditions
|
|
616
705
|
self.__state_vector[: self.__n_states] = initial_state["x"][: self.__n_states].T
|
|
@@ -762,6 +851,8 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
762
851
|
self.set_var("time", self.get_current_time() + dt)
|
|
763
852
|
|
|
764
853
|
# take a step
|
|
854
|
+
if np.isnan(self.__state_vector).any():
|
|
855
|
+
logger.error("Found a nan in the state vector (before making the step)")
|
|
765
856
|
guess = self.__state_vector[: self.__n_states]
|
|
766
857
|
if len(self.__mx["parameters"]) > 0:
|
|
767
858
|
next_state = self.__do_step(
|
|
@@ -769,6 +860,23 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
769
860
|
)
|
|
770
861
|
else:
|
|
771
862
|
next_state = self.__do_step(guess, dt, self.__state_vector)
|
|
863
|
+
|
|
864
|
+
try:
|
|
865
|
+
if np.isnan(next_state).any():
|
|
866
|
+
index_to_name = {index[0]: name for name, index in self.__indices.items()}
|
|
867
|
+
named_next_state = {
|
|
868
|
+
index_to_name[i]: float(next_state[i]) for i in range(0, next_state.shape[0])
|
|
869
|
+
}
|
|
870
|
+
variables_with_nan = [
|
|
871
|
+
name for name, value in named_next_state.items() if np.isnan(value)
|
|
872
|
+
]
|
|
873
|
+
if variables_with_nan:
|
|
874
|
+
logger.error(
|
|
875
|
+
f"Found nan(s) in the next_state vector for:\n\t {variables_with_nan}"
|
|
876
|
+
)
|
|
877
|
+
except (KeyError, IndexError, TypeError):
|
|
878
|
+
logger.warning("Something went wrong while checking for nans in the next_state vector")
|
|
879
|
+
|
|
772
880
|
# Check convergence of rootfinder
|
|
773
881
|
rootfinder_stats = self.__do_step.stats()
|
|
774
882
|
|
|
@@ -964,9 +1072,9 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
964
1072
|
:param dt: Timestep size of the simulation.
|
|
965
1073
|
"""
|
|
966
1074
|
if self._dt_is_fixed:
|
|
967
|
-
assert math.isclose(
|
|
968
|
-
|
|
969
|
-
)
|
|
1075
|
+
assert math.isclose(self.__dt, dt), (
|
|
1076
|
+
"Timestep size dt is marked as constant and cannot be changed."
|
|
1077
|
+
)
|
|
970
1078
|
else:
|
|
971
1079
|
self.__dt = dt
|
|
972
1080
|
|
|
@@ -1149,9 +1257,9 @@ class SimulationProblem(DataStoreAccessor):
|
|
|
1149
1257
|
# Where imported model libraries are located.
|
|
1150
1258
|
library_folders = self.modelica_library_folders.copy()
|
|
1151
1259
|
|
|
1152
|
-
for ep in
|
|
1260
|
+
for ep in importlib_metadata.entry_points(group="rtctools.libraries.modelica"):
|
|
1153
1261
|
if ep.name == "library_folder":
|
|
1154
|
-
library_folders.append(
|
|
1262
|
+
library_folders.append(str(importlib.resources.files(ep.module).joinpath(ep.attr)))
|
|
1155
1263
|
|
|
1156
1264
|
compiler_options["library_folders"] = library_folders
|
|
1157
1265
|
|
rtctools/util.py
CHANGED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
rtctools/__init__.py,sha256=91hvS2-ryd2Pvw0COpsUzTwJwSnTZ035REiej-1hNI4,107
|
|
2
|
-
rtctools/_version.py,sha256=dUPcNcf2xQ9Ynkv1d2c0aTxHuz_HBjht0yZ3i8NDzGc,499
|
|
3
|
-
rtctools/rtctoolsapp.py,sha256=A6M0v6vymAZWdBPLzgRVyAUfahD0knC8B4IptJ7_sBM,4097
|
|
4
|
-
rtctools/util.py,sha256=PaeKfDUA174ODZbY5fZjCTf-F-TdhW7yEuP189Ro190,9075
|
|
5
|
-
rtctools/_internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
rtctools/_internal/alias_tools.py,sha256=XuQSAhhFuVtwn0yrAObZWIKPsSF4j2axXRtEmitIFPs,5310
|
|
7
|
-
rtctools/_internal/caching.py,sha256=p4gqSL7kCI7Hff-KjMEP7mhJCQSiU_lYm2MR7E18gBM,905
|
|
8
|
-
rtctools/_internal/casadi_helpers.py,sha256=oAf5zyFkZbaMhvhgMnQkOi2A6dBOzj-VAUkYwBf-Jxk,1410
|
|
9
|
-
rtctools/_internal/debug_check_helpers.py,sha256=UgQTEPw4PyR7MbYLewSSWQqTwQj7xr5yUBk820O9Kk4,1084
|
|
10
|
-
rtctools/data/__init__.py,sha256=EllgSmCdrlvQZSd1VilvjPaeYJGhY9ErPiQtedmuFoA,157
|
|
11
|
-
rtctools/data/csv.py,sha256=iYOEED3AaNxt4ews_aAkHfl9Tq9a-9vjxvYwjVR_lQE,5231
|
|
12
|
-
rtctools/data/netcdf.py,sha256=xpk4Ggl7gItNG6lO7p3OJPR-elK8_CiCtxUI7cX0gwk,19109
|
|
13
|
-
rtctools/data/pi.py,sha256=hBgK_dSLv_V9pWFGNzOEnG76ffLsjW3SBSWfgVJpXSA,45380
|
|
14
|
-
rtctools/data/rtc.py,sha256=FBuUQ6aL4D3y6puKudyuLAeP_vmpDiliqzJg8f1kd7g,9043
|
|
15
|
-
rtctools/data/storage.py,sha256=67J4BRTl0AMEzlKNZ8Xdpy_4cGtwx8Lo_tL2n0G4S9w,13206
|
|
16
|
-
rtctools/data/interpolation/__init__.py,sha256=GBubCIT5mFoSTV-lOk7cpwvZekNMEe5bvqSQJ9HE34M,73
|
|
17
|
-
rtctools/data/interpolation/bspline.py,sha256=qevB842XWCH3fWlWMBqKMy1mw37ust-0YtSnb9PKCEc,948
|
|
18
|
-
rtctools/data/interpolation/bspline1d.py,sha256=hQrok4rrBcJV_HciuFjZYSwrSP8w_VufQRP6JLZhA7U,6106
|
|
19
|
-
rtctools/data/interpolation/bspline2d.py,sha256=ScmX0fPDxbUVtj3pbUE0L7UJocqroD_6fUT-4cvdRMc,1693
|
|
20
|
-
rtctools/optimization/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
-
rtctools/optimization/collocated_integrated_optimization_problem.py,sha256=Bv1a1O4QTAdIpe9SOA9_oEDDph-oj-9q5yfN4SFMdW8,131343
|
|
22
|
-
rtctools/optimization/control_tree_mixin.py,sha256=CC6TWp3kFQgMokx6213pRLx9iY17Fd0VcwG4Wpwa0Uo,8974
|
|
23
|
-
rtctools/optimization/csv_lookup_table_mixin.py,sha256=xiyOKpPT3kQ6yuxSJRorGYW_QwnlBzW6vvrtvQNhHsE,17264
|
|
24
|
-
rtctools/optimization/csv_mixin.py,sha256=sRp5paHWfCw2bz-23Nw-HdFLS3CZTpVwaBdFo98DbvE,12252
|
|
25
|
-
rtctools/optimization/goal_programming_mixin.py,sha256=GK25DrbAY_rMsra080pSCDZwzLQNN2Ppd-2d0_FEllg,32999
|
|
26
|
-
rtctools/optimization/goal_programming_mixin_base.py,sha256=oh9CsEiyYTmthcfvRbX-9Z9bIo6SHv_DCiVt9kx0sjI,43781
|
|
27
|
-
rtctools/optimization/homotopy_mixin.py,sha256=Kh0kMfxB-Fo1FBGW5tPOQk24Xx_Mmw_p0YuSQotdkMU,6905
|
|
28
|
-
rtctools/optimization/initial_state_estimation_mixin.py,sha256=74QYfG-VYYTNVg-kAnCG6QoY3_sUmaID0ideF7bPkkY,3116
|
|
29
|
-
rtctools/optimization/io_mixin.py,sha256=AsZQ7YOUcUbWoczmjTXaSje5MUEsPNbQyZBJ6qzSjzU,11821
|
|
30
|
-
rtctools/optimization/linearization_mixin.py,sha256=mG5S7uwvwDydw-eBPyQKnLyKoy08EBjQh25vu97afhY,1049
|
|
31
|
-
rtctools/optimization/linearized_order_goal_programming_mixin.py,sha256=LQ2qpYt0YGLpEoerif4FJ5wwzq16q--27bsRjcqIU5A,9087
|
|
32
|
-
rtctools/optimization/min_abs_goal_programming_mixin.py,sha256=WMOv9EF8cfDJgTunzXfI_cUmBSQK26u1HJB_9EAarfM,14031
|
|
33
|
-
rtctools/optimization/modelica_mixin.py,sha256=ysVMayNA4sSFoHkSdhjWOxT6UzOVbN0ZeM4v-RpvZXE,17161
|
|
34
|
-
rtctools/optimization/netcdf_mixin.py,sha256=-zkXh3sMYE50c3kHsrmUVGWMSFm-0cXQpGrCm0yn-Tc,7563
|
|
35
|
-
rtctools/optimization/optimization_problem.py,sha256=qzpc81NaZMeoXKuayFmBF15iXYuNAk5yxmaER_Gcz_A,44131
|
|
36
|
-
rtctools/optimization/pi_mixin.py,sha256=63qda6i7hjtDuP3hL6RO29vCCP11aUpR9B4KoqlLFVI,11314
|
|
37
|
-
rtctools/optimization/planning_mixin.py,sha256=O_Y74X8xZmaNZR4iYOe7BR06s9hnmcapbuHYHQTBPPQ,724
|
|
38
|
-
rtctools/optimization/single_pass_goal_programming_mixin.py,sha256=Zb9szg3PGT2o6gkGsXluSfEaAswkw3TKfPQDzUrj_Y4,25784
|
|
39
|
-
rtctools/optimization/timeseries.py,sha256=nCrsGCJThBMh9lvngEpbBDa834_QvklVvkxJqwX4a1M,1734
|
|
40
|
-
rtctools/simulation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
41
|
-
rtctools/simulation/csv_mixin.py,sha256=rGDUFPsqGHmF0_dWdXeWzWzMpkPmwCNweTBVrwSh31g,6704
|
|
42
|
-
rtctools/simulation/io_mixin.py,sha256=SJasNGI--OQ9Y-Z61oeeaGCxSrNddYz4AOVfJYbmf74,6209
|
|
43
|
-
rtctools/simulation/pi_mixin.py,sha256=uwl61LYjb8dmMz910EB2-bC0KSuhLzsrJzk0hxWYEhk,9359
|
|
44
|
-
rtctools/simulation/simulation_problem.py,sha256=gTAimG2MLw_TTkeHLkIMxpYgAmR-voqzvje7pcFnw4U,44556
|
|
45
|
-
rtc_tools-2.6.0b2.dist-info/COPYING.LESSER,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
|
|
46
|
-
rtc_tools-2.6.0b2.dist-info/METADATA,sha256=J_s90hgXnSTTIZg76jopXRUeL0V3VUJfOyvorAaE_1s,1452
|
|
47
|
-
rtc_tools-2.6.0b2.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
48
|
-
rtc_tools-2.6.0b2.dist-info/entry_points.txt,sha256=-x622IB_l1duw2M6t6syfQ4yzOiQTp0IZxKGcYRgWgk,151
|
|
49
|
-
rtc_tools-2.6.0b2.dist-info/top_level.txt,sha256=pnBrb58PFPd1kp1dqa-JHU7R55h3alDNJIJnF3Jf9Dw,9
|
|
50
|
-
rtc_tools-2.6.0b2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|