fmu-manipulation-toolbox 1.9rc3__py3-none-any.whl → 1.9rc5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. fmu_manipulation_toolbox/__version__.py +1 -1
  2. fmu_manipulation_toolbox/cli/__init__.py +0 -0
  3. fmu_manipulation_toolbox/cli/fmucontainer.py +103 -0
  4. fmu_manipulation_toolbox/cli/fmusplit.py +45 -0
  5. fmu_manipulation_toolbox/cli/fmutool.py +115 -0
  6. fmu_manipulation_toolbox/cli/utils.py +36 -0
  7. fmu_manipulation_toolbox/container.py +34 -30
  8. fmu_manipulation_toolbox/gui.py +2 -0
  9. fmu_manipulation_toolbox/operations.py +4 -63
  10. fmu_manipulation_toolbox/remoting.py +105 -0
  11. fmu_manipulation_toolbox/resources/darwin64/container.dylib +0 -0
  12. fmu_manipulation_toolbox/resources/linux32/client_sm.so +0 -0
  13. fmu_manipulation_toolbox/resources/linux32/server_sm +0 -0
  14. fmu_manipulation_toolbox/resources/linux64/client_sm.so +0 -0
  15. fmu_manipulation_toolbox/resources/linux64/container.so +0 -0
  16. fmu_manipulation_toolbox/resources/linux64/server_sm +0 -0
  17. fmu_manipulation_toolbox/resources/win32/client_sm.dll +0 -0
  18. fmu_manipulation_toolbox/resources/win32/server_sm.exe +0 -0
  19. fmu_manipulation_toolbox/resources/win64/client_sm.dll +0 -0
  20. fmu_manipulation_toolbox/resources/win64/container.dll +0 -0
  21. fmu_manipulation_toolbox/resources/win64/server_sm.exe +0 -0
  22. {fmu_manipulation_toolbox-1.9rc3.dist-info → fmu_manipulation_toolbox-1.9rc5.dist-info}/METADATA +1 -1
  23. {fmu_manipulation_toolbox-1.9rc3.dist-info → fmu_manipulation_toolbox-1.9rc5.dist-info}/RECORD +27 -21
  24. {fmu_manipulation_toolbox-1.9rc3.dist-info → fmu_manipulation_toolbox-1.9rc5.dist-info}/WHEEL +0 -0
  25. {fmu_manipulation_toolbox-1.9rc3.dist-info → fmu_manipulation_toolbox-1.9rc5.dist-info}/entry_points.txt +0 -0
  26. {fmu_manipulation_toolbox-1.9rc3.dist-info → fmu_manipulation_toolbox-1.9rc5.dist-info}/licenses/LICENSE.txt +0 -0
  27. {fmu_manipulation_toolbox-1.9rc3.dist-info → fmu_manipulation_toolbox-1.9rc5.dist-info}/top_level.txt +0 -0
@@ -1 +1 @@
1
- 'V1.9-rc3'
1
+ 'V1.9-rc5'
File without changes
@@ -0,0 +1,103 @@
1
+ import argparse
2
+ import logging
3
+
4
+ from pathlib import Path
5
+
6
+ from .utils import setup_logger, make_wide
7
+ from ..assembly import Assembly, AssemblyError
8
+ from ..container import FMUContainerError
9
+ from ..version import __version__ as version
10
+
11
+
12
+ def fmucontainer():
13
+ logger = setup_logger()
14
+
15
+ logger.info(f"FMUContainer version {version}")
16
+ parser = argparse.ArgumentParser(prog="fmucontainer", description="Generate FMU from FMU's",
17
+ formatter_class=make_wide(argparse.ArgumentDefaultsHelpFormatter),
18
+ add_help=False,
19
+ epilog="see: https://github.com/grouperenault/fmu_manipulation_toolbox/blob/main/"
20
+ "container/README.md")
21
+
22
+ parser.add_argument('-h', '-help', action="help")
23
+
24
+ parser.add_argument("-fmu-directory", action="store", dest="fmu_directory", required=False, default=".",
25
+ help="Directory containing initial FMU’s and used to generate containers. "
26
+ "If not defined, current directory is used.")
27
+
28
+ parser.add_argument("-fmi", action="store", dest="fmi_version", required=False, default="2",
29
+ help="Define version of FMI to be used for container interface."
30
+ "Only '2' or '3' is supported.")
31
+
32
+ parser.add_argument("-container", action="append", dest="container_descriptions_list", default=[],
33
+ metavar="filename.{csv|json|ssp},[:step_size]", required=True,
34
+ help="Description of the container to create.")
35
+
36
+ parser.add_argument("-debug", action="store_true", dest="debug",
37
+ help="Add lot of useful log during the process.")
38
+
39
+ parser.add_argument("-no-auto-input", action="store_false", dest="auto_input", default=True,
40
+ help="Create ONLY explicit input.")
41
+
42
+ parser.add_argument("-no-auto-output", action="store_false", dest="auto_output", default=True,
43
+ help="Create ONLY explicit output.")
44
+
45
+ parser.add_argument("-auto-parameter", action="store_true", dest="auto_parameter", default=False,
46
+ help="Expose parameters of the embedded fmu's.")
47
+
48
+ parser.add_argument("-auto-local", action="store_true", dest="auto_local", default=False,
49
+ help="Expose local variables of the embedded fmu's.")
50
+
51
+ parser.add_argument("-no-auto-link", action="store_false", dest="auto_link", default=True,
52
+ help="Create ONLY explicit links.")
53
+
54
+ parser.add_argument("-mt", action="store_true", dest="mt", default=False,
55
+ help="Enable Multi-Threaded mode for the generated container.")
56
+
57
+ parser.add_argument("-profile", action="store_true", dest="profiling", default=False,
58
+ help="Enable Profiling mode for the generated container.")
59
+
60
+ parser.add_argument("-sequential", action="store_true", dest="sequential", default=False,
61
+ help="Use sequential mode to schedule embedded fmu's.")
62
+
63
+ parser.add_argument("-dump-json", action="store_true", dest="dump", default=False,
64
+ help="Dump a JSON file for each container.")
65
+
66
+ config = parser.parse_args()
67
+
68
+ if config.debug:
69
+ logger.setLevel(logging.DEBUG)
70
+
71
+ fmu_directory = Path(config.fmu_directory)
72
+ logger.info(f"FMU directory: '{fmu_directory}'")
73
+
74
+ for description in config.container_descriptions_list:
75
+ try:
76
+ tokens = description.split(":")
77
+ filename = ":".join(tokens[:-1])
78
+ step_size = float(tokens[-1])
79
+ except ValueError:
80
+ step_size = None
81
+ filename = description
82
+
83
+ try:
84
+ assembly = Assembly(filename, step_size=step_size, auto_link=config.auto_link,
85
+ auto_input=config.auto_input, auto_output=config.auto_output,
86
+ auto_local=config.auto_local, mt=config.mt, sequential=config.sequential,
87
+ profiling=config.profiling, fmu_directory=fmu_directory, debug=config.debug,
88
+ auto_parameter=config.auto_parameter)
89
+ except FileNotFoundError as e:
90
+ logger.fatal(f"Cannot read file: {e}")
91
+ continue
92
+ except (FMUContainerError, AssemblyError) as e:
93
+ logger.fatal(f"{filename}: {e}")
94
+ continue
95
+
96
+ try:
97
+ assembly.make_fmu(dump_json=config.dump, fmi_version=int(config.fmi_version))
98
+ except FMUContainerError as e:
99
+ logger.fatal(f"{filename}: {e}")
100
+ continue
101
+
102
+ if __name__ == "__main__":
103
+ fmucontainer()
@@ -0,0 +1,45 @@
1
+ import argparse
2
+ import logging
3
+
4
+ from .utils import setup_logger, make_wide
5
+ from ..split import FMUSplitter, FMUSplitterError
6
+ from ..version import __version__ as version
7
+
8
+
9
+ def fmusplit():
10
+ logger = setup_logger()
11
+
12
+ logger.info(f"FMUSplit version {version}")
13
+ parser = argparse.ArgumentParser(prog="fmusplit", description="Split FMU Container into FMU's",
14
+ formatter_class=make_wide(argparse.ArgumentDefaultsHelpFormatter),
15
+ add_help=False,
16
+ epilog="see: https://github.com/grouperenault/fmu_manipulation_toolbox/blob/main/"
17
+ "container/README.md")
18
+ parser.add_argument('-h', '-help', action="help")
19
+
20
+ parser.add_argument("-debug", action="store_true", dest="debug",
21
+ help="Add lot of useful log during the process.")
22
+
23
+ parser.add_argument("-fmu", action="append", dest="fmu_filename_list", default=[],
24
+ metavar="filename.fmu", required=True,
25
+ help="Description of the FMU container to split.")
26
+
27
+ config = parser.parse_args()
28
+
29
+ if config.debug:
30
+ logger.setLevel(logging.DEBUG)
31
+
32
+ for fmu_filename in config.fmu_filename_list:
33
+ try:
34
+ splitter = FMUSplitter(fmu_filename)
35
+ splitter.split_fmu()
36
+ except FMUSplitterError as e:
37
+ logger.fatal(f"{fmu_filename}: {e}")
38
+ continue
39
+ except FileNotFoundError as e:
40
+ logger.fatal(f"Cannot read file: {e}")
41
+ continue
42
+
43
+
44
+ if __name__ == "__main__":
45
+ fmusplit()
@@ -0,0 +1,115 @@
1
+ import argparse
2
+ import sys
3
+
4
+ from .utils import setup_logger, make_wide
5
+ from ..operations import (OperationSummary, OperationError, OperationRemoveRegexp,
6
+ OperationRemoveSources, OperationTrimUntil, OperationKeepOnlyRegexp, OperationMergeTopLevel,
7
+ OperationStripTopLevel, OperationRenameFromCSV, OperationSaveNamesToCSV, FMU, FMUError)
8
+ from ..remoting import (OperationAddFrontendWin32, OperationAddFrontendWin64, OperationAddRemotingWin32,
9
+ OperationAddRemotingWin64)
10
+ from ..checker import checker_list
11
+ from ..version import __version__ as version
12
+ from ..help import Help
13
+
14
+
15
+ def fmutool():
16
+ logger = setup_logger()
17
+
18
+ logger.info(f"FMU Manipulation Toolbox version {version}")
19
+ help_message = Help()
20
+
21
+ parser = argparse.ArgumentParser(prog='fmutool',
22
+ description="Analyse and Manipulate a FMU by modifying its 'modelDescription.xml'",
23
+ formatter_class=make_wide(argparse.HelpFormatter),
24
+ add_help=False,
25
+ epilog="see: https://github.com/grouperenault/fmu_manipulation_toolbox/blob/main/README.md")
26
+
27
+ def add_option(option, *args, **kwargs):
28
+ parser.add_argument(option, *args, help=help_message.usage(option), **kwargs)
29
+
30
+ add_option('-h', '-help', action="help")
31
+
32
+ # I/O
33
+ add_option('-input', action='store', dest='fmu_input', default=None, required=True, metavar='path/to/module.fmu')
34
+ add_option('-output', action='store', dest='fmu_output', default=None, metavar='path/to/module-modified.fmu')
35
+
36
+ # Port name manipulation
37
+ add_option('-remove-toplevel', action='append_const', dest='operations_list', const=OperationStripTopLevel())
38
+ add_option('-merge-toplevel', action='append_const', dest='operations_list', const=OperationMergeTopLevel())
39
+ add_option('-trim-until', action='append', dest='operations_list', type=OperationTrimUntil, metavar='prefix')
40
+ add_option('-remove-regexp', action='append', dest='operations_list', type=OperationRemoveRegexp,
41
+ metavar='regular-expression')
42
+ add_option('-keep-only-regexp', action='append', dest='operations_list', type=OperationKeepOnlyRegexp,
43
+ metavar='regular-expression')
44
+ add_option('-remove-all', action='append_const', dest='operations_list', const=OperationRemoveRegexp('.*'))
45
+
46
+ # Batch Rename
47
+ add_option('-dump-csv', action='append', dest='operations_list', type=OperationSaveNamesToCSV,
48
+ metavar='path/to/list.csv')
49
+ add_option('-rename-from-csv', action='append', dest='operations_list', type=OperationRenameFromCSV,
50
+ metavar='path/to/translation.csv')
51
+
52
+ # Remoting
53
+ add_option('-add-remoting-win32', action='append_const', dest='operations_list', const=OperationAddRemotingWin32())
54
+ add_option('-add-remoting-win64', action='append_const', dest='operations_list', const=OperationAddRemotingWin64())
55
+ add_option('-add-frontend-win32', action='append_const', dest='operations_list', const=OperationAddFrontendWin32())
56
+ add_option('-add-frontend-win64', action='append_const', dest='operations_list', const=OperationAddFrontendWin64())
57
+
58
+ # Extraction / Removal
59
+ add_option('-extract-descriptor', action='store', dest='extract_description',
60
+ metavar='path/to/saved-modelDescriptor.xml')
61
+ add_option('-remove-sources', action='append_const', dest='operations_list',
62
+ const=OperationRemoveSources())
63
+ # Filter
64
+ add_option('-only-parameters', action='append_const', dest='apply_on', const='parameter')
65
+ add_option('-only-inputs', action='append_const', dest='apply_on', const='input')
66
+ add_option('-only-outputs', action='append_const', dest='apply_on', const='output')
67
+ # Checker
68
+ add_option('-summary', action='append_const', dest='operations_list', const=OperationSummary())
69
+ add_option('-check', action='append_const', dest='operations_list', const=[checker() for checker in checker_list])
70
+
71
+ cli_options = parser.parse_args()
72
+ # handle the "no operation" use case
73
+ if not cli_options.operations_list:
74
+ cli_options.operations_list = []
75
+
76
+ if cli_options.fmu_input == cli_options.fmu_output:
77
+ logger.fatal(f"'-input' and '-output' should point to different files.")
78
+ sys.exit(-3)
79
+
80
+ logger.info(f"READING Input='{cli_options.fmu_input}'")
81
+ try:
82
+ fmu = FMU(cli_options.fmu_input)
83
+ except FMUError as reason:
84
+ logger.fatal(f"{reason}")
85
+ sys.exit(-4)
86
+
87
+ if cli_options.apply_on:
88
+ logger.info("Applying operation for :")
89
+ for causality in cli_options.apply_on:
90
+ logger.info(f" - causality = {causality}")
91
+
92
+ for operation in cli_options.operations_list:
93
+ logger.info(f" => {operation}")
94
+ try:
95
+ fmu.apply_operation(operation, cli_options.apply_on)
96
+ except OperationError as reason:
97
+ logger.fatal(f"{reason}")
98
+ sys.exit(-6)
99
+
100
+ if cli_options.extract_description:
101
+ logger.info(f"WRITING ModelDescriptor='{cli_options.extract_description}'")
102
+ fmu.save_descriptor(cli_options.extract_description)
103
+
104
+ if cli_options.fmu_output:
105
+ logger.info(f"WRITING Output='{cli_options.fmu_output}'")
106
+ try:
107
+ fmu.repack(cli_options.fmu_output)
108
+ except FMUError as reason:
109
+ logger.fatal(f"FATAL ERROR: {reason}")
110
+ sys.exit(-5)
111
+ else:
112
+ logger.info(f"INFO Modified FMU is not saved. If necessary use '-output' option.")
113
+
114
+ if __name__ == "__main__":
115
+ fmutool()
@@ -0,0 +1,36 @@
1
+ import logging
2
+ import sys
3
+ from colorama import Fore, Style, init
4
+
5
+ def setup_logger():
6
+ class CustomFormatter(logging.Formatter):
7
+ def format(self, record):
8
+ log_format = "%(levelname)-8s | %(message)s"
9
+ format_per_level = {
10
+ logging.DEBUG: str(Fore.BLUE) + log_format,
11
+ logging.INFO: str(Fore.CYAN) + log_format,
12
+ logging.WARNING: str(Fore.YELLOW) + log_format,
13
+ logging.ERROR: str(Fore.RED) + log_format,
14
+ logging.CRITICAL: str(Fore.RED + Style.BRIGHT) + log_format,
15
+ }
16
+ formatter = logging.Formatter(format_per_level[record.levelno])
17
+ return formatter.format(record)
18
+ init()
19
+ logger = logging.getLogger("fmu_manipulation_toolbox")
20
+ handler = logging.StreamHandler(stream=sys.stdout)
21
+ handler.setFormatter(CustomFormatter())
22
+ logger.addHandler(handler)
23
+ logger.setLevel(logging.INFO)
24
+
25
+ return logger
26
+
27
+ def make_wide(formatter, w=120, h=36):
28
+ """Return a wider HelpFormatter, if possible."""
29
+ try:
30
+ # https://stackoverflow.com/a/5464440
31
+ # beware: "Only the name of this class is considered a public API."
32
+ kwargs = {'width': w, 'max_help_position': h}
33
+ formatter(None, **kwargs)
34
+ return lambda prog: formatter(prog, **kwargs)
35
+ except TypeError:
36
+ return formatter
@@ -1,5 +1,6 @@
1
1
  import logging
2
2
  import getpass
3
+ import math
3
4
  import os
4
5
  import shutil
5
6
  import uuid
@@ -9,7 +10,7 @@ from datetime import datetime
9
10
  from pathlib import Path
10
11
  from typing import *
11
12
 
12
- from .operations import FMU, OperationAbstract, FMUError
13
+ from .operations import FMU, OperationAbstract, FMUError, FMUPort
13
14
  from .version import __version__ as tool_version
14
15
 
15
16
 
@@ -70,9 +71,7 @@ class EmbeddedFMUPort:
70
71
  "string"
71
72
  )
72
73
 
73
-
74
-
75
- def __init__(self, fmi_type, attrs: Dict[str, str], fmi_version=0):
74
+ def __init__(self, fmi_type, attrs: Union[FMUPort, Dict[str, str]], fmi_version=0):
76
75
  self.causality = attrs.get("causality", "local")
77
76
  self.variability = attrs.get("variability", "continuous")
78
77
  self.name = attrs["name"]
@@ -87,8 +86,6 @@ class EmbeddedFMUPort:
87
86
  self.start_value = attrs.get("start", None)
88
87
  self.initial = attrs.get("initial", None)
89
88
 
90
-
91
-
92
89
  def xml(self, vr: int, name=None, causality=None, start=None, fmi_version=2) -> str:
93
90
  if name is None:
94
91
  name = self.name
@@ -162,7 +159,8 @@ class EmbeddedFMUPort:
162
159
 
163
160
  class EmbeddedFMU(OperationAbstract):
164
161
  capability_list = ("needsExecutionTool",
165
- "canBeInstantiatedOnlyOncePerProcess")
162
+ "canBeInstantiatedOnlyOncePerProcess",
163
+ "canHandleVariableCommunicationStepSize")
166
164
 
167
165
  def __init__(self, filename):
168
166
  self.fmu = FMU(filename)
@@ -189,7 +187,7 @@ class EmbeddedFMU(OperationAbstract):
189
187
  if fmi_version == "2.0":
190
188
  self.guid = attrs['guid']
191
189
  self.fmi_version = 2
192
- if fmi_version == "3.0":
190
+ if fmi_version == "3.0": # TODO: handle 3.x cases
193
191
  self.guid = attrs['instantiationToken']
194
192
  self.fmi_version = 3
195
193
 
@@ -206,12 +204,18 @@ class EmbeddedFMU(OperationAbstract):
206
204
  self.start_time = float(attrs.get("startTime", 0.0))
207
205
  self.stop_time = float(attrs.get("stopTime", self.start_time + 1.0))
208
206
 
209
- def port_attrs(self, fmu_port):
207
+ def port_attrs(self, fmu_port: FMUPort):
208
+ # Container will manage Enumeration as Integer
209
+ if fmu_port.fmi_type == "Enumeration":
210
+ if self.fmi_version == 2:
211
+ fmu_port.fmi_type = "Integer"
212
+ else:
213
+ fmu_port.fmi_type = "Int32"
210
214
  port = EmbeddedFMUPort(fmu_port.fmi_type, fmu_port, fmi_version=self.fmi_version)
211
215
  self.ports[port.name] = port
212
216
 
213
217
  def __repr__(self):
214
- return f"FMU '{self.name}' ({len(self.ports)} variables)"
218
+ return f"FMU '{self.name}' ({len(self.ports)} variables, ts={self.step_size}s)"
215
219
 
216
220
 
217
221
  class FMUContainerError(Exception):
@@ -491,8 +495,8 @@ class FMUContainer:
491
495
 
492
496
  try:
493
497
  fmu = EmbeddedFMU(self.fmu_directory / fmu_filename)
494
- if fmu.fmi_version > self.fmi_version:
495
- logger.warning(f"Try to embed FMU-{fmu.fmi_version} into container FMI-{self.fmi_version}")
498
+ if not fmu.fmi_version == self.fmi_version:
499
+ logger.warning(f"Try to embed FMU-{fmu.fmi_version} into container FMI-{self.fmi_version}.")
496
500
  self.involved_fmu[fmu.name] = fmu
497
501
 
498
502
  logger.debug(f"Adding FMU #{len(self.involved_fmu)}: {fmu}")
@@ -642,16 +646,16 @@ class FMUContainer:
642
646
 
643
647
  return auto_wired
644
648
 
645
- def minimum_step_size(self) -> float:
646
- step_size = None
649
+ def default_step_size(self) -> float:
650
+ freq_set = set()
647
651
  for fmu in self.involved_fmu.values():
648
- if step_size:
649
- if fmu.step_size and fmu.step_size < step_size:
650
- step_size = fmu.step_size
651
- else:
652
- step_size = fmu.step_size
652
+ if fmu.step_size and fmu.capabilities["canHandleVariableCommunicationStepSize"] == "false":
653
+ freq_set.add(int(1.0/fmu.step_size))
653
654
 
654
- if not step_size:
655
+ common_freq = math.gcd(*freq_set)
656
+ try:
657
+ step_size = 1.0 / float(common_freq)
658
+ except ZeroDivisionError:
655
659
  step_size = 0.1
656
660
  logger.warning(f"Defaulting to step_size={step_size}")
657
661
 
@@ -659,15 +663,15 @@ class FMUContainer:
659
663
 
660
664
  def sanity_check(self, step_size: Optional[float]):
661
665
  for fmu in self.involved_fmu.values():
662
- if not fmu.step_size:
663
- continue
664
- ts_ratio = step_size / fmu.step_size
665
- if ts_ratio < 1.0:
666
- logger.warning(f"Container step_size={step_size}s is lower than FMU '{fmu.name}' "
667
- f"step_size={fmu.step_size}s.")
668
- if ts_ratio != int(ts_ratio):
669
- logger.warning(f"Container step_size={step_size}s should divisible by FMU '{fmu.name}' "
670
- f"step_size={fmu.step_size}s.")
666
+ if fmu.step_size and fmu.capabilities["canHandleVariableCommunicationStepSize"] == "false":
667
+ ts_ratio = step_size / fmu.step_size
668
+ logger.debug(f"container step_size: {step_size} = {fmu.step_size} x {ts_ratio} for {fmu.name}")
669
+ if ts_ratio < 1.0:
670
+ logger.warning(f"Container step_size={step_size}s is lower than FMU '{fmu.name}' "
671
+ f"step_size={fmu.step_size}s.")
672
+ if ts_ratio != int(ts_ratio):
673
+ logger.warning(f"Container step_size={step_size}s should divisible by FMU '{fmu.name}' "
674
+ f"step_size={fmu.step_size}s.")
671
675
  for port_name in fmu.ports:
672
676
  cport = ContainerPort(fmu, port_name)
673
677
  if cport not in self.rules:
@@ -683,7 +687,7 @@ class FMUContainer:
683
687
 
684
688
  if step_size is None:
685
689
  logger.info(f"step_size will be deduced from the embedded FMU's")
686
- step_size = self.minimum_step_size()
690
+ step_size = self.default_step_size()
687
691
  self.sanity_check(step_size)
688
692
 
689
693
  logger.info(f"Building FMU '{fmu_filename}', step_size={step_size}")
@@ -13,6 +13,8 @@ from functools import partial
13
13
 
14
14
  from .gui_style import gui_style, log_color
15
15
  from .operations import *
16
+ from .remoting import (OperationAddRemotingWin32, OperationAddRemotingWin64, OperationAddFrontendWin32,
17
+ OperationAddFrontendWin64)
16
18
  from .assembly import Assembly, AssemblyNode
17
19
  from .checker import checker_list
18
20
  from .help import Help
@@ -8,7 +8,6 @@ import tempfile
8
8
  import xml.parsers.expat
9
9
  import zipfile
10
10
  import hashlib
11
- from pathlib import Path
12
11
  from typing import *
13
12
 
14
13
  logger = logging.getLogger("fmu_manipulation_toolbox")
@@ -161,8 +160,9 @@ class Manipulation:
161
160
  self.current_port = FMUPort()
162
161
  self.current_port.push_attrs(attrs)
163
162
  elif self.fmu.fmi_version == 2 and name in self.fmu.FMI2_TYPES:
164
- self.current_port.fmi_type = name
165
- self.current_port.push_attrs(attrs)
163
+ if self.current_port: # <Enumeration> can be found before port defition. Ignored.
164
+ self.current_port.fmi_type = name
165
+ self.current_port.push_attrs(attrs)
166
166
  elif self.fmu.fmi_version == 3 and name in self.fmu.FMI3_TYPES:
167
167
  self.current_port = FMUPort()
168
168
  self.current_port.fmi_type = name
@@ -279,7 +279,7 @@ class OperationAbstract:
279
279
  def experiment_attrs(self, attrs):
280
280
  pass
281
281
 
282
- def port_attrs(self, fmu_port) -> int:
282
+ def port_attrs(self, fmu_port: FMUPort) -> int:
283
283
  """ return 0 to keep port, otherwise remove it"""
284
284
  return 0
285
285
 
@@ -366,65 +366,6 @@ class OperationRenameFromCSV(OperationAbstract):
366
366
  return 1
367
367
 
368
368
 
369
- class OperationAddRemotingWinAbstract(OperationAbstract):
370
- bitness_from = None
371
- bitness_to = None
372
-
373
- def __repr__(self):
374
- return f"Add '{self.bitness_to}' remoting on '{self.bitness_from}' FMU"
375
-
376
- def fmi_attrs(self, attrs):
377
- if not attrs["fmiVersion"] == "2.0":
378
- raise OperationError(f"Adding remoting is only available for FMI-2.0")
379
-
380
- def cosimulation_attrs(self, attrs):
381
- fmu_bin = {
382
- "win32": os.path.join(self.fmu.tmp_directory, "binaries", f"win32"),
383
- "win64": os.path.join(self.fmu.tmp_directory, "binaries", f"win64"),
384
- }
385
-
386
- if not os.path.isdir(fmu_bin[self.bitness_from]):
387
- raise OperationError(f"{self.bitness_from} interface does not exist")
388
-
389
- if os.path.isdir(fmu_bin[self.bitness_to]):
390
- logger.info(f"{self.bitness_to} already exists. Add front-end.")
391
- shutil.move(os.path.join(fmu_bin[self.bitness_to], attrs['modelIdentifier'] + ".dll"),
392
- os.path.join(fmu_bin[self.bitness_to], attrs['modelIdentifier'] + "-remoted.dll"))
393
- else:
394
- os.mkdir(fmu_bin[self.bitness_to])
395
-
396
- to_path = Path(__file__).parent / "resources" / self.bitness_to
397
- shutil.copyfile(to_path / "client_sm.dll",
398
- Path(fmu_bin[self.bitness_to]) / Path(attrs['modelIdentifier']).with_suffix(".dll"))
399
-
400
- from_path = Path(__file__).parent / "resources" / self.bitness_from
401
- shutil.copyfile(from_path / "server_sm.exe",
402
- Path(fmu_bin[self.bitness_from]) / "server_sm.exe")
403
-
404
- shutil.copyfile(Path(__file__).parent / "resources" / "license.txt",
405
- Path(fmu_bin[self.bitness_to]) / "license.txt")
406
-
407
-
408
- class OperationAddRemotingWin64(OperationAddRemotingWinAbstract):
409
- bitness_from = "win32"
410
- bitness_to = "win64"
411
-
412
-
413
- class OperationAddFrontendWin32(OperationAddRemotingWinAbstract):
414
- bitness_from = "win32"
415
- bitness_to = "win32"
416
-
417
-
418
- class OperationAddFrontendWin64(OperationAddRemotingWinAbstract):
419
- bitness_from = "win64"
420
- bitness_to = "win64"
421
-
422
-
423
- class OperationAddRemotingWin32(OperationAddRemotingWinAbstract):
424
- bitness_from = "win64"
425
- bitness_to = "win32"
426
-
427
-
428
369
  class OperationRemoveRegexp(OperationAbstract):
429
370
  def __repr__(self):
430
371
  return f"Remove ports matching '{self.regex_string}'"
@@ -0,0 +1,105 @@
1
+ import logging
2
+ import shutil
3
+
4
+ from pathlib import Path
5
+ from .operations import OperationAbstract, OperationError
6
+
7
+ logger = logging.getLogger("fmu_manipulation_toolbox")
8
+
9
+ class OperationAddRemotingWinAbstract(OperationAbstract):
10
+ bitness_from = None
11
+ bitness_to = None
12
+
13
+ def __repr__(self):
14
+ return f"Add '{self.bitness_to}' remoting on '{self.bitness_from}' FMU"
15
+
16
+ def __init__(self):
17
+ self.vr = {
18
+ "Real": [],
19
+ "Integer": [],
20
+ "Boolean": []
21
+ }
22
+ self.nb_input = 0;
23
+ self.nb_output = 0;
24
+
25
+ def fmi_attrs(self, attrs):
26
+ if not attrs["fmiVersion"] == "2.0":
27
+ raise OperationError(f"Adding remoting is only available for FMI-2.0")
28
+
29
+ def cosimulation_attrs(self, attrs):
30
+ fmu_bin = {
31
+ "win32": Path(self.fmu.tmp_directory) / "binaries" / "win32",
32
+ "win64": Path(self.fmu.tmp_directory) / "binaries" / "win64",
33
+ }
34
+
35
+ if not fmu_bin[self.bitness_from].is_dir():
36
+ raise OperationError(f"{self.bitness_from} interface does not exist")
37
+
38
+ if fmu_bin[self.bitness_to].is_dir():
39
+ logger.info(f"{self.bitness_to} already exists. Add front-end.")
40
+ shutil.move(fmu_bin[self.bitness_to] / Path(attrs['modelIdentifier']).with_suffix(".dll"),
41
+ fmu_bin[self.bitness_to] / Path(attrs['modelIdentifier']).with_suffix("-remoted.dll"))
42
+ else:
43
+ fmu_bin[self.bitness_to].mkdir()
44
+
45
+ to_path = Path(__file__).parent / "resources" / self.bitness_to
46
+ try:
47
+ shutil.copyfile(to_path / "client_sm.dll",
48
+ fmu_bin[self.bitness_to] / Path(attrs['modelIdentifier']).with_suffix(".dll"))
49
+ except FileNotFoundError as e:
50
+ logger.critical(f"Cannot add remoting client: {e}")
51
+
52
+ from_path = Path(__file__).parent / "resources" / self.bitness_from
53
+ try:
54
+ shutil.copyfile(from_path / "server_sm.exe",
55
+ fmu_bin[self.bitness_from] / "server_sm.exe")
56
+ except FileNotFoundError as e:
57
+ logger.critical(f"Cannot add remoting server: {e}")
58
+
59
+ shutil.copyfile(Path(__file__).parent / "resources" / "license.txt",
60
+ fmu_bin[self.bitness_to] / "license.txt")
61
+
62
+ def port_attrs(self, fmu_port) -> int:
63
+ try:
64
+ self.vr[fmu_port.fmi_type].append(fmu_port["valueReference"])
65
+ if fmu_port["causality"] in ("input", "parameter"):
66
+ self.nb_input += 1
67
+ else:
68
+ self.nb_output += 1
69
+ except KeyError:
70
+ logger.error(f"Type '{fmu_port.fmi_type}' is not supported by remoting.")
71
+
72
+ return 0
73
+
74
+ def closure(self):
75
+ target_dir = Path(self.fmu.tmp_directory) / "resources"
76
+ if not target_dir.is_dir():
77
+ target_dir.mkdir()
78
+
79
+ logger.info(f"Remoting nb input port: {self.nb_input}")
80
+ logger.info(f"Remoting nb output port: {self.nb_output}")
81
+ with open(target_dir/ "remoting_table.txt", "wt") as file:
82
+ for fmi_type in ('Real', 'Integer', 'Boolean'):
83
+ print(len(self.vr[fmi_type]), file=file)
84
+ for fmi_type in ('Real', 'Integer', 'Boolean'):
85
+ for vr in sorted(self.vr[fmi_type]):
86
+ print(vr, file=file)
87
+
88
+ class OperationAddRemotingWin64(OperationAddRemotingWinAbstract):
89
+ bitness_from = "win32"
90
+ bitness_to = "win64"
91
+
92
+
93
+ class OperationAddFrontendWin32(OperationAddRemotingWinAbstract):
94
+ bitness_from = "win32"
95
+ bitness_to = "win32"
96
+
97
+
98
+ class OperationAddFrontendWin64(OperationAddRemotingWinAbstract):
99
+ bitness_from = "win64"
100
+ bitness_to = "win64"
101
+
102
+
103
+ class OperationAddRemotingWin32(OperationAddRemotingWinAbstract):
104
+ bitness_from = "win64"
105
+ bitness_to = "win32"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fmu_manipulation_toolbox
3
- Version: 1.9rc3
3
+ Version: 1.9rc5
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
@@ -1,15 +1,21 @@
1
1
  fmu_manipulation_toolbox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  fmu_manipulation_toolbox/__main__.py,sha256=FpG0ITBz5q-AvIbXplVh_1g1zla5souFGtpiDdECxEw,352
3
- fmu_manipulation_toolbox/__version__.py,sha256=CGyZIselV5kCL6An0m7aR4m-Y2X2IRQadcj88KEF3Ps,11
3
+ fmu_manipulation_toolbox/__version__.py,sha256=niVpMeIUg7iKHRlsUPuXHpvJ5XeFDKAdI2L5ilFhMbg,11
4
4
  fmu_manipulation_toolbox/assembly.py,sha256=XQ_1sB6K1Dk2mnNe-E3_6Opoeub7F9Qaln0EUDzsop8,26553
5
5
  fmu_manipulation_toolbox/checker.py,sha256=jw1omfrMMIMHlIpHXpWBcQgIiS9hnHe5T9CZ5KlbVGs,2422
6
- fmu_manipulation_toolbox/container.py,sha256=8Wf16sgUPkY-ByWeKt-3TD_4vNRQuLwH9Gs7D2Q6tAk,44959
7
- fmu_manipulation_toolbox/gui.py,sha256=iOJ3F_zfw3mU34VofZrYdaffljTmYfuy33fJXlLaOwg,29045
6
+ fmu_manipulation_toolbox/container.py,sha256=Anubg08tr0HRb1_6rUqIRoE3E6emv6pKqDbs2aezv38,45625
7
+ fmu_manipulation_toolbox/gui.py,sha256=ax-IbGO7GyBG0Mb5okN588CKQDfMxoF1uZtD1_CYnjc,29199
8
8
  fmu_manipulation_toolbox/gui_style.py,sha256=s6WdrnNd_lCMWhuBf5LKK8wrfLXCU7pFTLUfvqkJVno,6633
9
9
  fmu_manipulation_toolbox/help.py,sha256=aklKiLrsE0adSzQ5uoEB1sBDmI6s4l231gavu4XxxzA,5856
10
- fmu_manipulation_toolbox/operations.py,sha256=b7N5AVHLIpQO8od4BYasb9CppHJ-ZmW8mu0ZdhndoHI,19472
10
+ fmu_manipulation_toolbox/operations.py,sha256=WayxcpnVRpvxGOXx2I5Vh9ThVbj6IRW6Vr8qKfqck8Y,17348
11
+ fmu_manipulation_toolbox/remoting.py,sha256=vsvGRIUr-VxUkpBMCfE_G0kYVnB2CN03ts_Imi2uLk8,3814
11
12
  fmu_manipulation_toolbox/split.py,sha256=NVkfdTRR0jj_VOdgtxHQoKptkAg5TFVUA7nUx3_o9Pg,13336
12
13
  fmu_manipulation_toolbox/version.py,sha256=OhBLkZ1-nhC77kyvffPNAf6m8OZe1bYTnNf_PWs1NvM,392
14
+ fmu_manipulation_toolbox/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ fmu_manipulation_toolbox/cli/fmucontainer.py,sha256=bxiOcVwHHLQaVtTga77t_UdE6duPX1kTXef53LyPqbA,4738
16
+ fmu_manipulation_toolbox/cli/fmusplit.py,sha256=QSMHZJlNOYbaPgI6Z9QHr95mrC3PuXDeUXR2sHm73HU,1636
17
+ fmu_manipulation_toolbox/cli/fmutool.py,sha256=OuPrDeqnbsMGV50Jq7ugX7q19gt9WI2v1HMXvOvzozM,5637
18
+ fmu_manipulation_toolbox/cli/utils.py,sha256=gNhdlFYSSNSb0fovzS0crnxgmqqKXe0KtoZZFhRKhfg,1375
13
19
  fmu_manipulation_toolbox/resources/checkbox-checked-disabled.png,sha256=FWIuyrXlaNLLePHfXj7j9ca5rT8Hgr14KCe1EqTCZyk,2288
14
20
  fmu_manipulation_toolbox/resources/checkbox-checked-hover.png,sha256=KNlV-d_aJNTTvUVXKGT9DBY30sIs2LwocLJrFKNKv8k,2419
15
21
  fmu_manipulation_toolbox/resources/checkbox-checked.png,sha256=gzyFqvRFsZixVh6ZlV4SMWUKzglY1rSn7SvJUKMVvtk,2411
@@ -27,7 +33,7 @@ fmu_manipulation_toolbox/resources/icon_fmu.png,sha256=EuygB2xcoM2WAfKKdyKG_UvTL
27
33
  fmu_manipulation_toolbox/resources/license.txt,sha256=5ODuU8g8pIkK-NMWXu_rjZ6k7gM7b-N2rmg87-2Kmqw,1583
28
34
  fmu_manipulation_toolbox/resources/mask.png,sha256=px1U4hQGL0AmZ4BQPknOVREpMpTSejbah3ntkpqAzFA,3008
29
35
  fmu_manipulation_toolbox/resources/model.png,sha256=EAf_HnZJe8zYGZygerG1MMt2U-tMMZlifzXPj4_iORA,208788
30
- fmu_manipulation_toolbox/resources/darwin64/container.dylib,sha256=qYV-5d35a7OmSHjYejuTRG8TurfctN5rkF-YjQua-Zo,161560
36
+ fmu_manipulation_toolbox/resources/darwin64/container.dylib,sha256=hc8FpHbqZDkpnLRy8oKfhk7iSTW7G89B4sACASW4Ta8,161560
31
37
  fmu_manipulation_toolbox/resources/fmi-2.0/fmi2Annotation.xsd,sha256=OGfyJtaJntKypX5KDpuZ-nV1oYLZ6HV16pkpKOmYox4,2731
32
38
  fmu_manipulation_toolbox/resources/fmi-2.0/fmi2AttributeGroups.xsd,sha256=HwyV7LBse-PQSv4z1xjmtzPU3Hjnv4mluq9YdSBNHMQ,3704
33
39
  fmu_manipulation_toolbox/resources/fmi-2.0/fmi2ModelDescription.xsd,sha256=JM4j_9q-pc40XYHb28jfT3iV3aYM5JLqD5aRjO72K1E,18939
@@ -47,19 +53,19 @@ fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Type.xsd,sha256=TaHRoUBIFtmdEwBKB
47
53
  fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Unit.xsd,sha256=CK_F2t5LfyQ6eSNJ8soTFMVK9DU8vD2WiMi2MQvjB0g,3746
48
54
  fmu_manipulation_toolbox/resources/fmi-3.0/fmi3Variable.xsd,sha256=3YU-3q1-c-namz7sMe5cxnmOVOJsRSmfWR02PKv3xaU,19171
49
55
  fmu_manipulation_toolbox/resources/fmi-3.0/fmi3VariableDependency.xsd,sha256=YQSBwXt4IsDlyegY8bX-qQHGSfE5TipTPfo2g2yqq1c,3082
50
- fmu_manipulation_toolbox/resources/linux32/client_sm.so,sha256=xVdY2zy13pa2DcvFiweSNpp7E6DiONqeoBdlcJHrW_k,35940
51
- fmu_manipulation_toolbox/resources/linux32/server_sm,sha256=1TLGqNPyM5UVOrCfzNqWyF6ClLksY3EiY3CSsrnp6c0,22836
52
- fmu_manipulation_toolbox/resources/linux64/client_sm.so,sha256=EhY1XHo1YcQn6yqZ7wk5okqtZyp0MrcCsGcudqE-aIM,37000
53
- fmu_manipulation_toolbox/resources/linux64/container.so,sha256=KT6_GdTc0saR-H6l2-0udaJtEDiHnzlFBIp0FtlOtrw,135520
54
- fmu_manipulation_toolbox/resources/linux64/server_sm,sha256=ulfoPvmaYe9nInYcVEyj7mD9zDzGk56OUoWx1mPKLiE,22768
55
- fmu_manipulation_toolbox/resources/win32/client_sm.dll,sha256=q91IE2IFDzchUukNc93c7MkRHgKYA3ll3CnKthPfKB0,17920
56
- fmu_manipulation_toolbox/resources/win32/server_sm.exe,sha256=cTmbVSx_wyD-VcJMXgQWvfmByzrb9lJnTlp9Dzdu9sA,15872
57
- fmu_manipulation_toolbox/resources/win64/client_sm.dll,sha256=RYaQA4l0iOis-QbnCz_T1zRnuDTlWFtt-FzWnEnenag,22016
58
- fmu_manipulation_toolbox/resources/win64/container.dll,sha256=vBslbM-PWm9Dj4zTwhElqm9EPHFwv4BV9obBEb0sx9I,98816
59
- fmu_manipulation_toolbox/resources/win64/server_sm.exe,sha256=oKiRKA1irVkkL-P84bOU1TC7K9h_xrnr_4EGJqoYIfU,19968
60
- fmu_manipulation_toolbox-1.9rc3.dist-info/licenses/LICENSE.txt,sha256=c_862mzyk6ownO3Gt6cVs0-53IXLi_-ZEQFNDVabESw,1285
61
- fmu_manipulation_toolbox-1.9rc3.dist-info/METADATA,sha256=4E3iWPeD60EJzvvBjPFnWqMI6cIEMn3wxsaLjmZwkNw,1156
62
- fmu_manipulation_toolbox-1.9rc3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
63
- fmu_manipulation_toolbox-1.9rc3.dist-info/entry_points.txt,sha256=HjOZkflbI1IuSY8BpOZre20m24M4GDQGCJfPIa7NrlY,264
64
- fmu_manipulation_toolbox-1.9rc3.dist-info/top_level.txt,sha256=9D_h-5BMjSqf9z-XFkbJL_bMppR2XNYW3WNuPkXou0k,25
65
- fmu_manipulation_toolbox-1.9rc3.dist-info/RECORD,,
56
+ fmu_manipulation_toolbox/resources/linux32/client_sm.so,sha256=ytv2fMHRYkQS4v_ODKVCt3Z_19k7tCYTKT8kKOK0Pu0,34756
57
+ fmu_manipulation_toolbox/resources/linux32/server_sm,sha256=pHXd5rRyJrCEUPGxVcK3irE86ThxVUTBRn_rgOZdSYg,21224
58
+ fmu_manipulation_toolbox/resources/linux64/client_sm.so,sha256=xBgQTTiww_SON8bHP4UP6UT8PqzzHiBgJHTiiG3Asi8,32592
59
+ fmu_manipulation_toolbox/resources/linux64/container.so,sha256=cCue2KyQjBi75dJnlySPVmAGb8H0WzpHqhxYkB7Aay4,135520
60
+ fmu_manipulation_toolbox/resources/linux64/server_sm,sha256=A6-IQUCN51r5rQkEW9lJJuZKqRPgeoxyMwjc5NNMq-A,22552
61
+ fmu_manipulation_toolbox/resources/win32/client_sm.dll,sha256=1HXgBXj0FwLmT7xPdlWCYsTRu-TnggJTTNtkrDS7v0o,17408
62
+ fmu_manipulation_toolbox/resources/win32/server_sm.exe,sha256=h4CkEB4a47vF_Dsnwbvy9YwIra8mn_taWYTkBdlDrNc,15360
63
+ fmu_manipulation_toolbox/resources/win64/client_sm.dll,sha256=diUwWUB_pKjbU2NT8q4JUaby6ppAQnxbTj6ZCAxjTK8,20992
64
+ fmu_manipulation_toolbox/resources/win64/container.dll,sha256=-EnDn6FIpLxX3L0vp1tGAOp78fQAQfaIWl4tC0P1rj8,98816
65
+ fmu_manipulation_toolbox/resources/win64/server_sm.exe,sha256=5woZaxLhHP5xr7tOSCz6JmaHK9Wb0xuB0pzdROUDDpU,18432
66
+ fmu_manipulation_toolbox-1.9rc5.dist-info/licenses/LICENSE.txt,sha256=c_862mzyk6ownO3Gt6cVs0-53IXLi_-ZEQFNDVabESw,1285
67
+ fmu_manipulation_toolbox-1.9rc5.dist-info/METADATA,sha256=8O6lxLDyaW5Fu3qxa4PNsyawnvBtEtDuozgyHxvJ-4w,1156
68
+ fmu_manipulation_toolbox-1.9rc5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
69
+ fmu_manipulation_toolbox-1.9rc5.dist-info/entry_points.txt,sha256=HjOZkflbI1IuSY8BpOZre20m24M4GDQGCJfPIa7NrlY,264
70
+ fmu_manipulation_toolbox-1.9rc5.dist-info/top_level.txt,sha256=9D_h-5BMjSqf9z-XFkbJL_bMppR2XNYW3WNuPkXou0k,25
71
+ fmu_manipulation_toolbox-1.9rc5.dist-info/RECORD,,