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.
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/PKG-INFO +1 -1
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/README.md +24 -9
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/__version__.py +1 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/assembly.py +14 -7
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/checker.py +5 -3
- 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
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/gui.py +1 -1
- 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
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Annotation.xsd +51 -0
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3AttributeGroups.xsd +119 -0
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3BuildDescription.xsd +117 -0
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3InterfaceType.xsd +80 -0
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3LayeredStandardManifest.xsd +93 -0
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3ModelDescription.xsd +131 -0
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Terminal.xsd +87 -0
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3TerminalsAndIcons.xsd +84 -0
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Type.xsd +207 -0
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Unit.xsd +69 -0
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Variable.xsd +413 -0
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3VariableDependency.xsd +64 -0
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/linux64/container.so +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/win32/client_sm.dll +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/win32/server_sm.exe +0 -0
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/win64/client_sm.dll +0 -0
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/win64/container.dll +0 -0
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/resources/win64/server_sm.exe +0 -0
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox/split.py +314 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox.egg-info/PKG-INFO +1 -1
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox.egg-info/SOURCES.txt +15 -3
- fmu_manipulation_toolbox-1.9rc0/fmu_manipulation_toolbox.egg-info/entry_points.txt +7 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/setup.py +6 -2
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/tests/test_suite.py +13 -3
- fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox/__version__.py +0 -1
- fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox/cli.py +0 -235
- fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox/resources/linux64/container.so +0 -0
- fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox/resources/win64/client_sm.dll +0 -0
- fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox/resources/win64/container.dll +0 -0
- fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox/resources/win64/server_sm.exe +0 -0
- fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox.egg-info/entry_points.txt +0 -3
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/LICENSE.txt +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/__init__.py +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/__main__.py +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/gui_style.py +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/help.py +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/checkbox-checked-disabled.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/checkbox-checked-hover.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/checkbox-checked.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/checkbox-unchecked-disabled.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/checkbox-unchecked-hover.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/checkbox-unchecked.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/container.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/drop_fmu.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Annotation.xsd +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2AttributeGroups.xsd +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2ModelDescription.xsd +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2ScalarVariable.xsd +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Type.xsd +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Unit.xsd +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2VariableDependency.xsd +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmu.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/fmu_manipulation_toolbox.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/help.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/icon-round.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/icon.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/icon_fmu.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/license.txt +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/linux32/client_sm.so +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/linux32/server_sm +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/linux64/client_sm.so +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/linux64/server_sm +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/mask.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/resources/model.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox/version.py +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox.egg-info/dependency_links.txt +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox.egg-info/requires.txt +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.9rc0}/fmu_manipulation_toolbox.egg-info/top_level.txt +0 -0
- {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.
|
|
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: `
|
|
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] -
|
|
126
|
-
|
|
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
|
-
|
|
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.
|
|
153
|
-
|
|
166
|
+
from fmu_manipulation_toolbox.operations import FMU, OperationExtractNames, OperationStripTopLevel,
|
|
167
|
+
|
|
168
|
+
OperationRenameFromCSV
|
|
154
169
|
```
|
|
155
170
|
|
|
156
171
|
### remove toplevel bus (if any)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'V1.9-pre0'
|
|
@@ -7,7 +7,7 @@ import uuid
|
|
|
7
7
|
import xml.parsers.expat
|
|
8
8
|
import zipfile
|
|
9
9
|
|
|
10
|
-
from .
|
|
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,
|
|
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
|
-
|
|
287
|
-
|
|
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 .
|
|
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
|
-
"
|
|
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 .
|
|
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.
|
|
23
|
-
self.attrs.
|
|
24
|
-
self.attrs.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
self.type_name = None
|
|
28
|
-
self.
|
|
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.
|
|
33
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
96
|
-
|
|
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
|
-
|
|
100
|
-
|
|
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
|
|
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
|
|
363
|
+
if cport.port.type_name in ('Real', 'Float64', 'Float32'):
|
|
350
364
|
value = float(value)
|
|
351
|
-
elif cport.port.type_name
|
|
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
|
-
|
|
585
|
-
|
|
586
|
-
|
|
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 .
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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>
|