fmu-manipulation-toolbox 1.8.4.2rc1__tar.gz → 1.8.4.3b0__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.8.4.3b0}/PKG-INFO +1 -1
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/README.md +16 -6
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/__version__.py +1 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/assembly.py +1 -1
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/checker.py +5 -3
- fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox/fmu_container.py → fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/container.py +66 -52
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/gui.py +1 -1
- fmu_manipulation_toolbox-1.8.4.2rc1/fmu_manipulation_toolbox/fmu_operations.py → fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/operations.py +35 -19
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Annotation.xsd +51 -0
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3AttributeGroups.xsd +119 -0
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3BuildDescription.xsd +117 -0
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3InterfaceType.xsd +80 -0
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3LayeredStandardManifest.xsd +93 -0
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3ModelDescription.xsd +131 -0
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Terminal.xsd +87 -0
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3TerminalsAndIcons.xsd +84 -0
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Type.xsd +207 -0
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Unit.xsd +69 -0
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Variable.xsd +413 -0
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3VariableDependency.xsd +64 -0
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/resources/linux64/container.so +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/win32/client_sm.dll +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/win32/server_sm.exe +0 -0
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/resources/win64/client_sm.dll +0 -0
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/resources/win64/container.dll +0 -0
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/resources/win64/server_sm.exe +0 -0
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/split.py +298 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox.egg-info/PKG-INFO +1 -1
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox.egg-info/SOURCES.txt +15 -3
- fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox.egg-info/entry_points.txt +7 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/setup.py +6 -2
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/tests/test_suite.py +3 -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.8.4.3b0}/LICENSE.txt +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/__init__.py +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/__main__.py +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/gui_style.py +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/help.py +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/checkbox-checked-disabled.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/checkbox-checked-hover.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/checkbox-checked.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/checkbox-unchecked-disabled.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/checkbox-unchecked-hover.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/checkbox-unchecked.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/container.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/drop_fmu.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Annotation.xsd +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2AttributeGroups.xsd +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2ModelDescription.xsd +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2ScalarVariable.xsd +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Type.xsd +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Unit.xsd +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/fmi-2.0/fmi2VariableDependency.xsd +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/fmu.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/fmu_manipulation_toolbox.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/help.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/icon-round.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/icon.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/icon_fmu.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/license.txt +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/linux32/client_sm.so +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/linux32/server_sm +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/linux64/client_sm.so +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/linux64/server_sm +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/mask.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/resources/model.png +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox/version.py +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox.egg-info/dependency_links.txt +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox.egg-info/requires.txt +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/fmu_manipulation_toolbox.egg-info/top_level.txt +0 -0
- {fmu_manipulation_toolbox-1.8.4.2rc1 → fmu_manipulation_toolbox-1.8.4.3b0}/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.
|
|
3
|
+
Version: 1.8.4.3b0
|
|
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`
|
|
@@ -149,8 +158,9 @@ You can write your own FMU Manipulation scripts. Once you downloaded fmutool mod
|
|
|
149
158
|
adding the `import` statement lets you access the API :
|
|
150
159
|
|
|
151
160
|
```python
|
|
152
|
-
from fmu_manipulation_toolbox.
|
|
153
|
-
|
|
161
|
+
from fmu_manipulation_toolbox.operations import FMU, OperationExtractNames, OperationStripTopLevel,
|
|
162
|
+
|
|
163
|
+
OperationRenameFromCSV
|
|
154
164
|
```
|
|
155
165
|
|
|
156
166
|
### remove toplevel bus (if any)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
'V1.8.4.3-beta'
|
|
@@ -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.
|
|
20
|
-
self.
|
|
21
|
-
self.
|
|
22
|
-
self.
|
|
23
|
-
self.attrs.pop("
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
self.
|
|
28
|
-
self.child = None
|
|
19
|
+
self.causality = attrs.pop("causality", "local")
|
|
20
|
+
self.variability = attrs.pop("variability", "continuous")
|
|
21
|
+
self.name = attrs.pop("name")
|
|
22
|
+
self.vr = int(attrs.pop("valueReference"))
|
|
23
|
+
self.description = attrs.pop("description", None)
|
|
24
|
+
|
|
25
|
+
self.type_name = attrs.pop("type_name", None)
|
|
26
|
+
self.start_value = attrs.pop("start", None)
|
|
27
|
+
self.initial = attrs.pop("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))
|
|
@@ -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):
|
fmu_manipulation_toolbox-1.8.4.3b0/fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Annotation.xsd
ADDED
|
@@ -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>
|
|
@@ -0,0 +1,119 @@
|
|
|
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:attributeGroup name="fmi3RealBaseAttributes">
|
|
38
|
+
<xs:attribute name="quantity" type="xs:normalizedString"/>
|
|
39
|
+
<xs:attribute name="unit" type="xs:normalizedString"/>
|
|
40
|
+
<xs:attribute name="displayUnit" type="xs:normalizedString"/>
|
|
41
|
+
<xs:attribute name="relativeQuantity" type="xs:boolean" default="false"/>
|
|
42
|
+
<xs:attribute name="unbounded" type="xs:boolean" default="false"/>
|
|
43
|
+
</xs:attributeGroup>
|
|
44
|
+
<xs:attributeGroup name="fmi3Float64Attributes">
|
|
45
|
+
<xs:attribute name="min" type="xs:double"/>
|
|
46
|
+
<xs:attribute name="max" type="xs:double"/>
|
|
47
|
+
<xs:attribute name="nominal" type="xs:double"/>
|
|
48
|
+
</xs:attributeGroup>
|
|
49
|
+
<xs:attributeGroup name="fmi3Float32Attributes">
|
|
50
|
+
<xs:attribute name="min" type="xs:float"/>
|
|
51
|
+
<xs:attribute name="max" type="xs:float"/>
|
|
52
|
+
<xs:attribute name="nominal" type="xs:float"/>
|
|
53
|
+
</xs:attributeGroup>
|
|
54
|
+
<xs:attributeGroup name="fmi3IntegerBaseAttributes">
|
|
55
|
+
<xs:attribute name="quantity" type="xs:normalizedString"/>
|
|
56
|
+
</xs:attributeGroup>
|
|
57
|
+
<xs:attributeGroup name="fmi3Int8Attributes">
|
|
58
|
+
<xs:attribute name="min" type="xs:byte"/>
|
|
59
|
+
<xs:attribute name="max" type="xs:byte"/>
|
|
60
|
+
</xs:attributeGroup>
|
|
61
|
+
<xs:attributeGroup name="fmi3UInt8Attributes">
|
|
62
|
+
<xs:attribute name="min" type="xs:unsignedByte"/>
|
|
63
|
+
<xs:attribute name="max" type="xs:unsignedByte"/>
|
|
64
|
+
</xs:attributeGroup>
|
|
65
|
+
<xs:attributeGroup name="fmi3Int16Attributes">
|
|
66
|
+
<xs:attribute name="min" type="xs:short"/>
|
|
67
|
+
<xs:attribute name="max" type="xs:short"/>
|
|
68
|
+
</xs:attributeGroup>
|
|
69
|
+
<xs:attributeGroup name="fmi3UInt16Attributes">
|
|
70
|
+
<xs:attribute name="min" type="xs:unsignedShort"/>
|
|
71
|
+
<xs:attribute name="max" type="xs:unsignedShort"/>
|
|
72
|
+
</xs:attributeGroup>
|
|
73
|
+
<xs:attributeGroup name="fmi3Int32Attributes">
|
|
74
|
+
<xs:attribute name="min" type="xs:int"/>
|
|
75
|
+
<xs:attribute name="max" type="xs:int"/>
|
|
76
|
+
</xs:attributeGroup>
|
|
77
|
+
<xs:attributeGroup name="fmi3UInt32Attributes">
|
|
78
|
+
<xs:attribute name="min" type="xs:unsignedInt"/>
|
|
79
|
+
<xs:attribute name="max" type="xs:unsignedInt"/>
|
|
80
|
+
</xs:attributeGroup>
|
|
81
|
+
<xs:attributeGroup name="fmi3Int64Attributes">
|
|
82
|
+
<xs:attribute name="min" type="xs:long"/>
|
|
83
|
+
<xs:attribute name="max" type="xs:long"/>
|
|
84
|
+
</xs:attributeGroup>
|
|
85
|
+
<xs:attributeGroup name="fmi3UInt64Attributes">
|
|
86
|
+
<xs:attribute name="min" type="xs:unsignedLong"/>
|
|
87
|
+
<xs:attribute name="max" type="xs:unsignedLong"/>
|
|
88
|
+
</xs:attributeGroup>
|
|
89
|
+
<xs:attributeGroup name="fmi3RealVariableAttributes">
|
|
90
|
+
<xs:attribute name="derivative" type="xs:unsignedInt"/>
|
|
91
|
+
<xs:attribute name="reinit" type="xs:boolean" default="false"/>
|
|
92
|
+
</xs:attributeGroup>
|
|
93
|
+
<xs:attributeGroup name="fmi3EnumerationAttributes">
|
|
94
|
+
<xs:attribute name="min" type="xs:long"/>
|
|
95
|
+
<xs:attribute name="max" type="xs:long"/>
|
|
96
|
+
</xs:attributeGroup>
|
|
97
|
+
<xs:attributeGroup name="fmi3ClockAttributes">
|
|
98
|
+
<xs:attribute name="canBeDeactivated" type="xs:boolean" default="false"/>
|
|
99
|
+
<xs:attribute name="priority" type="xs:unsignedInt" use="optional"/>
|
|
100
|
+
<xs:attribute name="intervalVariability" use="required">
|
|
101
|
+
<xs:simpleType>
|
|
102
|
+
<xs:restriction base="xs:normalizedString">
|
|
103
|
+
<xs:enumeration value="constant"/>
|
|
104
|
+
<xs:enumeration value="fixed"/>
|
|
105
|
+
<xs:enumeration value="tunable"/>
|
|
106
|
+
<xs:enumeration value="changing"/>
|
|
107
|
+
<xs:enumeration value="countdown"/>
|
|
108
|
+
<xs:enumeration value="triggered"/>
|
|
109
|
+
</xs:restriction>
|
|
110
|
+
</xs:simpleType>
|
|
111
|
+
</xs:attribute>
|
|
112
|
+
<xs:attribute name="intervalDecimal" type="xs:double" use="optional"/>
|
|
113
|
+
<xs:attribute name="shiftDecimal" type="xs:double" default="0"/>
|
|
114
|
+
<xs:attribute name="supportsFraction" type="xs:boolean" default="false"/>
|
|
115
|
+
<xs:attribute name="resolution" type="xs:unsignedLong" use="optional"/>
|
|
116
|
+
<xs:attribute name="intervalCounter" type="xs:unsignedLong" use="optional"/>
|
|
117
|
+
<xs:attribute name="shiftCounter" type="xs:unsignedLong" default="0"/>
|
|
118
|
+
</xs:attributeGroup>
|
|
119
|
+
</xs:schema>
|