physioblocks 1.0.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.
- physioblocks/__init__.py +37 -0
- physioblocks/base/__init__.py +27 -0
- physioblocks/base/operators.py +176 -0
- physioblocks/base/registers.py +108 -0
- physioblocks/computing/__init__.py +47 -0
- physioblocks/computing/assembling.py +291 -0
- physioblocks/computing/models.py +811 -0
- physioblocks/computing/quantities.py +354 -0
- physioblocks/configuration/__init__.py +38 -0
- physioblocks/configuration/aliases.py +203 -0
- physioblocks/configuration/base.py +123 -0
- physioblocks/configuration/computing/__init__.py +27 -0
- physioblocks/configuration/computing/quantities.py +56 -0
- physioblocks/configuration/constants.py +121 -0
- physioblocks/configuration/description/__init__.py +33 -0
- physioblocks/configuration/description/blocks.py +239 -0
- physioblocks/configuration/description/nets.py +155 -0
- physioblocks/configuration/functions.py +695 -0
- physioblocks/configuration/simulation/__init__.py +32 -0
- physioblocks/configuration/simulation/simulations.py +280 -0
- physioblocks/description/__init__.py +34 -0
- physioblocks/description/blocks.py +418 -0
- physioblocks/description/flux.py +157 -0
- physioblocks/description/nets.py +746 -0
- physioblocks/io/__init__.py +29 -0
- physioblocks/io/aliases.py +73 -0
- physioblocks/io/configuration.py +125 -0
- physioblocks/launcher/__main__.py +285 -0
- physioblocks/launcher/configuration.py +231 -0
- physioblocks/launcher/configure/__main__.py +99 -0
- physioblocks/launcher/constants.py +105 -0
- physioblocks/launcher/files.py +150 -0
- physioblocks/launcher/series.py +165 -0
- physioblocks/library/__init__.py +27 -0
- physioblocks/library/aliases/blocks/c_block.json +5 -0
- physioblocks/library/aliases/blocks/rc_block.json +5 -0
- physioblocks/library/aliases/blocks/rcr_block.json +5 -0
- physioblocks/library/aliases/blocks/spherical_cavity_block.json +5 -0
- physioblocks/library/aliases/blocks/valve_rl_block.json +5 -0
- physioblocks/library/aliases/flux/heart_flux_dof_couples.jsonc +4 -0
- physioblocks/library/aliases/model_components/active_law_macro_huxley_two_moments.json +5 -0
- physioblocks/library/aliases/model_components/rheology_fiber_additive.json +5 -0
- physioblocks/library/aliases/model_components/spherical_dynamics.json +5 -0
- physioblocks/library/aliases/model_components/velocity_law_hht.json +5 -0
- physioblocks/library/aliases/nets/circulation_alone_net.json +31 -0
- physioblocks/library/aliases/nets/spherical_heart_net.json +93 -0
- physioblocks/library/aliases/simulations/circulation_alone_forward_simulation.jsonc +55 -0
- physioblocks/library/aliases/simulations/default_forward_simulation.jsonc +7 -0
- physioblocks/library/aliases/simulations/default_time.jsonc +8 -0
- physioblocks/library/aliases/simulations/newton_method_solver.json +5 -0
- physioblocks/library/aliases/simulations/spherical_heart_forward_simulation.jsonc +157 -0
- physioblocks/library/aliases/simulations/spherical_heart_with_respiration_forward_simulation.jsonc +45 -0
- physioblocks/library/blocks/__init__.py +27 -0
- physioblocks/library/blocks/capacitances.py +516 -0
- physioblocks/library/blocks/cavity.py +192 -0
- physioblocks/library/blocks/valves.py +281 -0
- physioblocks/library/functions/__init__.py +27 -0
- physioblocks/library/functions/base_operations.py +129 -0
- physioblocks/library/functions/first_order.py +113 -0
- physioblocks/library/functions/piecewise.py +271 -0
- physioblocks/library/functions/trigonometric.py +78 -0
- physioblocks/library/functions/watchers.py +113 -0
- physioblocks/library/model_components/__init__.py +27 -0
- physioblocks/library/model_components/active_law.py +345 -0
- physioblocks/library/model_components/dynamics.py +986 -0
- physioblocks/library/model_components/rheology.py +160 -0
- physioblocks/library/model_components/velocity_law.py +169 -0
- physioblocks/references/circulation_alone_sim.jsonc +24 -0
- physioblocks/references/spherical_heart_respiration_sim.jsonc +33 -0
- physioblocks/references/spherical_heart_sim.jsonc +29 -0
- physioblocks/registers/__init__.py +32 -0
- physioblocks/registers/load_function_register.py +93 -0
- physioblocks/registers/save_function_register.py +106 -0
- physioblocks/registers/type_register.py +97 -0
- physioblocks/simulation/__init__.py +48 -0
- physioblocks/simulation/constants.py +30 -0
- physioblocks/simulation/functions.py +71 -0
- physioblocks/simulation/runtime.py +484 -0
- physioblocks/simulation/saved_quantities.py +129 -0
- physioblocks/simulation/setup.py +576 -0
- physioblocks/simulation/solvers.py +235 -0
- physioblocks/simulation/state.py +340 -0
- physioblocks/simulation/time_manager.py +354 -0
- physioblocks/utils/__init__.py +27 -0
- physioblocks/utils/dynamic_import_utils.py +150 -0
- physioblocks/utils/exceptions_utils.py +115 -0
- physioblocks/utils/gradient_test_utils.py +337 -0
- physioblocks/utils/math_utils.py +109 -0
- physioblocks-1.0.0.dist-info/METADATA +127 -0
- physioblocks-1.0.0.dist-info/RECORD +93 -0
- physioblocks-1.0.0.dist-info/WHEEL +4 -0
- physioblocks-1.0.0.dist-info/licenses/licenses/GPL-3.0-only.txt +674 -0
- physioblocks-1.0.0.dist-info/licenses/licenses/LGPL-3.0-only.txt +165 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright INRIA
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: LGPL-3.0-only
|
|
4
|
+
#
|
|
5
|
+
# Copyright INRIA
|
|
6
|
+
#
|
|
7
|
+
# This file is part of PhysioBlocks, a library mostly developed by the
|
|
8
|
+
# [Ananke project-team](https://team.inria.fr/ananke) at INRIA.
|
|
9
|
+
#
|
|
10
|
+
# Authors:
|
|
11
|
+
# - Colin Drieu
|
|
12
|
+
# - Dominique Chapelle
|
|
13
|
+
# - François Kimmig
|
|
14
|
+
# - Philippe Moireau
|
|
15
|
+
#
|
|
16
|
+
# PhysioBlocks is free software: you can redistribute it and/or modify it under the
|
|
17
|
+
# terms of the GNU Lesser General Public License as published by the Free Software
|
|
18
|
+
# Foundation, version 3 of the License.
|
|
19
|
+
#
|
|
20
|
+
# PhysioBlocks is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
21
|
+
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
22
|
+
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
23
|
+
#
|
|
24
|
+
# You should have received a copy of the GNU Lesser General Public License along with
|
|
25
|
+
# PhysioBlocks. If not, see <https://www.gnu.org/licenses/>.
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
Defines read and write files functions
|
|
29
|
+
"""
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright INRIA
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: LGPL-3.0-only
|
|
4
|
+
#
|
|
5
|
+
# Copyright INRIA
|
|
6
|
+
#
|
|
7
|
+
# This file is part of PhysioBlocks, a library mostly developed by the
|
|
8
|
+
# [Ananke project-team](https://team.inria.fr/ananke) at INRIA.
|
|
9
|
+
#
|
|
10
|
+
# Authors:
|
|
11
|
+
# - Colin Drieu
|
|
12
|
+
# - Dominique Chapelle
|
|
13
|
+
# - François Kimmig
|
|
14
|
+
# - Philippe Moireau
|
|
15
|
+
#
|
|
16
|
+
# PhysioBlocks is free software: you can redistribute it and/or modify it under the
|
|
17
|
+
# terms of the GNU Lesser General Public License as published by the Free Software
|
|
18
|
+
# Foundation, version 3 of the License.
|
|
19
|
+
#
|
|
20
|
+
# PhysioBlocks is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
21
|
+
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
22
|
+
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
23
|
+
#
|
|
24
|
+
# You should have received a copy of the GNU Lesser General Public License along with
|
|
25
|
+
# PhysioBlocks. If not, see <https://www.gnu.org/licenses/>.
|
|
26
|
+
|
|
27
|
+
"""Defines methods to load aliases folders."""
|
|
28
|
+
|
|
29
|
+
from pathlib import Path
|
|
30
|
+
|
|
31
|
+
from physioblocks.configuration.aliases import add_alias
|
|
32
|
+
from physioblocks.io.configuration import read_json
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def load_aliases(path: str) -> None:
|
|
36
|
+
"""
|
|
37
|
+
Load all aliases recursively in the directory into the **Alias Register**.
|
|
38
|
+
|
|
39
|
+
.. warning::
|
|
40
|
+
|
|
41
|
+
The given key for each alias is its file name without extensions.
|
|
42
|
+
It has to be unique.
|
|
43
|
+
|
|
44
|
+
:param path: the alias directory path to load.
|
|
45
|
+
:type path: Path
|
|
46
|
+
"""
|
|
47
|
+
directory_path = Path(path)
|
|
48
|
+
|
|
49
|
+
if directory_path.is_dir() is False:
|
|
50
|
+
raise OSError(
|
|
51
|
+
str.format(
|
|
52
|
+
"Provided alias directory is not a folder: {0}",
|
|
53
|
+
directory_path,
|
|
54
|
+
)
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
if directory_path.exists() is False:
|
|
58
|
+
raise OSError(
|
|
59
|
+
str.format(
|
|
60
|
+
"Provided alias directory do not exist: {0}",
|
|
61
|
+
directory_path,
|
|
62
|
+
)
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
for child in directory_path.iterdir():
|
|
66
|
+
if child.is_dir():
|
|
67
|
+
# recursivly load child directories
|
|
68
|
+
load_aliases(str(child))
|
|
69
|
+
else:
|
|
70
|
+
config_alias = read_json(str(child))
|
|
71
|
+
# get file name without extension as alias id
|
|
72
|
+
alias_id = child.name.removesuffix(child.suffix)
|
|
73
|
+
add_alias(alias_id, config_alias)
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright INRIA
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: LGPL-3.0-only
|
|
4
|
+
#
|
|
5
|
+
# Copyright INRIA
|
|
6
|
+
#
|
|
7
|
+
# This file is part of PhysioBlocks, a library mostly developed by the
|
|
8
|
+
# [Ananke project-team](https://team.inria.fr/ananke) at INRIA.
|
|
9
|
+
#
|
|
10
|
+
# Authors:
|
|
11
|
+
# - Colin Drieu
|
|
12
|
+
# - Dominique Chapelle
|
|
13
|
+
# - François Kimmig
|
|
14
|
+
# - Philippe Moireau
|
|
15
|
+
#
|
|
16
|
+
# PhysioBlocks is free software: you can redistribute it and/or modify it under the
|
|
17
|
+
# terms of the GNU Lesser General Public License as published by the Free Software
|
|
18
|
+
# Foundation, version 3 of the License.
|
|
19
|
+
#
|
|
20
|
+
# PhysioBlocks is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
21
|
+
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
22
|
+
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
23
|
+
#
|
|
24
|
+
# You should have received a copy of the GNU Lesser General Public License along with
|
|
25
|
+
# PhysioBlocks. If not, see <https://www.gnu.org/licenses/>.
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
Defines methods to save and load
|
|
29
|
+
:class:`~physioblocks.configuration.base.Configuration` objects to a json file
|
|
30
|
+
|
|
31
|
+
.. note::
|
|
32
|
+
|
|
33
|
+
It is possible to save and load ``.jsonc`` files and use ``//`` characters to
|
|
34
|
+
comment the file.
|
|
35
|
+
|
|
36
|
+
The comments are discarded when the file is loaded: there are only here to increase
|
|
37
|
+
the json readability.
|
|
38
|
+
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
import json
|
|
42
|
+
import os
|
|
43
|
+
from pathlib import Path
|
|
44
|
+
from typing import Any
|
|
45
|
+
|
|
46
|
+
from physioblocks.configuration.base import Configuration
|
|
47
|
+
|
|
48
|
+
# Key giving the type of the configured object
|
|
49
|
+
_ITEM_TYPE_LABEL = "type"
|
|
50
|
+
|
|
51
|
+
# Character delimiting a comment
|
|
52
|
+
_COMMENT_CHAR = "//"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class _JSONConfigEncoder(json.JSONEncoder):
|
|
56
|
+
"""
|
|
57
|
+
Derive from the base JSONEncoder class to redefine the
|
|
58
|
+
encoding of Configuration and Configuration objects
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
def default(self, obj: Any) -> Any:
|
|
62
|
+
"""
|
|
63
|
+
Overwrite the default encoder method.
|
|
64
|
+
|
|
65
|
+
:param obj: the object to encode
|
|
66
|
+
:type obj: Any
|
|
67
|
+
|
|
68
|
+
:return: the encoded object
|
|
69
|
+
:rtype: dict[str, obj]
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
if isinstance(obj, Configuration):
|
|
73
|
+
item_dict: dict[str, Any]
|
|
74
|
+
item_dict = {}
|
|
75
|
+
item_dict[_ITEM_TYPE_LABEL] = obj.label
|
|
76
|
+
item_dict.update(obj.configuration_items)
|
|
77
|
+
|
|
78
|
+
return item_dict
|
|
79
|
+
|
|
80
|
+
return super().default(obj)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def write_json(file_path: str, config: Configuration) -> None:
|
|
84
|
+
"""
|
|
85
|
+
Write the :class:`~physioblocks.configuration.base.Configuration` object
|
|
86
|
+
to a json file
|
|
87
|
+
|
|
88
|
+
:param file_path: the path of the file to read
|
|
89
|
+
:type file_path: str
|
|
90
|
+
|
|
91
|
+
:param config: the configuration to write
|
|
92
|
+
:type config: Configuration
|
|
93
|
+
"""
|
|
94
|
+
config_json = json.dumps(config, cls=_JSONConfigEncoder, indent=4)
|
|
95
|
+
Path(file_path).write_text(config_json)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def read_json(file_path: str) -> Any:
|
|
99
|
+
"""
|
|
100
|
+
Read a :class:`~physioblocks.configuration.base.Configuration` from a json file
|
|
101
|
+
|
|
102
|
+
:param file_path: the path of the file to read
|
|
103
|
+
:type file_path: str
|
|
104
|
+
|
|
105
|
+
:return: the loaded configuration
|
|
106
|
+
:rtype: Configuration
|
|
107
|
+
"""
|
|
108
|
+
json_txt = Path(file_path).read_text()
|
|
109
|
+
|
|
110
|
+
uncommented_lines = [
|
|
111
|
+
line.split(_COMMENT_CHAR, 1)[0] for line in json_txt.splitlines()
|
|
112
|
+
]
|
|
113
|
+
uncommented_json_txt = os.linesep.join(uncommented_lines)
|
|
114
|
+
return json.loads(uncommented_json_txt, object_hook=_as_config)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _as_config(dict_obj: dict[Any, Any]) -> Any:
|
|
118
|
+
if _ITEM_TYPE_LABEL in dict_obj:
|
|
119
|
+
config_item = Configuration(
|
|
120
|
+
dict_obj[_ITEM_TYPE_LABEL],
|
|
121
|
+
{key: value for key, value in dict_obj.items() if key != _ITEM_TYPE_LABEL},
|
|
122
|
+
)
|
|
123
|
+
return config_item
|
|
124
|
+
|
|
125
|
+
return dict_obj
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright INRIA
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: LGPL-3.0-only
|
|
4
|
+
#
|
|
5
|
+
# Copyright INRIA
|
|
6
|
+
#
|
|
7
|
+
# This file is part of PhysioBlocks, a library mostly developed by the
|
|
8
|
+
# [Ananke project-team](https://team.inria.fr/ananke) at INRIA.
|
|
9
|
+
#
|
|
10
|
+
# Authors:
|
|
11
|
+
# - Colin Drieu
|
|
12
|
+
# - Dominique Chapelle
|
|
13
|
+
# - François Kimmig
|
|
14
|
+
# - Philippe Moireau
|
|
15
|
+
#
|
|
16
|
+
# PhysioBlocks is free software: you can redistribute it and/or modify it under the
|
|
17
|
+
# terms of the GNU Lesser General Public License as published by the Free Software
|
|
18
|
+
# Foundation, version 3 of the License.
|
|
19
|
+
#
|
|
20
|
+
# PhysioBlocks is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
21
|
+
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
22
|
+
# PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
|
23
|
+
#
|
|
24
|
+
# You should have received a copy of the GNU Lesser General Public License along with
|
|
25
|
+
# PhysioBlocks. If not, see <https://www.gnu.org/licenses/>.
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
Launch a simulation from a simulation configuration file and organize
|
|
29
|
+
the results in a simulation folder.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
import argparse
|
|
33
|
+
import logging
|
|
34
|
+
import site
|
|
35
|
+
import sys
|
|
36
|
+
from pathlib import Path
|
|
37
|
+
from typing import Any
|
|
38
|
+
|
|
39
|
+
import pandas as pd
|
|
40
|
+
|
|
41
|
+
import physioblocks.utils.exceptions_utils as exception_utils
|
|
42
|
+
from physioblocks.configuration import Configuration, load, unwrap_aliases
|
|
43
|
+
from physioblocks.io.configuration import read_json, write_json
|
|
44
|
+
from physioblocks.launcher.configuration import (
|
|
45
|
+
check_launcher_directory,
|
|
46
|
+
create_simulation_folder_path,
|
|
47
|
+
get_launcher_configuration,
|
|
48
|
+
import_configured_aliases,
|
|
49
|
+
import_configured_libraries,
|
|
50
|
+
)
|
|
51
|
+
from physioblocks.launcher.constants import (
|
|
52
|
+
LAUNCHER_COMPARE_TRACE_FILE_NAME,
|
|
53
|
+
LAUNCHER_SERIES_DIR_NAME,
|
|
54
|
+
)
|
|
55
|
+
from physioblocks.launcher.files import (
|
|
56
|
+
write_figure,
|
|
57
|
+
write_simulation_log_entry,
|
|
58
|
+
write_simulation_results,
|
|
59
|
+
)
|
|
60
|
+
from physioblocks.launcher.series import get_simulation_info
|
|
61
|
+
from physioblocks.simulation import AbstractSimulation, SimulationError
|
|
62
|
+
|
|
63
|
+
"""
|
|
64
|
+
.. note:: When deleting a serie from the launcher folder, or a specific simulation from
|
|
65
|
+
a serie, the launchers logs are updated the next time any simulation is launched.
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
SIMULATION_LOG_FORMATER = logging.Formatter(logging.BASIC_FORMAT)
|
|
69
|
+
_root_logger = logging.getLogger()
|
|
70
|
+
_root_logger.setLevel(logging.DEBUG)
|
|
71
|
+
|
|
72
|
+
# register a hook to log uncaught exceptions
|
|
73
|
+
sys.excepthook = exception_utils.create_uncaught_exception_logger_handler(_root_logger)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def load_configuration(config_file_path: Path) -> Any:
|
|
77
|
+
simulation_config = read_json(str(config_file_path))
|
|
78
|
+
return unwrap_aliases(simulation_config)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def run_simulation(config: Configuration) -> pd.DataFrame:
|
|
82
|
+
simulation: AbstractSimulation = load(config)
|
|
83
|
+
try:
|
|
84
|
+
results = simulation.run()
|
|
85
|
+
_root_logger.info("Simulation complete.")
|
|
86
|
+
except SimulationError as sim_error:
|
|
87
|
+
_root_logger.error(sim_error)
|
|
88
|
+
results = sim_error.intermediate_results
|
|
89
|
+
|
|
90
|
+
return pd.DataFrame(results)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def add_log_handler(handler: logging.Handler, level: str | int) -> None:
|
|
94
|
+
handler.setFormatter(SIMULATION_LOG_FORMATER)
|
|
95
|
+
handler.setLevel(level)
|
|
96
|
+
_root_logger.addHandler(handler)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def main(
|
|
100
|
+
root_sim_directory: Path,
|
|
101
|
+
config_file_path: Path,
|
|
102
|
+
series: str,
|
|
103
|
+
message: str,
|
|
104
|
+
extension: str,
|
|
105
|
+
trace: bool = False,
|
|
106
|
+
reference_file_path: Path | None = None,
|
|
107
|
+
rows_height: float = 200.0,
|
|
108
|
+
) -> int:
|
|
109
|
+
if check_launcher_directory(root_sim_directory) is False:
|
|
110
|
+
_root_logger.error(
|
|
111
|
+
str.format(
|
|
112
|
+
"{0} is not a suitable directory for the "
|
|
113
|
+
"launcher. Use the configure script to setup a new launcher directory.",
|
|
114
|
+
str(root_sim_directory.absolute()),
|
|
115
|
+
)
|
|
116
|
+
)
|
|
117
|
+
return -1
|
|
118
|
+
|
|
119
|
+
# Add site base libraries
|
|
120
|
+
site.addsitedir(str(root_sim_directory.absolute()))
|
|
121
|
+
|
|
122
|
+
# Prepare the series directory if necessary
|
|
123
|
+
serie_path = root_sim_directory / LAUNCHER_SERIES_DIR_NAME / series
|
|
124
|
+
if serie_path.exists() is False:
|
|
125
|
+
serie_path.mkdir(parents=True)
|
|
126
|
+
|
|
127
|
+
# Write the simulation log
|
|
128
|
+
sim_info = get_simulation_info(serie_path, message)
|
|
129
|
+
write_simulation_log_entry(root_sim_directory, sim_info)
|
|
130
|
+
sim_folder = create_simulation_folder_path(serie_path, sim_info)
|
|
131
|
+
|
|
132
|
+
# configure the simulation log file (always in DEBUG)
|
|
133
|
+
log_file_path = sim_folder / str.join(".", [sim_info.reference, "log"])
|
|
134
|
+
file_handler = logging.FileHandler(log_file_path)
|
|
135
|
+
add_log_handler(file_handler, logging.DEBUG)
|
|
136
|
+
|
|
137
|
+
# log the current simulation infos
|
|
138
|
+
_root_logger.info(str(sim_info))
|
|
139
|
+
|
|
140
|
+
launcher_configuration = get_launcher_configuration(root_sim_directory)
|
|
141
|
+
import_configured_libraries(launcher_configuration)
|
|
142
|
+
import_configured_aliases(launcher_configuration)
|
|
143
|
+
|
|
144
|
+
# Load configuration and unwrap aliases
|
|
145
|
+
sim_config = load_configuration(config_file_path)
|
|
146
|
+
|
|
147
|
+
# copy the unwrapped simulation configuration file to the simulation folder
|
|
148
|
+
write_json(str(sim_folder / config_file_path.name), sim_config)
|
|
149
|
+
|
|
150
|
+
# run the simulation
|
|
151
|
+
data = run_simulation(sim_config)
|
|
152
|
+
|
|
153
|
+
# write the result
|
|
154
|
+
write_simulation_results(sim_folder, sim_info, data, extension)
|
|
155
|
+
|
|
156
|
+
# trace the simulation result if needed.
|
|
157
|
+
if trace is True:
|
|
158
|
+
data = data.set_index("time")
|
|
159
|
+
write_figure(
|
|
160
|
+
data, sim_folder, str.join(".", [sim_info.reference, "html"]), rows_height
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
if reference_file_path is not None:
|
|
164
|
+
df_ref = pd.read_csv(reference_file_path, sep=";").set_index("time")
|
|
165
|
+
error_df = abs(df_ref - data)
|
|
166
|
+
write_figure(
|
|
167
|
+
error_df, sim_folder, LAUNCHER_COMPARE_TRACE_FILE_NAME, rows_height
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
return 0
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
if __name__ == "__main__":
|
|
174
|
+
# arguments handling
|
|
175
|
+
|
|
176
|
+
parser = argparse.ArgumentParser(
|
|
177
|
+
description=__doc__, formatter_class=argparse.HelpFormatter
|
|
178
|
+
)
|
|
179
|
+
parser.add_argument(
|
|
180
|
+
"simulation_configuration",
|
|
181
|
+
help="The simulation configuration file path.",
|
|
182
|
+
)
|
|
183
|
+
parser.add_argument(
|
|
184
|
+
"-d",
|
|
185
|
+
"--launcher_directory",
|
|
186
|
+
default="./",
|
|
187
|
+
required=False,
|
|
188
|
+
help="A valid folder for the launcher to run (initialized with the configure "
|
|
189
|
+
"script)",
|
|
190
|
+
)
|
|
191
|
+
parser.add_argument(
|
|
192
|
+
"-s",
|
|
193
|
+
"--series",
|
|
194
|
+
dest="series",
|
|
195
|
+
default="Z",
|
|
196
|
+
required=False,
|
|
197
|
+
help="The series name to save the simulation result.",
|
|
198
|
+
)
|
|
199
|
+
parser.add_argument(
|
|
200
|
+
"-m",
|
|
201
|
+
"--message",
|
|
202
|
+
dest="message",
|
|
203
|
+
default="",
|
|
204
|
+
required=False,
|
|
205
|
+
help="A optional comment on the simulation",
|
|
206
|
+
)
|
|
207
|
+
parser.add_argument(
|
|
208
|
+
"-v",
|
|
209
|
+
"--verbose",
|
|
210
|
+
dest="verbose",
|
|
211
|
+
action="store_true",
|
|
212
|
+
default=False,
|
|
213
|
+
required=False,
|
|
214
|
+
help="Display logs in console",
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
parser.add_argument(
|
|
218
|
+
"-l",
|
|
219
|
+
"--log_level",
|
|
220
|
+
dest="log_level",
|
|
221
|
+
default="INFO",
|
|
222
|
+
choices=["INFO", "DEBUG", "WARNING", "ERROR", "CRITICAL"],
|
|
223
|
+
required=False,
|
|
224
|
+
help="Level of the console logs",
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
parser.add_argument(
|
|
228
|
+
"-ext",
|
|
229
|
+
"--file_extension",
|
|
230
|
+
dest="extension",
|
|
231
|
+
default="csv",
|
|
232
|
+
required=False,
|
|
233
|
+
help="The file extension to write the simulation results.",
|
|
234
|
+
choices=["csv", "parquet"],
|
|
235
|
+
)
|
|
236
|
+
parser.add_argument(
|
|
237
|
+
"-t",
|
|
238
|
+
"--trace",
|
|
239
|
+
dest="trace",
|
|
240
|
+
default="False",
|
|
241
|
+
required=False,
|
|
242
|
+
action="store_true",
|
|
243
|
+
help="Set to True to save a html graph of the results. Default is False",
|
|
244
|
+
)
|
|
245
|
+
parser.add_argument(
|
|
246
|
+
"--compare",
|
|
247
|
+
dest="reference",
|
|
248
|
+
required=False,
|
|
249
|
+
help="Set a reference file to compare against the simulation results"
|
|
250
|
+
"(column names must match).",
|
|
251
|
+
)
|
|
252
|
+
parser.add_argument(
|
|
253
|
+
"--rows_height",
|
|
254
|
+
dest="rows_height",
|
|
255
|
+
default=200.0,
|
|
256
|
+
required=False,
|
|
257
|
+
help="Height of each row in the graph if any.",
|
|
258
|
+
)
|
|
259
|
+
args = parser.parse_args()
|
|
260
|
+
|
|
261
|
+
# setup logger when verbose
|
|
262
|
+
if args.verbose is True:
|
|
263
|
+
stdout_handler = logging.StreamHandler(sys.stdout)
|
|
264
|
+
add_log_handler(stdout_handler, args.log_level)
|
|
265
|
+
|
|
266
|
+
# create paths from arguments
|
|
267
|
+
root_folder_path = Path(args.launcher_directory).absolute()
|
|
268
|
+
config_file_path = Path(args.simulation_configuration).absolute()
|
|
269
|
+
reference_file_path = (
|
|
270
|
+
Path(args.reference).absolute() if args.reference is not None else None
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
rows_heights = float(args.rows_height)
|
|
274
|
+
sys.exit(
|
|
275
|
+
main(
|
|
276
|
+
root_sim_directory=root_folder_path,
|
|
277
|
+
config_file_path=config_file_path,
|
|
278
|
+
series=args.series,
|
|
279
|
+
message=args.message,
|
|
280
|
+
extension=args.extension,
|
|
281
|
+
trace=args.trace,
|
|
282
|
+
reference_file_path=reference_file_path,
|
|
283
|
+
rows_height=rows_heights,
|
|
284
|
+
)
|
|
285
|
+
)
|