fmu-manipulation-toolbox 1.8.4.2rc1__tar.gz → 1.9rc0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/PKG-INFO +1 -1
  2. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/README.md +24 -9
  3. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/__version__.py +1 -0
  4. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/assembly.py +14 -7
  5. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/checker.py +5 -3
  6. fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox/fmu_container.py → fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/container.py +71 -63
  7. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/gui.py +1 -1
  8. fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox/fmu_operations.py → fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/operations.py +35 -19
  9. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Annotation.xsd +51 -0
  10. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3AttributeGroups.xsd +119 -0
  11. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3BuildDescription.xsd +117 -0
  12. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3InterfaceType.xsd +80 -0
  13. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3LayeredStandardManifest.xsd +93 -0
  14. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3ModelDescription.xsd +131 -0
  15. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Terminal.xsd +87 -0
  16. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3TerminalsAndIcons.xsd +84 -0
  17. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Type.xsd +207 -0
  18. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Unit.xsd +69 -0
  19. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Variable.xsd +413 -0
  20. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3VariableDependency.xsd +64 -0
  21. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/linux64/container.so +0 -0
  22. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/win32/client_sm.dll +0 -0
  23. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/win32/server_sm.exe +0 -0
  24. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/win64/client_sm.dll +0 -0
  25. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/win64/container.dll +0 -0
  26. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/win64/server_sm.exe +0 -0
  27. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/split.py +314 -0
  28. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox.egg-info/PKG-INFO +1 -1
  29. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox.egg-info/SOURCES.txt +15 -3
  30. fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox.egg-info/entry_points.txt +7 -0
  31. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/setup.py +6 -2
  32. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/tests/test_suite.py +13 -3
  33. fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox/__version__.py +0 -1
  34. fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox/cli.py +0 -235
  35. fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox/resources/linux64/container.so +0 -0
  36. fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox/resources/win64/client_sm.dll +0 -0
  37. fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox/resources/win64/container.dll +0 -0
  38. fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox/resources/win64/server_sm.exe +0 -0
  39. fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox.egg-info/entry_points.txt +0 -3
  40. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/LICENSE.txt +0 -0
  41. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/__init__.py +0 -0
  42. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/__main__.py +0 -0
  43. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/gui_style.py +0 -0
  44. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/help.py +0 -0
  45. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/checkbox-checked-disabled.png +0 -0
  46. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/checkbox-checked-hover.png +0 -0
  47. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/checkbox-checked.png +0 -0
  48. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/checkbox-unchecked-disabled.png +0 -0
  49. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/checkbox-unchecked-hover.png +0 -0
  50. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/checkbox-unchecked.png +0 -0
  51. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/container.png +0 -0
  52. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/drop_fmu.png +0 -0
  53. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Annotation.xsd +0 -0
  54. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2AttributeGroups.xsd +0 -0
  55. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2ModelDescription.xsd +0 -0
  56. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2ScalarVariable.xsd +0 -0
  57. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Type.xsd +0 -0
  58. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Unit.xsd +0 -0
  59. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2VariableDependency.xsd +0 -0
  60. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmu.png +0 -0
  61. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmu_manipulation_toolbox.png +0 -0
  62. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/help.png +0 -0
  63. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/icon-round.png +0 -0
  64. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/icon.png +0 -0
  65. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/icon_fmu.png +0 -0
  66. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/license.txt +0 -0
  67. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/linux32/client_sm.so +0 -0
  68. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/linux32/server_sm +0 -0
  69. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/linux64/client_sm.so +0 -0
  70. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/linux64/server_sm +0 -0
  71. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/mask.png +0 -0
  72. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/model.png +0 -0
  73. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/version.py +0 -0
  74. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox.egg-info/dependency_links.txt +0 -0
  75. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox.egg-info/requires.txt +0 -0
  76. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox.egg-info/top_level.txt +0 -0
  77. {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmu_manipulation_toolbox
3
- Version: 1.8.4.2rc1
3
+ Version: 1.9rc0
4
4
  Summary: FMU Manipulation Toolbox is a python application for modifying Functional Mock-up Units (FMUs) without recompilation or bundling them into FMU Containers
5
5
  Home-page: https://github.com/grouperenault/fmu_manipulation_toolbox/
6
6
  Author: Nicolas.LAURENT@Renault.com
@@ -12,12 +12,21 @@ FMU Manipulation Toolbox also allows to group FMU's inside FMU Containers. (see
12
12
 
13
13
  Two options available to install FMU Manipulation Toolbox:
14
14
 
15
- - (Easiest option) Install with from PyPI: `python -m pip install fmu_manipulation`
15
+ - (*Easiest option*) Install with from PyPI: `pip install fmu-manipulation-toolbox`. This will install the latest
16
+ version of FMU Manipulation Toolbox and all its dependencies. See [PyPI page](https://pypi.org/project/fmu-manipulation-toolbox/).
16
17
  - Compile and install from [github repository](https://github.com/grouperenault/fmu_manipulation_toolbox). You will need
17
- - Python required packages. See `requirements.txt`.
18
- - C compiler
18
+ - Python required packages. See [`requirements.txt`](requirements.txt).
19
+ - C compiler (C99 or later)
20
+ - CMake (>= 3.16)
21
+
22
+ ### Supported platforms
23
+ FMU Manipulation Toolbox is tested on:
24
+ - Windows 10/11
25
+ - Linux (Ubuntu 22.04)
26
+
27
+ Compilation is reported to work on:
28
+ - MacOS (Apple Silicon and Intel)
19
29
 
20
-
21
30
  ## Graphical User Interface
22
31
 
23
32
  FMU Manipulation Toolbox is released with a GUI. You can launch it with the following command `fmutool`
@@ -122,24 +131,29 @@ optional arguments:
122
131
  ### FMU Containers
123
132
 
124
133
  ```
125
- usage: fmucontainer [-h] [-fmu-directory FMU_DIRECTORY] -container filename.{csv|json|ssp},[:step_size] [-debug]
126
- [-no-auto-input] [-no-auto-output] [-auto-parameter] [-no-auto-link] [-mt] [-profile] [-dump-json]
134
+ usage: fmucontainer [-h] [-fmu-directory FMU_DIRECTORY] [-fmi FMI_VERSION]
135
+ -container filename.{csv|json|ssp},[:step_size] [-debug] [-no-auto-input] [-no-auto-output]
136
+ [-auto-parameter] [-auto-local] [-no-auto-link] [-mt] [-profile] [-sequential] [-dump-json]
127
137
 
128
138
  Generate FMU from FMU's
129
139
 
130
- optional arguments:
140
+ options:
131
141
  -h, -help
132
142
  -fmu-directory FMU_DIRECTORY Directory containing initial FMU’s and used to generate containers. If not defined,
133
143
  current directory is used. (default: .)
144
+ -fmi FMI_VERSION Define version of FMI to be used for container interface.Only '2' or '3' is
145
+ supported. (default: 2)
134
146
  -container filename.{csv|json|ssp},[:step_size]
135
147
  Description of the container to create. (default: [])
136
148
  -debug Add lot of useful log during the process. (default: False)
137
149
  -no-auto-input Create ONLY explicit input. (default: True)
138
150
  -no-auto-output Create ONLY explicit output. (default: True)
139
151
  -auto-parameter Expose parameters of the embedded fmu's. (default: False)
152
+ -auto-local Expose local variables of the embedded fmu's. (default: False)
140
153
  -no-auto-link Create ONLY explicit links. (default: True)
141
154
  -mt Enable Multi-Threaded mode for the generated container. (default: False)
142
155
  -profile Enable Profiling mode for the generated container. (default: False)
156
+ -sequential Use sequential mode to schedule embedded fmu's. (default: False)
143
157
  -dump-json Dump a JSON file for each container. (default: False)
144
158
  ```
145
159
 
@@ -149,8 +163,9 @@ You can write your own FMU Manipulation scripts. Once you downloaded fmutool mod
149
163
  adding the `import` statement lets you access the API :
150
164
 
151
165
  ```python
152
- from fmu_manipulation_toolbox.fmu_operations import FMU, OperationExtractNames, OperationStripTopLevel,
153
- OperationRenameFromCSV
166
+ from fmu_manipulation_toolbox.operations import FMU, OperationExtractNames, OperationStripTopLevel,
167
+
168
+ OperationRenameFromCSV
154
169
  ```
155
170
 
156
171
  ### remove toplevel bus (if any)
@@ -7,7 +7,7 @@ import uuid
7
7
  import xml.parsers.expat
8
8
  import zipfile
9
9
 
10
- from .fmu_container import FMUContainer, AutoWired
10
+ from .container import FMUContainer, AutoWired
11
11
 
12
12
  logger = logging.getLogger("fmu_manipulation_toolbox")
13
13
 
@@ -37,7 +37,7 @@ class Connection:
37
37
 
38
38
 
39
39
  class AssemblyNode:
40
- def __init__(self, name: Optional[str], step_size: float = None, mt=False, profiling=False,
40
+ def __init__(self, name: Optional[str], step_size: float = None, mt=False, profiling=False, sequential=False,
41
41
  auto_link=True, auto_input=True, auto_output=True, auto_parameter=False, auto_local=False):
42
42
  self.name = name
43
43
  if step_size:
@@ -50,6 +50,7 @@ class AssemblyNode:
50
50
  self.step_size = None
51
51
  self.mt = mt
52
52
  self.profiling = profiling
53
+ self.sequential = sequential
53
54
  self.auto_link = auto_link
54
55
  self.auto_input = auto_input
55
56
  self.auto_output = auto_output
@@ -138,7 +139,8 @@ class AssemblyNode:
138
139
  for link_rule in wired.rule_link:
139
140
  self.add_link(link_rule[0], link_rule[1], link_rule[2], link_rule[3])
140
141
 
141
- container.make_fmu(self.name, self.step_size, mt=self.mt, profiling=self.profiling, debug=debug)
142
+ container.make_fmu(self.name, self.step_size, mt=self.mt, profiling=self.profiling, sequential=self.sequential,
143
+ debug=debug)
142
144
 
143
145
  for node in self.children.values():
144
146
  logger.info(f"Deleting transient FMU Container '{node.name}'")
@@ -216,7 +218,7 @@ class AssemblyError(Exception):
216
218
 
217
219
 
218
220
  class Assembly:
219
- def __init__(self, filename: str, step_size=None, auto_link=True, auto_input=True, debug=False,
221
+ def __init__(self, filename: str, step_size=None, auto_link=True, auto_input=True, debug=False, sequential=False,
220
222
  auto_output=True, mt=False, profiling=False, fmu_directory: Path = Path("."), auto_parameter=False,
221
223
  auto_local=False):
222
224
  self.filename = Path(filename)
@@ -228,6 +230,7 @@ class Assembly:
228
230
  self.default_auto_parameter = auto_parameter
229
231
  self.default_auto_local = auto_local
230
232
  self.default_mt = mt
233
+ self.default_sequential = sequential
231
234
  self.default_profiling = profiling
232
235
  self.fmu_directory = fmu_directory
233
236
  self.transient_filenames: List[Path] = []
@@ -283,8 +286,9 @@ class Assembly:
283
286
  name = str(self.filename.with_suffix(".fmu"))
284
287
  self.root = AssemblyNode(name, step_size=self.default_step_size, auto_link=self.default_auto_link,
285
288
  mt=self.default_mt, profiling=self.default_profiling,
286
- auto_input=self.default_auto_input, auto_output=self.default_auto_output,
287
- auto_parameter=self.default_auto_parameter, auto_local=self.default_auto_local)
289
+ sequential=self.default_sequential, auto_input=self.default_auto_input,
290
+ auto_output=self.default_auto_output, auto_parameter=self.default_auto_parameter,
291
+ auto_local=self.default_auto_local)
288
292
 
289
293
  with open(self.input_pathname) as file:
290
294
  reader = csv.reader(file, delimiter=';')
@@ -385,6 +389,7 @@ class Assembly:
385
389
  name = data.get("name", None) # 1
386
390
  mt = data.get("mt", self.default_mt) # 2
387
391
  profiling = data.get("profiling", self.default_profiling) # 3
392
+ sequential = data.get("sequential", self.default_sequential) # 3b
388
393
  auto_link = data.get("auto_link", self.default_auto_link) # 4
389
394
  auto_input = data.get("auto_input", self.default_auto_input) # 5
390
395
  auto_output = data.get("auto_output", self.default_auto_output) # 6
@@ -393,11 +398,12 @@ class Assembly:
393
398
  step_size = data.get("step_size", self.default_step_size) # 7
394
399
 
395
400
  node = AssemblyNode(name, step_size=step_size, auto_link=auto_link, mt=mt, profiling=profiling,
401
+ sequential=sequential,
396
402
  auto_input=auto_input, auto_output=auto_output, auto_parameter=auto_parameter,
397
403
  auto_local=auto_local)
398
404
 
399
405
  for key, value in data.items():
400
- if key in ('name', 'step_size', 'auto_link', 'auto_input', 'auto_output', 'mt', 'profiling',
406
+ if key in ('name', 'step_size', 'auto_link', 'auto_input', 'auto_output', 'mt', 'profiling', 'sequential',
401
407
  'auto_parameter', 'auto_local'):
402
408
  continue # Already read
403
409
 
@@ -455,6 +461,7 @@ class Assembly:
455
461
  json_node["name"] = node.name # 1
456
462
  json_node["mt"] = node.mt # 2
457
463
  json_node["profiling"] = node.profiling # 3
464
+ json_node["sequential"] = node.sequential # 3b
458
465
  json_node["auto_link"] = node.auto_link # 4
459
466
  json_node["auto_input"] = node.auto_input # 5
460
467
  json_node["auto_output"] = node.auto_output # 6
@@ -3,11 +3,11 @@ import inspect
3
3
  import os
4
4
  import xmlschema
5
5
  from xmlschema.validators.exceptions import XMLSchemaValidationError
6
- from .fmu_operations import OperationAbstract
6
+ from .operations import OperationAbstract
7
7
 
8
8
 
9
9
  class OperationGenericCheck(OperationAbstract):
10
- SUPPORTED_FMI_VERSIONS = ('2.0',)
10
+ SUPPORTED_FMI_VERSIONS = ('2.0', '3.0')
11
11
 
12
12
  def __init__(self):
13
13
  self.compliant_with_version = None
@@ -20,8 +20,10 @@ class OperationGenericCheck(OperationAbstract):
20
20
  print(f"ERROR: Expected FMI {','.join(self.SUPPORTED_FMI_VERSIONS)} versions.")
21
21
  return
22
22
 
23
+ fmi_name = f"fmi{attrs['fmiVersion'][0]}"
24
+
23
25
  xsd_filename = os.path.join(os.path.dirname(__file__), "resources", "fmi-" + attrs['fmiVersion'],
24
- "fmi2ModelDescription.xsd")
26
+ f"{fmi_name}ModelDescription.xsd")
25
27
  try:
26
28
  xmlschema.validate(self.fmu.descriptor_filename, schema=xsd_filename)
27
29
  except XMLSchemaValidationError as error:
@@ -7,7 +7,7 @@ from datetime import datetime
7
7
  from pathlib import Path
8
8
  from typing import *
9
9
 
10
- from .fmu_operations import FMU, OperationAbstract
10
+ from .operations import FMU, OperationAbstract, FMUError
11
11
  from .version import __version__ as tool_version
12
12
 
13
13
 
@@ -16,55 +16,61 @@ logger = logging.getLogger("fmu_manipulation_toolbox")
16
16
 
17
17
  class FMUPort:
18
18
  def __init__(self, attrs: Dict[str, str]):
19
- self.name = attrs["name"]
20
- self.vr = int(attrs["valueReference"])
21
19
  self.causality = attrs.get("causality", "local")
22
- self.attrs = attrs.copy()
23
- self.attrs.pop("name")
24
- self.attrs.pop("valueReference")
25
- if "causality" in self.attrs:
26
- self.attrs.pop("causality")
27
- self.type_name = None
28
- self.child = None
20
+ self.variability = attrs.get("variability", "continuous")
21
+ self.name = attrs.get("name")
22
+ self.vr = int(attrs.get("valueReference"))
23
+ self.description = attrs.get("description", None)
24
+
25
+ self.type_name = attrs.get("type_name", None)
26
+ self.start_value = attrs.get("start", None)
27
+ self.initial = attrs.get("initial", None)
29
28
 
30
29
  def set_port_type(self, type_name: str, attrs: Dict[str, str]):
31
30
  self.type_name = type_name
32
- self.child = attrs.copy()
33
- for unsupported in ("unit", "declaredType"):
34
- if unsupported in self.child:
35
- self.child.pop(unsupported)
36
-
37
- def xml(self, vr: int, name=None, causality=None, start=None):
38
-
39
- if self.child is None:
40
- raise FMUContainerError(f"FMUPort has no child. Bug?")
41
-
42
- child_str = f"<{self.type_name}"
43
- if self.child:
44
- if start is not None and 'start' in self.child:
45
- self.child['start'] = start
46
- child_str += " " + " ".join([f'{key}="{value}"' for (key, value) in self.child.items()]) + "/>"
47
- else:
48
- child_str += "/>"
31
+ self.start_value = attrs.pop("start", None)
32
+ self.initial = attrs.pop("initial", None)
49
33
 
34
+ def xml(self, vr: int, name=None, causality=None, start=None, fmi_version=2):
50
35
  if name is None:
51
36
  name = self.name
52
37
  if causality is None:
53
38
  causality = self.causality
54
-
55
- variability = "continuous" if self.type_name == "Real" else "discrete"
56
-
57
- scalar_attrs = {
58
- "name": name,
59
- "valueReference": vr,
60
- "causality": causality,
61
- "variability": variability,
62
- }
63
- scalar_attrs.update(self.attrs)
64
-
65
- scalar_attrs_str = " ".join([f'{key}="{value}"' for (key, value) in scalar_attrs.items()])
66
-
67
- return f'<ScalarVariable {scalar_attrs_str}>{child_str}</ScalarVariable>'
39
+ if start is None:
40
+ start = self.start_value
41
+ if self.variability is None:
42
+ self.variability = "continuous" if self.type_name == "Real" else "discrete"
43
+
44
+
45
+ if fmi_version == 2:
46
+ child_dict = {
47
+ "start": start,
48
+ }
49
+ if "Float" in self.type_name:
50
+ type_name = "Real"
51
+ elif "Int" in self.type_name:
52
+ type_name = "Integer"
53
+ else:
54
+ type_name = self.type_name
55
+
56
+ child_str = (f"<{type_name} " +
57
+ " ".join([f'{key}="{value}"' if value is not None else ""
58
+ for (key, value) in child_dict.items()]) +
59
+ "/>")
60
+
61
+ scalar_attrs = {
62
+ "name": name,
63
+ "valueReference": vr,
64
+ "causality": causality,
65
+ "variability": self.variability,
66
+ "initial": self.initial,
67
+ "description": self.description,
68
+ }
69
+ scalar_attrs_str = " ".join([f'{key}="{value}"' if value is not None else ""
70
+ for (key, value) in scalar_attrs.items()])
71
+ return f'<ScalarVariable {scalar_attrs_str}>{child_str}</ScalarVariable>'
72
+ else:
73
+ return f'FIX ME'
68
74
 
69
75
 
70
76
  class EmbeddedFMU(OperationAbstract):
@@ -76,7 +82,6 @@ class EmbeddedFMU(OperationAbstract):
76
82
  self.name = Path(filename).name
77
83
  self.id = Path(filename).stem
78
84
 
79
- self.fmi_version = None
80
85
  self.step_size = None
81
86
  self.start_time = None
82
87
  self.stop_time = None
@@ -92,12 +97,22 @@ class EmbeddedFMU(OperationAbstract):
92
97
  raise FMUContainerError(f"FMU '{self.name}' does not implement Co-Simulation mode.")
93
98
 
94
99
  def fmi_attrs(self, attrs):
95
- self.guid = attrs['guid']
96
- self.fmi_version = attrs['fmiVersion']
100
+ fmi_version = attrs['fmiVersion']
101
+ if fmi_version == "2.0":
102
+ self.guid = attrs['guid']
103
+ if fmi_version == "3.0":
104
+ self.guid = attrs['instantiationToken']
105
+
97
106
 
98
107
  def scalar_attrs(self, attrs) -> int:
99
- self.current_port = FMUPort(attrs)
100
- self.ports[self.current_port.name] = self.current_port
108
+ if 'type_name' in attrs: # FMI 3.0
109
+ type_name = attrs.pop('type_name')
110
+ port = FMUPort(attrs)
111
+ port.type_name = type_name
112
+ self.ports[port.name] = port
113
+ else: # FMI 2.0
114
+ self.current_port = FMUPort(attrs)
115
+ self.ports[self.current_port.name] = self.current_port
101
116
 
102
117
  return 0
103
118
 
@@ -199,6 +214,7 @@ class ValueReferenceTable:
199
214
  def __init__(self):
200
215
  self.vr_table: Dict[str, int] = {
201
216
  "Real": 0,
217
+ "Float64": 0,
202
218
  "Integer": 0,
203
219
  "Boolean": 0,
204
220
  "String": 0,
@@ -268,10 +284,8 @@ class FMUContainer:
268
284
  fmu = EmbeddedFMU(self.fmu_directory / fmu_filename)
269
285
  self.involved_fmu[fmu.name] = fmu
270
286
  self.execution_order.append(fmu)
271
- if not fmu.fmi_version == "2.0":
272
- raise FMUContainerError("Only FMI-2.0 is supported by FMUContainer")
273
287
  logger.debug(f"Adding FMU #{len(self.execution_order)}: {fmu}")
274
- except Exception as e:
288
+ except (FMUContainerError, FMUError) as e:
275
289
  raise FMUContainerError(f"Cannot load '{fmu_filename}': {e}")
276
290
 
277
291
  return fmu
@@ -346,9 +360,9 @@ class FMUContainer:
346
360
  cport = ContainerPort(self.get_fmu(fmu_filename), port_name)
347
361
 
348
362
  try:
349
- if cport.port.type_name == 'Real':
363
+ if cport.port.type_name in ('Real', 'Float64', 'Float32'):
350
364
  value = float(value)
351
- elif cport.port.type_name == 'Integer':
365
+ elif cport.port.type_name in ('Integer', 'Int8', 'UInt8', 'Int16', 'UInt16', 'Int32', 'UInt32', 'Int64', 'UInt64'):
352
366
  value = int(value)
353
367
  elif cport.port.type_name == 'Boolean':
354
368
  value = int(bool(value))
@@ -451,7 +465,7 @@ class FMUContainer:
451
465
  logger.warning(f"{cport} is not connected")
452
466
 
453
467
  def make_fmu(self, fmu_filename: Union[str, Path], step_size: Optional[float] = None, debug=False, mt=False,
454
- profiling=False):
468
+ profiling=False, sequential=False):
455
469
  if isinstance(fmu_filename, str):
456
470
  fmu_filename = Path(fmu_filename)
457
471
 
@@ -467,7 +481,7 @@ class FMUContainer:
467
481
  with open(base_directory / "modelDescription.xml", "wt") as xml_file:
468
482
  self.make_fmu_xml(xml_file, step_size, profiling)
469
483
  with open(resources_directory / "container.txt", "wt") as txt_file:
470
- self.make_fmu_txt(txt_file, step_size, mt, profiling)
484
+ self.make_fmu_txt(txt_file, step_size, mt, profiling, sequential)
471
485
 
472
486
  self.make_fmu_package(base_directory, fmu_filename)
473
487
  if not debug:
@@ -580,16 +594,10 @@ class FMUContainer:
580
594
  </fmiModelDescription>
581
595
  """)
582
596
 
583
- def make_fmu_txt(self, txt_file, step_size: float, mt: bool, profiling: bool):
584
- if mt:
585
- print("# Use MT\n1", file=txt_file)
586
- else:
587
- print("# Don't use MT\n0", file=txt_file)
588
-
589
- if profiling:
590
- print("# Profiling ENABLED\n1", file=txt_file)
591
- else:
592
- print("# Profiling DISABLED\n0", file=txt_file)
597
+ def make_fmu_txt(self, txt_file, step_size: float, mt: bool, profiling: bool, sequential: bool):
598
+ print("# Container flags <MT> <Profiling> <Sequential>", file=txt_file)
599
+ flags = [ str(int(flag == True)) for flag in (mt, profiling, sequential)]
600
+ print(" ".join(flags), file=txt_file)
593
601
 
594
602
  print(f"# Internal time step in seconds", file=txt_file)
595
603
  print(f"{step_size}", file=txt_file)
@@ -12,7 +12,7 @@ from functools import partial
12
12
  from typing import Optional
13
13
 
14
14
  from .gui_style import gui_style
15
- from .fmu_operations import *
15
+ from .operations import *
16
16
  from .assembly import Assembly, AssemblyNode
17
17
  from .checker import checker_list
18
18
  from .help import Help
@@ -8,23 +8,29 @@ import xml.parsers.expat
8
8
  import zipfile
9
9
  import hashlib
10
10
  from pathlib import Path
11
+ from typing import *
11
12
 
12
13
 
13
14
  class FMU:
14
15
  """Unpack and Repack facilities for FMU package. Once unpacked, we can process Operation on
15
16
  modelDescription.xml file."""
17
+
18
+ FMI2_TYPES = ('Real', 'Integer', 'String', 'Boolean', 'Enumeration')
19
+ FMI3_TYPES = ('Float64')
20
+
16
21
  def __init__(self, fmu_filename):
17
22
  self.fmu_filename = fmu_filename
18
23
  self.tmp_directory = tempfile.mkdtemp()
24
+ self.fmi_version = None
19
25
 
20
26
  try:
21
27
  with zipfile.ZipFile(self.fmu_filename) as zin:
22
28
  zin.extractall(self.tmp_directory)
23
29
  except FileNotFoundError:
24
- raise FMUException(f"'{fmu_filename}' does not exist")
30
+ raise FMUError(f"'{fmu_filename}' does not exist")
25
31
  self.descriptor_filename = os.path.join(self.tmp_directory, "modelDescription.xml")
26
32
  if not os.path.isfile(self.descriptor_filename):
27
- raise FMUException(f"'{fmu_filename}' is not valid: {self.descriptor_filename} not found")
33
+ raise FMUError(f"'{fmu_filename}' is not valid: {self.descriptor_filename} not found")
28
34
 
29
35
  def __del__(self):
30
36
  shutil.rmtree(self.tmp_directory)
@@ -45,7 +51,7 @@ class FMU:
45
51
  manipulation.manipulate(self.descriptor_filename, apply_on)
46
52
 
47
53
 
48
- class FMUException(Exception):
54
+ class FMUError(Exception):
49
55
  def __init__(self, reason):
50
56
  self.reason = reason
51
57
 
@@ -63,12 +69,13 @@ class Manipulation:
63
69
  self.parser.StartElementHandler = self.start_element
64
70
  self.parser.EndElementHandler = self.end_element
65
71
  self.parser.CharacterDataHandler = self.char_data
66
- self.skip_until = None
72
+ self.skip_until: Optional[str] = None
67
73
  self.operation.set_fmu(fmu)
74
+ self.fmu = fmu
68
75
 
69
- self.current_port = 0
70
- self.port_translation = []
71
- self.port_name = []
76
+ self.current_port: int = 0
77
+ self.port_translation: List[int] = []
78
+ self.port_names_list: List[str] = []
72
79
  self.apply_on = None
73
80
 
74
81
  @staticmethod
@@ -78,19 +85,27 @@ class Manipulation:
78
85
  else:
79
86
  return value
80
87
 
88
+ def start_variable(self, attrs):
89
+ causality = OperationAbstract.scalar_get_causality(attrs)
90
+ port_name = attrs['name']
91
+ if not self.apply_on or causality in self.apply_on:
92
+ if self.operation.scalar_attrs(attrs):
93
+ self.remove_port(port_name)
94
+ else:
95
+ self.keep_port(port_name)
96
+ else: # Keep ScalarVariable as it is.
97
+ self.keep_port(port_name)
98
+
99
+
81
100
  def start_element(self, name, attrs):
82
101
  if self.skip_until:
83
102
  return
84
103
  try:
85
104
  if name == 'ScalarVariable':
86
- causality = OperationAbstract.scalar_get_causality(attrs)
87
- if not self.apply_on or causality in self.apply_on:
88
- if self.operation.scalar_attrs(attrs):
89
- self.remove_port(attrs['name'])
90
- else:
91
- self.keep_port(attrs['name'])
92
- else: # Keep ScalarVariable as it is.
93
- self.keep_port(attrs['name'])
105
+ self.start_variable(attrs)
106
+ elif name in self.fmu.FMI3_TYPES:
107
+ attrs['type_name'] = name
108
+ self.start_variable(attrs)
94
109
  elif name == 'CoSimulation':
95
110
  self.operation.cosimulation_attrs(attrs)
96
111
  elif name == 'DefaultExperiment':
@@ -99,7 +114,7 @@ class Manipulation:
99
114
  self.operation.fmi_attrs(attrs)
100
115
  elif name == 'Unknown':
101
116
  self.unknown_attrs(attrs)
102
- elif name in ('Real', 'Integer', 'String', 'Boolean', 'Enumeration'):
117
+ elif name in self.fmu.FMI2_TYPES:
103
118
  self.operation.scalar_type(name, attrs)
104
119
 
105
120
  except ManipulationSkipTag:
@@ -107,6 +122,7 @@ class Manipulation:
107
122
  return
108
123
 
109
124
  if attrs:
125
+ attrs.pop('fmi_type', None) # FMI 3.0: this attr was added during manipulation
110
126
  attrs_list = [f'{key}="{self.escape(value)}"' for (key, value) in attrs.items()]
111
127
  print(f"<{name}", " ".join(attrs_list), ">", end='', file=self.out)
112
128
  else:
@@ -125,12 +141,12 @@ class Manipulation:
125
141
  print(data, end='', file=self.out)
126
142
 
127
143
  def remove_port(self, name):
128
- self.port_name.append(name)
144
+ self.port_names_list.append(name)
129
145
  self.port_translation.append(None)
130
146
  raise ManipulationSkipTag
131
147
 
132
148
  def keep_port(self, name):
133
- self.port_name.append(name)
149
+ self.port_names_list.append(name)
134
150
  self.current_port += 1
135
151
  self.port_translation.append(self.current_port)
136
152
 
@@ -140,7 +156,7 @@ class Manipulation:
140
156
  if new_index:
141
157
  attrs['index'] = self.port_translation[int(attrs['index']) - 1]
142
158
  else:
143
- print(f"WARNING: Removed port '{self.port_name[index]}' is involved in dependencies tree.")
159
+ print(f"WARNING: Removed port '{self.port_names_list[index]}' is involved in dependencies tree.")
144
160
  raise ManipulationSkipTag
145
161
 
146
162
  def manipulate(self, descriptor_filename, apply_on=None):
@@ -0,0 +1,51 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
3
+ <xs:annotation>
4
+ <xs:documentation>
5
+ Copyright(c) 2008-2011 MODELISAR consortium,
6
+ 2012-2024 Modelica Association Project "FMI".
7
+ All rights reserved.
8
+
9
+ This file is licensed by the copyright holders under the 2-Clause BSD License
10
+ (https://opensource.org/licenses/BSD-2-Clause):
11
+
12
+ ----------------------------------------------------------------------------
13
+ Redistribution and use in source and binary forms, with or without
14
+ modification, are permitted provided that the following conditions are met:
15
+
16
+ - Redistributions of source code must retain the above copyright notice,
17
+ this list of conditions and the following disclaimer.
18
+
19
+ - Redistributions in binary form must reproduce the above copyright notice,
20
+ this list of conditions and the following disclaimer in the documentation
21
+ and/or other materials provided with the distribution.
22
+
23
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
27
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
30
+ OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
33
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+ ----------------------------------------------------------------------------
35
+ </xs:documentation>
36
+ </xs:annotation>
37
+ <xs:complexType name="fmi3Annotations">
38
+ <xs:sequence maxOccurs="unbounded">
39
+ <xs:element name="Annotation">
40
+ <xs:complexType mixed="true">
41
+ <xs:sequence>
42
+ <xs:any namespace="##any" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
43
+ </xs:sequence>
44
+ <xs:attribute name="type" type="xs:normalizedString" use="required">
45
+ </xs:attribute>
46
+ </xs:complexType>
47
+ </xs:element>
48
+ </xs:sequence>
49
+ </xs:complexType>
50
+ <xs:element name="Annotations" type="fmi3Annotations"/>
51
+ </xs:schema>