pythonfmu3 0.2.4__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pythonfmu3/__init__.py CHANGED
@@ -1,7 +1,9 @@
1
1
  from ._version import __version__
2
2
  from .builder import FmuBuilder
3
+ from .cosimulation import CoSimulation
4
+ from .modelexchange import ModelExchange
3
5
  from .enums import Fmi3Causality, Fmi3Initial, Fmi3Status, Fmi3Variability
4
- from .fmi3slave import Fmi3Slave, Fmi3StepResult
6
+ from .fmi3slave import Fmi3Slave, Fmi3SlaveBase, Fmi3StepResult
5
7
  from .variables import Boolean, Enumeration, Int32, Int64, UInt64, Float64, String, Dimension
6
8
  from .default_experiment import DefaultExperiment
7
9
  from .variable_types import Float64Type, EnumerationType
pythonfmu3/_version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.2.4"
1
+ __version__ = "0.3.0"
pythonfmu3/builder.py CHANGED
@@ -13,7 +13,7 @@ from typing import Iterable, Optional, Tuple, Union
13
13
  from xml.dom.minidom import parseString
14
14
  from xml.etree.ElementTree import Element, SubElement, tostring
15
15
  from .osutil import get_lib_extension, get_platform
16
- from .fmi3slave import FMI3_MODEL_OPTIONS, Fmi3Slave
16
+ from .fmi3slave import FMI3_MODEL_OPTIONS, Fmi3Slave, Fmi3SlaveBase
17
17
 
18
18
  FilePath = Union[str, Path]
19
19
  HERE = Path(__file__).parent
@@ -24,7 +24,7 @@ logger = logging.getLogger(__name__)
24
24
  def get_class_name(file_name: Path) -> str:
25
25
  with open(str(file_name), 'r') as file:
26
26
  data = file.read()
27
- return re.search(r'class (\w+)\(\s*Fmi3Slave\s*\)\s*:', data).group(1)
27
+ return re.search(r'class (\w+)\(([^)]*\bFmi3Slave(?:Base)?\b[^)]*)\)\s*:', data).group(1)
28
28
 
29
29
 
30
30
  def get_model_description(filepath: Path, module_name: str) -> Tuple[str, Element]:
@@ -50,9 +50,9 @@ def get_model_description(filepath: Path, module_name: str) -> Tuple[str, Elemen
50
50
  finally:
51
51
  sys.path.remove(str(filepath.parent)) # remove inserted temporary path
52
52
 
53
- if not isinstance(instance, Fmi3Slave):
53
+ if not isinstance(instance, Fmi3SlaveBase):
54
54
  raise TypeError(
55
- f"The provided class '{class_name}' does not inherit from {Fmi3Slave.__qualname__}"
55
+ f"The provided class '{class_name}' does not inherit from {Fmi3SlaveBase.__qualname__}"
56
56
  )
57
57
  # Produce the xml
58
58
  return instance.modelName, instance.to_xml()
@@ -138,9 +138,16 @@ class FmuBuilder:
138
138
 
139
139
  type_node = xml.find("CoSimulation")
140
140
  option_names = [opt.name for opt in FMI3_MODEL_OPTIONS]
141
- for option, value in options.items():
142
- if option in option_names:
143
- type_node.set(option, str(value).lower())
141
+ if type_node:
142
+ for option, value in options.items():
143
+ if option in option_names:
144
+ type_node.set(option, str(value).lower())
145
+
146
+ type_node = xml.find("ModelExchange")
147
+ if type_node:
148
+ for option, value in options.items():
149
+ if option in option_names:
150
+ type_node.set(option, str(value).lower())
144
151
 
145
152
  with zipfile.ZipFile(dest_file, "w") as zip_fmu:
146
153
 
@@ -0,0 +1,8 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ # co-simulation mixin
4
+ class CoSimulation(ABC):
5
+
6
+ @abstractmethod
7
+ def do_step(self, current_time: float, step_size: float):
8
+ pass
pythonfmu3/fmi3slave.py CHANGED
@@ -11,6 +11,8 @@ from xml.etree.ElementTree import Element, SubElement
11
11
 
12
12
  from .logmsg import LogMsg
13
13
  from .default_experiment import DefaultExperiment
14
+ from .cosimulation import CoSimulation
15
+ from .modelexchange import ModelExchange
14
16
  from ._version import __version__ as VERSION
15
17
  from .enums import Fmi3Type, Fmi3Status, Fmi3Causality, Fmi3Initial, Fmi3Variability
16
18
  from .variables import Boolean, Enumeration, Int32, Int64, UInt64, Float64, ModelVariable, String
@@ -33,7 +35,8 @@ class Fmi3StepResult(NamedTuple):
33
35
  terminateSimulation: bool = False
34
36
  earlyReturn: bool = False
35
37
 
36
- class Fmi3Slave(ABC):
38
+
39
+ class Fmi3SlaveBase(object):
37
40
  """Abstract facade class to execute Python through FMI standard."""
38
41
 
39
42
  # Dictionary of (category, description) entries
@@ -104,8 +107,18 @@ class Fmi3Slave(ABC):
104
107
  options[option.name] = str(value).lower()
105
108
  options["modelIdentifier"] = self.modelName
106
109
  options["canNotUseMemoryManagementFunctions"] = "true"
107
-
108
- SubElement(root, "CoSimulation", attrib=options)
110
+
111
+ options_me = dict()
112
+ options_me["canGetAndSetFMUState"] = "true"
113
+ options_me["modelIdentifier"] = self.modelName
114
+ options_me["needsCompletedIntegratorStep"] = "false"
115
+
116
+ # check if we have cosim mixin or model exchange mixin
117
+ if isinstance(self, ModelExchange):
118
+ SubElement(root, "ModelExchange", attrib=options_me)
119
+
120
+ if isinstance(self, CoSimulation):
121
+ SubElement(root, "CoSimulation", attrib=options)
109
122
 
110
123
  if self.units:
111
124
  unit_defs = SubElement(root, "UnitDefinitions")
@@ -239,7 +252,6 @@ class Fmi3Slave(ABC):
239
252
  def exit_initialization_mode(self):
240
253
  pass
241
254
 
242
- @abstractmethod
243
255
  def do_step(self, current_time: float, step_size: float) -> Fmi3StepResult:
244
256
  pass
245
257
 
@@ -404,6 +416,50 @@ class Fmi3Slave(ABC):
404
416
  if v.setter is not None:
405
417
  v.setter(value)
406
418
 
419
+ def set_continuous_states(self, values: List[float]):
420
+ offset = 0
421
+ continuous_state_derivatives = list(
422
+ filter(lambda v: v.variability == Fmi3Variability.continuous and (isinstance(v, Float64) and v.derivative is not None), self.vars.values())
423
+ )
424
+
425
+ vrs = [v.derivative for v in continuous_state_derivatives]
426
+
427
+ for vr in vrs:
428
+ var = self.vars[vr]
429
+ size = var.size(self.vars)
430
+ if size > 1:
431
+ var.setter(values[offset:offset+size])
432
+ else:
433
+ var.setter(values[offset])
434
+ offset += size
435
+
436
+ def get_continuous_states(self) -> List[float]:
437
+ offset = 0
438
+ continuous_state_derivatives = list(
439
+ filter(lambda v: v.variability == Fmi3Variability.continuous and (isinstance(v, Float64) and v.derivative is not None), self.vars.values())
440
+ )
441
+
442
+ vrs = [v.derivative for v in continuous_state_derivatives]
443
+
444
+ refs = list()
445
+ for vr in vrs:
446
+ var = self.vars[vr]
447
+ if len(var.dimensions) == 0:
448
+ refs.append(float(var.getter()))
449
+ else:
450
+ refs.extend(var.getter())
451
+
452
+ return refs
453
+
454
+ def get_number_of_continuous_states(self) -> int:
455
+ continuous_state_derivatives = list(
456
+ filter(lambda v: v.variability == Fmi3Variability.continuous and (isinstance(v, Float64) and v.derivative is not None), self.vars.values())
457
+ )
458
+ return len(continuous_state_derivatives)
459
+
460
+ def set_time(self, time: float):
461
+ self.time = time
462
+
407
463
  @staticmethod
408
464
  def _fmu_state_to_bytes(state: Dict[str, Any]) -> bytes:
409
465
  return json.dumps(state).encode("utf-8")
@@ -436,3 +492,6 @@ class Fmi3Slave(ABC):
436
492
  category = "logAll"
437
493
  log_msg = LogMsg(status, category, msg, debug)
438
494
  self.log_queue.append(log_msg)
495
+
496
+ class Fmi3Slave(Fmi3SlaveBase, CoSimulation):
497
+ pass
@@ -0,0 +1,23 @@
1
+ from abc import ABC, ABCMeta, abstractmethod
2
+
3
+ class RequireTimeMeta(ABCMeta):
4
+ def __init__(cls, name, bases, namespace):
5
+ super().__init__(name, bases, namespace)
6
+ orig_init = cls.__init__
7
+ def new_init(self, *args, **kwargs):
8
+ orig_init(self, *args, **kwargs)
9
+ if not hasattr(self, 'time'):
10
+ raise AttributeError(f"{cls.__name__} must define 'self.time' in __init__")
11
+ cls.__init__ = new_init
12
+
13
+
14
+ # model exchange mixin
15
+ class ModelExchange(ABC, metaclass=RequireTimeMeta):
16
+ """
17
+ Classes derived from ModelExchange must define a 'self.time' member variable.
18
+ """
19
+
20
+ @abstractmethod
21
+ def get_continuous_state_derivatives(self):
22
+ """Return the continuous state derivatives of the model."""
23
+ pass
@@ -133,6 +133,23 @@ public:
133
133
  FMIBoolean* earlyReturn,
134
134
  FMIFloat64& endOfStep) = 0;
135
135
 
136
+ // Model Exchange methods
137
+ virtual void GetContinuousStates(cppfmu::FMIFloat64* continuousStates, std::size_t nStates) const = 0;
138
+ virtual void GetContinuousStateDerivatives(cppfmu::FMIFloat64* derivatives, std::size_t nStates) const = 0;
139
+ virtual void GetNominalsOfContinuousStates(cppfmu::FMIFloat64* nominalContinuousStates, std::size_t nStates) const = 0;
140
+ virtual void SetContinuousStates(const cppfmu::FMIFloat64* continuousStates, std::size_t nStates) = 0;
141
+ virtual void SetTime(cppfmu::FMIFloat64 time) = 0;
142
+ virtual void GetNumberOfContinuousStates(std::size_t& nStates) const = 0;
143
+ virtual void GetNumberOfEventIndicators(std::size_t& nEventIndicators) const = 0;
144
+ virtual void UpdateDiscreteStates(
145
+ cppfmu::FMIBoolean* discreteStatesNeedUpdate,
146
+ cppfmu::FMIBoolean* terminateSimulation,
147
+ cppfmu::FMIBoolean* nominalContinuousStatesChanged,
148
+ cppfmu::FMIBoolean* valuesOfContinuousStatesChanged,
149
+ cppfmu::FMIBoolean* nextEventTimeDefined,
150
+ cppfmu::FMIFloat64* nextEventTime) = 0;
151
+
152
+
136
153
  virtual void GetFMUstate(fmi3FMUState& state) = 0;
137
154
  virtual void SetFMUstate(const fmi3FMUState& state) = 0;
138
155
  virtual void FreeFMUstate(fmi3FMUState& state) = 0;
@@ -110,10 +110,16 @@ fmi3Instance fmi3InstantiateCoSimulation(
110
110
  component->logger);
111
111
  return component;
112
112
  } catch (const cppfmu::FatalError& e) {
113
- // functions->logger(nullptr, instanceName, fmi3Fatal, "", e.what());
113
+ if (logMessage)
114
+ {
115
+ logMessage(environment, fmi3Fatal, "", e.what());
116
+ }
114
117
  return nullptr;
115
118
  } catch (const std::exception& e) {
116
- // functions->logger(nullptr, instanceName, fmi3Error, "", e.what());
119
+ if (logMessage)
120
+ {
121
+ logMessage(environment, fmi3Error, "", e.what());
122
+ }
117
123
  return nullptr;
118
124
  }
119
125
  }
@@ -124,10 +130,38 @@ fmi3Instance fmi3InstantiateModelExchange(
124
130
  fmi3String resourcePath,
125
131
  fmi3Boolean visible,
126
132
  fmi3Boolean loggingOn,
127
- fmi3InstanceEnvironment instanceEnvironment,
133
+ fmi3InstanceEnvironment environment,
128
134
  fmi3LogMessageCallback logMessage)
129
135
  {
130
- throw std::logic_error("Unsupported FMU instance type requested (only co-simulation is supported)");
136
+ try {
137
+ auto component = new Component(
138
+ environment,
139
+ logMessage,
140
+ loggingOn);
141
+ component->slave = CppfmuInstantiateSlave(
142
+ instanceName,
143
+ instantiationToken,
144
+ resourcePath,
145
+ "application/x-fmu-sharedlibrary",
146
+ 0.0,
147
+ visible,
148
+ cppfmu::FMIFalse,
149
+ component->logger);
150
+ return component;
151
+ } catch (const cppfmu::FatalError& e) {
152
+ if (logMessage)
153
+ {
154
+ logMessage(environment, fmi3Fatal, "", e.what());
155
+ }
156
+ return nullptr;
157
+ } catch (const std::exception& e) {
158
+ if (logMessage)
159
+ {
160
+ logMessage(environment, fmi3Error, "", e.what());
161
+ }
162
+ return nullptr;
163
+ }
164
+
131
165
  }
132
166
 
133
167
  fmi3Instance fmi3InstantiateScheduledExecution(
@@ -512,6 +546,183 @@ fmi3Status fmi3SetString(
512
546
  }
513
547
  }
514
548
 
549
+ fmi3Status fmi3GetContinuousStates(
550
+ fmi3Instance c,
551
+ fmi3Float64 continuousStates[],
552
+ size_t nStates)
553
+ {
554
+ auto component = reinterpret_cast<Component*>(c);
555
+ try {
556
+ component->slave->GetContinuousStates(continuousStates, nStates);
557
+ return fmi3OK;
558
+ } catch (const cppfmu::FatalError& e) {
559
+ component->logger.Log(fmi3Fatal, "", e.what());
560
+ return fmi3Fatal;
561
+ } catch (const std::exception& e) {
562
+ component->logger.Log(fmi3Error, "", e.what());
563
+ return fmi3Error;
564
+ }
565
+ }
566
+
567
+ fmi3Status fmi3GetContinuousStateDerivatives(
568
+ fmi3Instance c,
569
+ fmi3Float64 derivatives[],
570
+ size_t nStates)
571
+ {
572
+ auto component = reinterpret_cast<Component*>(c);
573
+ try {
574
+ component->slave->GetContinuousStateDerivatives(derivatives, nStates);
575
+ return fmi3OK;
576
+ } catch (const cppfmu::FatalError& e) {
577
+ component->logger.Log(fmi3Fatal, "", e.what());
578
+ return fmi3Fatal;
579
+ } catch (const std::exception& e) {
580
+ component->logger.Log(fmi3Error, "", e.what());
581
+ return fmi3Error;
582
+ }
583
+ }
584
+
585
+ fmi3Status fmi3SetTime(
586
+ fmi3Instance c,
587
+ fmi3Float64 time)
588
+ {
589
+ auto component = reinterpret_cast<Component*>(c);
590
+ try {
591
+ component->slave->SetTime(time);
592
+ return fmi3OK;
593
+ } catch (const cppfmu::FatalError& e) {
594
+ component->logger.Log(fmi3Fatal, "", e.what());
595
+ return fmi3Fatal;
596
+ } catch (const std::exception& e) {
597
+ component->logger.Log(fmi3Error, "", e.what());
598
+ return fmi3Error;
599
+ }
600
+ }
601
+
602
+ fmi3Status fmi3SetContinuousStates(
603
+ fmi3Instance c,
604
+ const fmi3Float64 continuousStates[],
605
+ size_t nStates)
606
+ {
607
+ auto component = reinterpret_cast<Component*>(c);
608
+ try {
609
+ component->slave->SetContinuousStates(continuousStates, nStates);
610
+ return fmi3OK;
611
+ } catch (const cppfmu::FatalError& e) {
612
+ component->logger.Log(fmi3Fatal, "", e.what());
613
+ return fmi3Fatal;
614
+ } catch (const std::exception& e) {
615
+ component->logger.Log(fmi3Error, "", e.what());
616
+ return fmi3Error;
617
+ }
618
+ }
619
+
620
+ fmi3Status fmi3GetEventIndicators(
621
+ fmi3Instance c,
622
+ fmi3Float64 eventIndicators[],
623
+ size_t nEventIndicators)
624
+ {
625
+ return fmi3OK;
626
+ }
627
+
628
+ fmi3Status fmi3GetNominalsOfContinuousStates(
629
+ fmi3Instance c,
630
+ fmi3Float64 nominalContinuousStates[],
631
+ size_t nStates)
632
+ {
633
+ const auto component = reinterpret_cast<Component*>(c);
634
+ try {
635
+ component->slave->GetNominalsOfContinuousStates(nominalContinuousStates, nStates);
636
+ return fmi3OK;
637
+ } catch (const cppfmu::FatalError& e) {
638
+ component->logger.Log(fmi3Fatal, "", e.what());
639
+ return fmi3Fatal;
640
+ } catch (const std::exception& e) {
641
+ component->logger.Log(fmi3Error, "", e.what());
642
+ return fmi3Error;
643
+ }
644
+ }
645
+
646
+ fmi3Status fmi3GetNumberOfContinuousStates(
647
+ fmi3Instance c,
648
+ std::size_t * nContinuousStates)
649
+ {
650
+ const auto component = reinterpret_cast<Component*>(c);
651
+ try {
652
+ component->slave->GetNumberOfContinuousStates(*nContinuousStates);
653
+ return fmi3OK;
654
+ } catch (const cppfmu::FatalError& e) {
655
+ component->logger.Log(fmi3Fatal, "", e.what());
656
+ return fmi3Fatal;
657
+ } catch (const std::exception& e) {
658
+ component->logger.Log(fmi3Error, "", e.what());
659
+ return fmi3Error;
660
+ }
661
+ }
662
+
663
+ fmi3Status fmi3GetNumberOfEventIndicators(
664
+ fmi3Instance c,
665
+ std::size_t * nEventIndicators)
666
+ {
667
+ const auto component = reinterpret_cast<Component*>(c);
668
+ try {
669
+ component->slave->GetNumberOfEventIndicators(*nEventIndicators);
670
+ return fmi3OK;
671
+ } catch (const cppfmu::FatalError& e) {
672
+ component->logger.Log(fmi3Fatal, "", e.what());
673
+ return fmi3Fatal;
674
+ } catch (const std::exception& e) {
675
+ component->logger.Log(fmi3Error, "", e.what());
676
+ return fmi3Error;
677
+ }
678
+ }
679
+
680
+
681
+ fmi3Status fmi3UpdateDiscreteStates(fmi3Instance c,
682
+ fmi3Boolean* discreteStatesNeedUpdate,
683
+ fmi3Boolean* terminateSimulation,
684
+ fmi3Boolean* nominalContinuousStatesChanged,
685
+ fmi3Boolean* valuesOfContinuousStatesChanged,
686
+ fmi3Boolean* nextEventTimeDefined,
687
+ fmi3Float64* nextEventTime)
688
+ {
689
+ const auto component = reinterpret_cast<Component*>(c);
690
+ try {
691
+ component->slave->UpdateDiscreteStates(
692
+ discreteStatesNeedUpdate,
693
+ terminateSimulation,
694
+ nominalContinuousStatesChanged,
695
+ valuesOfContinuousStatesChanged,
696
+ nextEventTimeDefined,
697
+ nextEventTime);
698
+ return fmi3OK;
699
+ } catch (const cppfmu::FatalError& e) {
700
+ component->logger.Log(fmi3Fatal, "", e.what());
701
+ return fmi3Fatal;
702
+ } catch (const std::exception& e) {
703
+ component->logger.Log(fmi3Error, "", e.what());
704
+ return fmi3Error;
705
+ }
706
+ }
707
+
708
+ fmi3Status fmi3EnterContinuousTimeMode(fmi3Instance c)
709
+ {
710
+ return fmi3OK;
711
+ }
712
+
713
+ fmi3Status fmi3CompletedIntegratorStep(
714
+ fmi3Instance c,
715
+ fmi3Boolean noSetFMUStatePriorToCurrentPoint,
716
+ fmi3Boolean* enterEventMode,
717
+ fmi3Boolean* terminateSimulation)
718
+ {
719
+ *enterEventMode = false;
720
+ *terminateSimulation = false;
721
+
722
+ return fmi3OK;
723
+ }
724
+
725
+
515
726
 
516
727
  fmi3Status fmi3GetFMUState(
517
728
  fmi3Instance c,
@@ -850,15 +1061,6 @@ fmi3EvaluateDiscreteStates(fmi3Instance instance)
850
1061
  NOT_IMPLEMENTED;
851
1062
  }
852
1063
 
853
- fmi3Status
854
- fmi3UpdateDiscreteStates(fmi3Instance instance, fmi3Boolean* discreteStatesNeedUpdate,
855
- fmi3Boolean* terminateSimulation,
856
- fmi3Boolean* nominalsOfContinuousStatesChanged,
857
- fmi3Boolean* valuesOfContinuousStatesChanged,
858
- fmi3Boolean* nextEventTimeDefined, fmi3Float64* nextEventTime)
859
- {
860
- NOT_IMPLEMENTED;
861
- }
862
1064
 
863
1065
  fmi3Status fmi3ActivateModelPartition(fmi3Instance instance, fmi3ValueReference clockReference,
864
1066
  fmi3Float64 activationTime)
@@ -866,72 +1068,3 @@ fmi3Status fmi3ActivateModelPartition(fmi3Instance instance, fmi3ValueReference
866
1068
  NOT_IMPLEMENTED;
867
1069
  }
868
1070
 
869
-
870
- // model exchange functions
871
- fmi3Status
872
- fmi3EnterContinuousTimeMode(fmi3Instance instance)
873
- {
874
- NOT_IMPLEMENTED;
875
- }
876
-
877
- fmi3Status
878
- fmi3CompletedIntegratorStep(fmi3Instance instance, fmi3Boolean noSetFMUStatePriorToCurrentPoint,
879
- fmi3Boolean* enterEventMode, fmi3Boolean* terminateSimulation)
880
- {
881
- NOT_IMPLEMENTED;
882
- }
883
-
884
- /* Providing independent variables and re-initialization of caching */
885
- fmi3Status
886
- fmi3SetTime(fmi3Instance instance, fmi3Float64 time)
887
- {
888
- NOT_IMPLEMENTED;
889
- }
890
-
891
- fmi3Status
892
- fmi3SetContinuousStates(fmi3Instance instance, const fmi3Float64 continuousStates[],
893
- size_t nContinuousStates)
894
- {
895
- NOT_IMPLEMENTED;
896
- }
897
-
898
- /* Evaluation of the model equations */
899
- fmi3Status
900
- fmi3GetContinuousStateDerivatives(fmi3Instance instance, fmi3Float64 derivatives[],
901
- size_t nContinuousStates)
902
- {
903
- NOT_IMPLEMENTED;
904
- }
905
-
906
- fmi3Status
907
- fmi3GetEventIndicators(fmi3Instance instance, fmi3Float64 eventIndicators[],
908
- size_t nEventIndicators)
909
- {
910
- NOT_IMPLEMENTED;
911
- }
912
-
913
- fmi3Status
914
- fmi3GetContinuousStates(fmi3Instance instance, fmi3Float64 continuousStates[],
915
- size_t nContinuousStates)
916
- {
917
- NOT_IMPLEMENTED;
918
- }
919
-
920
- fmi3Status
921
- fmi3GetNominalsOfContinuousStates(fmi3Instance instance, fmi3Float64 nominals[],
922
- size_t nContinuousStates)
923
- {
924
- NOT_IMPLEMENTED;
925
- }
926
-
927
- fmi3Status
928
- fmi3GetNumberOfEventIndicators(fmi3Instance instance, size_t* nEventIndicators)
929
- {
930
- NOT_IMPLEMENTED;
931
- }
932
-
933
- fmi3Status
934
- fmi3GetNumberOfContinuousStates(fmi3Instance instance, size_t* nContinuousStates)
935
- {
936
- NOT_IMPLEMENTED;
937
- }
@@ -28,7 +28,7 @@ inline std::string findClassName(const std::string& fileName)
28
28
  {
29
29
  std::string line;
30
30
  std::ifstream infile(fileName);
31
- std::string regexStr(R"(^class (\w+)\(\s*Fmi3Slave\s*\)\s*:)");
31
+ std::string regexStr(R"(^class (\w+)\(([^)]*\bFmi3Slave(?:Base)?\b[^)]*)\)\s*:)");
32
32
  while (getline(infile, line)) {
33
33
  std::smatch m;
34
34
  std::regex re(regexStr);
@@ -80,7 +80,7 @@ PySlaveInstance::PySlaveInstance(std::string instanceName, std::string resources
80
80
  std::string className = findClassName(resources_ + "/" + moduleName + ".py");
81
81
  if (className.empty()) {
82
82
  cleanPyObject();
83
- throw cppfmu::FatalError("Unable to find class extending Fmi3Slave!");
83
+ throw cppfmu::FatalError("Unable to find class extending Fmi3SlaveBase!");
84
84
  }
85
85
 
86
86
  PyObject* pyClassName = Py_BuildValue("s", className.c_str());
@@ -530,6 +530,109 @@ void PySlaveInstance::GetString(const cppfmu::FMIValueReference* vr, std::size_t
530
530
  });
531
531
  }
532
532
 
533
+ void PySlaveInstance::GetContinuousStates(cppfmu::FMIFloat64* continuousStates, std::size_t nStates) const
534
+ {
535
+ py_safe_run([this, &continuousStates, nStates](PyGILState_STATE gilState) {
536
+ auto f = PyObject_CallMethod(pInstance_, "get_continuous_states", nullptr);
537
+ if (f == nullptr) {
538
+ handle_py_exception("[get_continuous_states] PyObject_CallMethod", gilState);
539
+ }
540
+ // Assuming f is a list of floats
541
+ for (std::size_t i = 0; i < nStates; i++) {
542
+ PyObject* item = PyList_GetItem(f, i);
543
+ continuousStates[i] = static_cast<cppfmu::FMIFloat64>(PyFloat_AsDouble(item));
544
+ }
545
+ clearLogBuffer();
546
+ });
547
+ }
548
+
549
+ void PySlaveInstance::GetContinuousStateDerivatives(cppfmu::FMIFloat64* continuousStateDerivatives, std::size_t nStates) const
550
+ {
551
+ py_safe_run([this, &continuousStateDerivatives, nStates](PyGILState_STATE gilState) {
552
+ auto f = PyObject_CallMethod(pInstance_, "get_continuous_state_derivatives", nullptr);
553
+ if (f == nullptr) {
554
+ handle_py_exception("[get_continuous_state_derivatives] PyObject_CallMethod", gilState);
555
+ }
556
+ // Assuming f is a list of floats
557
+ for (std::size_t i = 0; i < nStates; i++) {
558
+ PyObject* item = PyList_GetItem(f, i);
559
+ continuousStateDerivatives[i] = static_cast<cppfmu::FMIFloat64>(PyFloat_AsDouble(item));
560
+ }
561
+ clearLogBuffer();
562
+ });
563
+ }
564
+
565
+ void PySlaveInstance::GetNominalsOfContinuousStates(cppfmu::FMIFloat64* nominalsOfContinuousStates, std::size_t nStates) const
566
+ {
567
+ for (size_t i = 0u; i < nStates; i++) {
568
+ nominalsOfContinuousStates[i] = 1.0;
569
+ }
570
+ }
571
+
572
+ void PySlaveInstance::SetContinuousStates(const cppfmu::FMIFloat64* continuousStates, std::size_t nStates)
573
+ {
574
+ py_safe_run([this, &continuousStates, nStates](PyGILState_STATE gilState) {
575
+ PyObject* refs = PyList_New(nStates);
576
+ for (int i = 0; i < nStates; i++) {
577
+ PyList_SetItem(refs, i, Py_BuildValue("d", continuousStates[i]));
578
+ }
579
+
580
+ auto f = PyObject_CallMethod(pInstance_, "set_continuous_states", "(O)", refs);
581
+ Py_DECREF(refs);
582
+ if (f == nullptr) {
583
+ handle_py_exception("[setContinuousStates] PyObject_CallMethod", gilState);
584
+ }
585
+ Py_DECREF(f);
586
+ clearLogBuffer();
587
+ });
588
+ }
589
+
590
+ void PySlaveInstance::GetNumberOfContinuousStates(std::size_t& nStates) const
591
+ {
592
+ py_safe_run([this, &nStates](PyGILState_STATE gilState) {
593
+ auto f = PyObject_CallMethod(pInstance_, "get_number_of_continuous_states", nullptr);
594
+ if (f == nullptr) {
595
+ handle_py_exception("[getNumberOfContinuousStates] PyObject_CallMethod", gilState);
596
+ }
597
+ nStates = static_cast<std::size_t>(PyLong_AsLong(f));
598
+ Py_DECREF(f);
599
+ clearLogBuffer();
600
+ });
601
+ }
602
+
603
+ void PySlaveInstance::GetNumberOfEventIndicators(std::size_t& nIndicators) const
604
+ {
605
+ nIndicators= 0u;
606
+ }
607
+
608
+ void PySlaveInstance::SetTime(cppfmu::FMIFloat64 time)
609
+ {
610
+ py_safe_run([this, time](PyGILState_STATE gilState) {
611
+ auto f = PyObject_CallMethod(pInstance_, "set_time", "(d)", time);
612
+ if (f == nullptr) {
613
+ handle_py_exception("[setTime] PyObject_CallMethod", gilState);
614
+ }
615
+ Py_DECREF(f);
616
+ clearLogBuffer();
617
+ });
618
+ }
619
+
620
+ void PySlaveInstance::UpdateDiscreteStates(
621
+ cppfmu::FMIBoolean* discreteStatesNeedUpdate,
622
+ cppfmu::FMIBoolean* terminateSimulation,
623
+ cppfmu::FMIBoolean* nominalContinuousStatesChanged,
624
+ cppfmu::FMIBoolean* valuesOfContinuousStatesChanged,
625
+ cppfmu::FMIBoolean* nextEventTimeDefined,
626
+ cppfmu::FMIFloat64* nextEventTime)
627
+ {
628
+ *discreteStatesNeedUpdate = false;
629
+ *terminateSimulation = false;
630
+ *nominalContinuousStatesChanged = false;
631
+ *valuesOfContinuousStatesChanged = false;
632
+ *nextEventTimeDefined = false;
633
+ *nextEventTime = 0.0;
634
+ }
635
+
533
636
  void PySlaveInstance::GetFMUstate(fmi3FMUState& state)
534
637
  {
535
638
  py_safe_run([this, &state](PyGILState_STATE gilState) {
@@ -50,6 +50,23 @@ public:
50
50
  void GetFMUstate(fmi3FMUState& State) override;
51
51
  void SetFMUstate(const fmi3FMUState& State) override;
52
52
  void FreeFMUstate(fmi3FMUState& State) override;
53
+
54
+ // Model Exchange methods
55
+ void GetContinuousStates(cppfmu::FMIFloat64* continuousStates, std::size_t nStates) const override;
56
+ void GetNumberOfContinuousStates(std::size_t& nStates) const override;
57
+ void GetNumberOfEventIndicators(std::size_t& nEventIndicators) const override;
58
+ void GetContinuousStateDerivatives(cppfmu::FMIFloat64* derivatives, std::size_t nStates) const override;
59
+ void GetNominalsOfContinuousStates(cppfmu::FMIFloat64* nominalContinuousStates, std::size_t nStates) const override;
60
+ void SetContinuousStates(const cppfmu::FMIFloat64* continuousStates, std::size_t nStates) override;
61
+ void SetTime(cppfmu::FMIFloat64 time) override;
62
+ void UpdateDiscreteStates(
63
+ cppfmu::FMIBoolean* discreteStatesNeedUpdate,
64
+ cppfmu::FMIBoolean* terminateSimulation,
65
+ cppfmu::FMIBoolean* nominalContinuousStatesChanged,
66
+ cppfmu::FMIBoolean* valuesOfContinuousStatesChanged,
67
+ cppfmu::FMIBoolean* nextEventTimeDefined,
68
+ cppfmu::FMIFloat64* nextEventTime) override;
69
+
53
70
 
54
71
  size_t SerializedFMUstateSize(const fmi3FMUState& State) override;
55
72
  void SerializeFMUstate(const fmi3FMUState& State, fmi3Byte bytes[], size_t size) override;
@@ -0,0 +1,27 @@
1
+ from pythonfmu3 import Fmi3Causality, ModelExchange, Fmi3Variability, Fmi3SlaveBase, Fmi3Status, Float64, Fmi3Initial, Unit, Float64Type, Fmi3StepResult
2
+
3
+ from typing import List
4
+
5
+ class Dahlquist(Fmi3SlaveBase, ModelExchange):
6
+
7
+ def __init__(self, **kwargs):
8
+ super().__init__(**kwargs)
9
+
10
+ self.author = "Stephen Smith"
11
+ self.description = "Dahlquist's test problem for model exchange FMUs"
12
+
13
+ self.time = 0.0
14
+ self.k = 1.0
15
+ self.x = 1.0
16
+ self.derx = 0.0
17
+
18
+ self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous))
19
+ self.register_variable(Float64("x", causality=Fmi3Causality.output, start=1, variability=Fmi3Variability.continuous, initial=Fmi3Initial.exact))
20
+ self.register_variable(Float64("derx", causality=Fmi3Causality.local, variability=Fmi3Variability.continuous, derivative=1))
21
+ self.register_variable(Float64("k", causality=Fmi3Causality.parameter, variability=Fmi3Variability.fixed))
22
+
23
+
24
+ def get_continuous_state_derivatives(self) -> List[float]:
25
+ self.derx = -self.k * self.x
26
+ return [self.derx]
27
+
@@ -0,0 +1,32 @@
1
+ from pythonfmu3 import Fmi3Causality, CoSimulation, ModelExchange, Fmi3Variability, Fmi3SlaveBase, Fmi3Status, Float64, Fmi3Initial, Unit, Float64Type, Fmi3StepResult
2
+
3
+ from typing import List
4
+
5
+ class Dahlquist(Fmi3SlaveBase, ModelExchange, CoSimulation):
6
+
7
+ def __init__(self, **kwargs):
8
+ super().__init__(**kwargs)
9
+
10
+ self.author = "Stephen Smith"
11
+ self.description = "Dahlquist's test problem for model exchange FMUs"
12
+
13
+ self.time = 0.0
14
+ self.k = 1.0
15
+ self.x = 1.0
16
+ self.derx = 0.0
17
+
18
+ self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous))
19
+ self.register_variable(Float64("x", causality=Fmi3Causality.output, start=1, variability=Fmi3Variability.continuous, initial=Fmi3Initial.exact))
20
+ self.register_variable(Float64("derx", causality=Fmi3Causality.local, variability=Fmi3Variability.continuous, derivative=1))
21
+ self.register_variable(Float64("k", causality=Fmi3Causality.parameter, variability=Fmi3Variability.fixed))
22
+
23
+
24
+ def get_continuous_state_derivatives(self) -> List[float]:
25
+ self.derx = -self.k * self.x
26
+ return [self.derx]
27
+
28
+ def do_step(self, current_time: float, step_size: float) -> Fmi3StepResult:
29
+ self.time = current_time + step_size
30
+ self.derx = -self.k * self.x
31
+ self.x += self.derx * step_size
32
+ return True
@@ -1,6 +1,6 @@
1
1
  import pytest
2
2
 
3
- from pythonfmu3 import Fmi3Slave
3
+ from pythonfmu3 import Fmi3Slave, ModelExchange
4
4
  from pythonfmu3 import __version__ as VERSION
5
5
 
6
6
  from .utils import FMI2PY, PY2FMI
@@ -150,3 +150,18 @@ def test_Fmi3Slave_customized_log_categories(new_categories):
150
150
  assert categories.find(f"Category[@name='{category}'][@description='{description}']") is not None
151
151
  else:
152
152
  assert categories is None
153
+
154
+
155
+ def test_Fmi3Slave_model_exchange():
156
+ class Slave(Fmi3Slave, ModelExchange):
157
+
158
+ def get_continuous_state_derivatives(self, vals):
159
+ return []
160
+
161
+ slave = Slave(instance_name="instance")
162
+ xml = slave.to_xml()
163
+
164
+ categories = xml.find("ModelExchange")
165
+
166
+ assert categories is not None, "ModelExchange category should be present in the XML"
167
+
@@ -1,5 +1,6 @@
1
1
  import math
2
2
  from pathlib import Path
3
+ import ctypes
3
4
 
4
5
  import pytest
5
6
 
@@ -30,6 +31,66 @@ def test_integration_demo(tmp_path):
30
31
  assert res["realOut"][-1] == pytest.approx(res["time"][-1], rel=1e-7)
31
32
 
32
33
 
34
+ @pytest.mark.integration
35
+ def test_integration_demo_MX(tmp_path):
36
+ script_file = Path(__file__).parent / "slaves/pythonslaveMX.py"
37
+ fmu = FmuBuilder.build_FMU(script_file, dest=tmp_path, needsExecutionTool="false")
38
+ assert fmu.exists()
39
+ res = fmpy.simulate_fmu(str(fmu), stop_time=0.5)
40
+
41
+
42
+ @pytest.mark.integration
43
+ def test_integration_solve_MX(tmp_path):
44
+ script_file = Path(__file__).parent / "slaves/pythonslaveMX.py"
45
+ fmu = FmuBuilder.build_FMU(script_file, dest=tmp_path, needsExecutionTool="false")
46
+ assert fmu.exists()
47
+
48
+ md = fmpy.read_model_description(str(fmu))
49
+ unzipdir = fmpy.extract(str(fmu))
50
+ model = fmpy.fmi3.FMU3Model(guid=md.guid,
51
+ unzipDirectory=unzipdir,
52
+ modelIdentifier=md.modelExchange.modelIdentifier,
53
+ instanceName="instance"
54
+ )
55
+ model.instantiate()
56
+ model.enterInitializationMode()
57
+ model.exitInitializationMode()
58
+
59
+ # forward euler
60
+ t = 0.0
61
+ step_size = 0.1
62
+
63
+ values = (ctypes.c_double * 1)(0.0)
64
+ states = (ctypes.c_double *1)(0.0)
65
+
66
+ model.getContinuousStateDerivatives(values, 1)
67
+ model.getContinuousStates(states, 1)
68
+
69
+ assert values[0] == pytest.approx(-1.0, rel=1e-7)
70
+
71
+ der = values[0]
72
+ new_state = states[0] + der * step_size
73
+
74
+ model.setContinuousStates((ctypes.c_double * 1)(new_state), 1)
75
+ model.setTime(t + step_size)
76
+
77
+ model.getContinuousStates(states, 1)
78
+
79
+ assert states[0] == pytest.approx(new_state, rel=1e-7)
80
+
81
+ @pytest.mark.integration
82
+ def test_integration_demo_CS_MX(tmp_path):
83
+ script_file = Path(__file__).parent / "slaves/pythonslaveMXCS.py"
84
+ fmu = FmuBuilder.build_FMU(script_file, dest=tmp_path, needsExecutionTool="false")
85
+ assert fmu.exists()
86
+ res = fmpy.simulate_fmu(str(fmu), stop_time=0.5, fmi_type="ModelExchange")
87
+
88
+ res1 = fmpy.simulate_fmu(str(fmu), stop_time=0.5, fmi_type="CoSimulation")
89
+
90
+ assert res[-1][0] == pytest.approx(res1[-1][0], rel=1e-7)
91
+ assert res[-1][1] == pytest.approx(res1[-1][1], rel=0.1)
92
+
93
+
33
94
  @pytest.mark.integration
34
95
  def test_integration_reset(tmp_path):
35
96
  script_file = Path(__file__).parent / "slaves/pythonslave.py"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pythonfmu3
3
- Version: 0.2.4
3
+ Version: 0.3.0
4
4
  Summary: A lightweight framework that enables the packaging of Python3.x code as co-simulation FMUs.
5
5
  Home-page: https://github.com/stephensmith25/PythonFMU3
6
6
  Author: Stephen Smith
@@ -27,7 +27,7 @@ Dynamic: license-file
27
27
 
28
28
  # PythonFMU3
29
29
 
30
- > A lightweight framework that enables the packaging of Python 3 code as co-simulation FMUs (following FMI version 3.0).
30
+ > A lightweight framework that enables the packaging of Python 3 code as FMUs (following FMI version 3.0).
31
31
 
32
32
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
33
33
  [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/StephenSmith25/PythonFMU3/issues)
@@ -42,14 +42,16 @@ This project is a fork of the original PythonFMU repository available at https:/
42
42
  ### Support:
43
43
 
44
44
  Please take a look at the examples to see the supported features.
45
+ We currently support both the Model exchange and Cosimulation Interfaces.
45
46
 
46
- ### Future
47
+ For both interfaces event mode is not supported.
47
48
 
48
- In no particular order, we plan to add support for:
49
+ We currently do not support the following methods (beyond a default, trivial implementation)
49
50
 
50
- - Support more variable types from FMI3
51
- - Improve array support
52
- - Add event mode
51
+ - fmi3UpdateDiscreteStates
52
+ - fmi3GetNumberOfEventindicators
53
+ - fmi3GetNominalsOfContinuousStates
54
+ - fmi3EvaluateDiscreteStates
53
55
 
54
56
  ### How do I build an FMU from python code?
55
57
 
@@ -123,7 +125,7 @@ optional arguments:
123
125
  Requirements or environment file.
124
126
  ```
125
127
 
126
- ### Example:
128
+ ### Cosimulation Example:
127
129
 
128
130
  #### Write the script
129
131
 
@@ -169,3 +171,54 @@ pythonfmu3 build -f pythonslave.py myproject
169
171
  In this example a python class named `PythonSlave` that extends `Fmi3Slave` is declared in a file named `pythonslave.py`,
170
172
  where `myproject` is an optional folder containing additional project files required by the python script.
171
173
  Project folders such as this will be recursively copied into the FMU. Multiple project files/folders may be added.
174
+
175
+
176
+ ### Model Exchange Example
177
+
178
+ To create a model exchange FMU you must inherit from `Fmi3SlaveBase` and one of (or both) mixin classes `ModelExchange` or `CoSimulation`.
179
+
180
+ #### Write the script
181
+
182
+ ```python
183
+
184
+ from pythonfmu3 import Fmi3Causality, Fmi3SlaveBase, Float64, ModelExchange
185
+
186
+
187
+ class PythonSlaveMX(Fmi3SlaveBase, ModelExchange):
188
+
189
+ def __init__(self, **kwargs):
190
+ super().__init__(**kwargs)
191
+
192
+ self.author = "John Doe"
193
+ self.description = "A simple description"
194
+
195
+ self.time = 0.0
196
+ self.mu = 1.0
197
+ self.x0 = 2
198
+ self.x1 = 0
199
+ self.derx0 = 0.0
200
+ self.derx1 = 0.0
201
+
202
+ self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous))
203
+ self.register_variable(Float64("x0", causality=Fmi3Causality.output, start=2, variability=Fmi3Variability.continuous, initial=Fmi3Initial.exact))
204
+ self.register_variable(Float64("x1", causality=Fmi3Causality.output, start=0, variability=Fmi3Variability.continuous, initial=Fmi3Initial.exact))
205
+ self.register_variable(Float64("derx0", causality=Fmi3Causality.local, variability=Fmi3Variability.continuous, derivative=1))
206
+ self.register_variable(Float64("derx1", causality=Fmi3Causality.local, variability=Fmi3Variability.continuous, derivative=2))
207
+ self.register_variable(Float64("mu", causality=Fmi3Causality.parameter, variability=Fmi3Variability.fixed))
208
+
209
+
210
+ def get_continuous_state_derivatives(self) -> List[float]:
211
+ self.derx0 = self.x1
212
+ self.derx1 = self.mu * ((1 - self.x0**2) * self.x1) - self.x0
213
+ return [self.derx0, self.derx1]
214
+
215
+
216
+ ```
217
+
218
+ Note: There is a hard requirement that we have a `self.time` member in the derived class.
219
+
220
+ #### Create the FMU
221
+
222
+ ```
223
+ pythonfmu3 build -f pythonslaveMX.py
224
+ ```
@@ -1,12 +1,14 @@
1
- pythonfmu3/__init__.py,sha256=oN-2oXyCFwq0gvL2IEf5QvwIXBXZgsSBwAJw7LZ9vzc,424
1
+ pythonfmu3/__init__.py,sha256=ZftV413VIf6iwjwRkjR0on_r3ufKIwMkp25TBN9APhY,519
2
2
  pythonfmu3/__main__.py,sha256=gC1T8x2d02hhqshyNQGSS70SyCk-3I3t8zPqoRo2Xd8,1543
3
- pythonfmu3/_version.py,sha256=SBl2EPFW-ltPvQ7vbVWItyAsz3aKYIpjO7vcfr84GkU,22
4
- pythonfmu3/builder.py,sha256=d_nTRWKohZrZsMbTmxiYJzszzVBp-CRisV_y_OVyW6U,9779
3
+ pythonfmu3/_version.py,sha256=VrXpHDu3erkzwl_WXrqINBm9xWkcyUy53IQOj042dOs,22
4
+ pythonfmu3/builder.py,sha256=w7c9ZFv1Udz99cb7rj2NpD0CgrcHRu1SR_axm0ew__Y,10103
5
+ pythonfmu3/cosimulation.py,sha256=EZ5pa_5hy1AwoaZRzZqNz_IX8kjxoFM9sPgeqrUiRuw,179
5
6
  pythonfmu3/default_experiment.py,sha256=FJ0l0FpU7pT4Pox2RiA2y-Cb_e7DE2XlbWKySRYQaVk,293
6
7
  pythonfmu3/deploy.py,sha256=eqFWVxZUkJCLvmq1-GuMNjn2j0VCGoaXPhRWrCk2Vxg,3741
7
8
  pythonfmu3/enums.py,sha256=ZmC6vGeBTGt7HarPQ4uYV10ezPsvIxAHH1ypjNq7G3E,729
8
- pythonfmu3/fmi3slave.py,sha256=M5zZbsdM8fv8NPfMp9ljyrLcqzE5RSvM3iFz5qyxnN0,16770
9
+ pythonfmu3/fmi3slave.py,sha256=5myd4EzlkLdeyNXGYDddrORFUCiKJnzBtmcoHJtmfA4,18960
9
10
  pythonfmu3/logmsg.py,sha256=0wn11GLwq0LLWqyC2ktLRjQFWlpj07wWliZ8rUHx1gg,359
11
+ pythonfmu3/modelexchange.py,sha256=riF9YkiAY1WN27jhYnUOHwwkajrFUR6Yu6038ClxYho,792
10
12
  pythonfmu3/osutil.py,sha256=1qN6qudN4zCupZwc15pzp52WObkqi6jGy9a-MehNt9Q,656
11
13
  pythonfmu3/unit.py,sha256=SjOaywb5lVQbAO_iLjc_7Ly3nYrmAvIW2_hAGt12UFU,1475
12
14
  pythonfmu3/variable_types.py,sha256=Q0D4wlGi3i3zE5UsmGJEpNh7SV_W8mn_8p_WIkwrLQA,2881
@@ -18,23 +20,23 @@ pythonfmu3/pythonfmu-export/build_win.sh,sha256=UzmAcWqFmwBu6mvYne2Dx3UK8iPwTtP4
18
20
  pythonfmu3/pythonfmu-export/src/CMakeLists.txt,sha256=fOVlV7hy9c0wx_Qp4K51tQaQ5xy9lL4qtyGl15ZXfGs,1208
19
21
  pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_common.hpp,sha256=cgrlZa5L-bbjZeVi0pmy4JKE5UJ2GszzuyOqTdRcBRQ,4353
20
22
  pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_cs.cpp,sha256=EsUIevwmCzX9hsui3i8x1crSnSOG8dEK15Zm1ZIavYQ,3843
21
- pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_cs.hpp,sha256=UmqAVAVE1KHNHMC8mIh8gIHRJ_aQk0Ma139TU6Kvv4o,6264
22
- pythonfmu3/pythonfmu-export/src/cppfmu/fmi_functions.cpp,sha256=FL8TveY4TNAbtrgzElC4WliY8C1vOfvtd5Sh2CcVFgc,25610
23
+ pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_cs.hpp,sha256=yI_iktqM2vh2OQXj5Ul6WNsRO591QPXWefSPfXXzXFg,7330
24
+ pythonfmu3/pythonfmu-export/src/cppfmu/fmi_functions.cpp,sha256=_vZcoG4EzeIjSqY28JtTwJBMZiGepruAg1r8nbp1_BU,29606
23
25
  pythonfmu3/pythonfmu-export/src/fmi/fmi3FunctionTypes.h,sha256=Tk1WY0nAYBGiOAQ8zVbmqRAfdQttITWsLba7udhBwG4,30050
24
26
  pythonfmu3/pythonfmu-export/src/fmi/fmi3Functions.h,sha256=NsHuclp20wcuUInYf-91UXZbljTeu2cPXENqNEORdgU,16262
25
27
  pythonfmu3/pythonfmu-export/src/fmi/fmi3PlatformTypes.h,sha256=ZCQLJgSbRGrMsBiQ4auaYCY4J3Hck6g3t1iZp5NEguw,4251
26
28
  pythonfmu3/pythonfmu-export/src/pythonfmu/IPyState.hpp,sha256=GLiOjhKLDVEICersnqVwezwEshbxfdh_cyMxBJGFbu8,456
27
- pythonfmu3/pythonfmu-export/src/pythonfmu/PySlaveInstance.cpp,sha256=WShZMdZExWWG86kFPh89mATYK4tVn38JdHV6c-fZ0_A,25411
28
- pythonfmu3/pythonfmu-export/src/pythonfmu/PySlaveInstance.hpp,sha256=T-epGp68SjhDv-JupxUe2ZgnV8unU4htc-PUBokjWm4,4239
29
+ pythonfmu3/pythonfmu-export/src/pythonfmu/PySlaveInstance.cpp,sha256=wwsp1N2tuCxdZzA6tbgcqI-wXPLnjXnQn3Tkdmxfxyo,29284
30
+ pythonfmu3/pythonfmu-export/src/pythonfmu/PySlaveInstance.hpp,sha256=mMNKbzP0pZYMJQbqwa_dybPAQtTslElRvoAqaRf6_ww,5281
29
31
  pythonfmu3/pythonfmu-export/src/pythonfmu/PyState.hpp,sha256=CjFEIrZu8b1jxQAIgfI_o36hyItW_SdQ5VSkImf7JNs,2977
30
- pythonfmu3/resources/binaries/x86_64-linux/libpythonfmu-export.so,sha256=WPL5ubqKQvfH8SOe_kTVoUQjFRRr1l4HnhPM-g1VGO0,342520
31
- pythonfmu3/resources/binaries/x86_64-windows/pythonfmu-export.dll,sha256=68J_TpfzniY8g9LZyzuFqMAWgrb1JBL_qBQvlKe6ixg,414720
32
+ pythonfmu3/resources/binaries/x86_64-linux/libpythonfmu-export.so,sha256=hKu5soPg6GEieC-H5_Tnd9PIRmU_PazfWOX3Y9mAmdY,356232
33
+ pythonfmu3/resources/binaries/x86_64-windows/pythonfmu-export.dll,sha256=iNB6sT7BEg2B2Cy2Mvhi6hHfQ5ctyHnr96Qix9iRBF0,421376
32
34
  pythonfmu3/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
35
  pythonfmu3/tests/conftest.py,sha256=B6XxTnBdeF_tEJ3w2DlfPKUfvlk-oULgIhQtXkgOJIc,171
34
36
  pythonfmu3/tests/test_builder.py,sha256=GrD4ziin3RLOe_36rBQCMnKrSkhc3IqnxE1a6kCFPok,6842
35
37
  pythonfmu3/tests/test_deploy.py,sha256=JCDo-O93-izxrP9Q4K0njBcfZ-gAXYx9aZ4plgctz7k,1783
36
- pythonfmu3/tests/test_fmi3slave.py,sha256=1uwTdfiFZNmU0yzIdC30kAuu95xsZSTMA9CGk_Kdmm4,4304
37
- pythonfmu3/tests/test_integration.py,sha256=zA3iJ4rI2cKEE8mDsAmcVuwNWlJzhonV8Wxz92hzEac,10387
38
+ pythonfmu3/tests/test_fmi3slave.py,sha256=7nPT5UPQdJu7T3SSQggIi2ZL_hEgs5iEX3KNc-UYX-c,4695
39
+ pythonfmu3/tests/test_integration.py,sha256=34rus-OU9S5FlAVAfpZyoHrXoziG14d4_yw4Wdt5uVU,12513
38
40
  pythonfmu3/tests/test_logger.py,sha256=OcHQhxUtNBPH-0zdmheC4I9OWz1yu48W8MYDshNVkf8,5765
39
41
  pythonfmu3/tests/test_multiple_fmus.py,sha256=-sthCm2YUZiRkdfvpLQNgquPBForUKQ7HGqfFBdrRas,3942
40
42
  pythonfmu3/tests/test_variables.py,sha256=FL7eUCXH4RmH0rK0k6qXDnyDzthW_wAWJBHEmC-u8SI,10384
@@ -44,11 +46,13 @@ pythonfmu3/tests/data/hello.txt,sha256=wFNeS-K3n_2TKRMFQ2v4iTFOSj-uwF7P_Lt98xrZ5
44
46
  pythonfmu3/tests/slaves/PythonSlaveWithException.py,sha256=lTTMMnD5Cu09HzA8G2masKyf-ntEMfJ0a3M8btdYVLo,644
45
47
  pythonfmu3/tests/slaves/localmodule.py,sha256=-q5Lmh2I88MG7nLTscms0n5xhHLkUDed1IuQ5wj49lo,79
46
48
  pythonfmu3/tests/slaves/pythonslave.py,sha256=uzrTQmfk0QBalxNTviGMZNph_YgVmcbxPqKgX5rSvXg,2172
49
+ pythonfmu3/tests/slaves/pythonslaveMX.py,sha256=rmtiKWj-7DNCEGKAzCoS-6ybkWKabYMhatpn14r7UpA,1167
50
+ pythonfmu3/tests/slaves/pythonslaveMXCS.py,sha256=P1aKY92obd-y9VGwDRin9fwmnAlSmdHguFW8E5-LU4I,1417
47
51
  pythonfmu3/tests/slaves/pythonslave_read_file.py,sha256=t2sDaZSr2veD91gdqCO9W9CN-AN3TyXABXXfV9Rt0Xs,791
48
52
  pythonfmu3/tests/slaves/slavewithdep.py,sha256=hHDFB0dw8wkHiGzxeAVbz9O5LR6ghsFeONgRFdiK_t0,812
49
- pythonfmu3-0.2.4.dist-info/licenses/LICENSE,sha256=RL2018BU2DKcTi8Eb4ODF-XF3wnr7SDKvMP5S49x4rQ,1188
50
- pythonfmu3-0.2.4.dist-info/METADATA,sha256=HlzLHalSOQL7t06N0Gzr-tcUqvEVgFQQB8R1TQlSR7A,7607
51
- pythonfmu3-0.2.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
52
- pythonfmu3-0.2.4.dist-info/entry_points.txt,sha256=GgkWYs0DKGHLcijMEYZGkhkHOK2RVUpjGwvl1fwyDwQ,60
53
- pythonfmu3-0.2.4.dist-info/top_level.txt,sha256=6ne7bh_cME1hepxCx1BG8N5QVhVAufrp7LLok6vq7nE,11
54
- pythonfmu3-0.2.4.dist-info/RECORD,,
53
+ pythonfmu3-0.3.0.dist-info/licenses/LICENSE,sha256=RL2018BU2DKcTi8Eb4ODF-XF3wnr7SDKvMP5S49x4rQ,1188
54
+ pythonfmu3-0.3.0.dist-info/METADATA,sha256=MfS9nNJe_1MHA7fs7mlu92rsPd6bbXpKM-oTIjGU8q4,9621
55
+ pythonfmu3-0.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
56
+ pythonfmu3-0.3.0.dist-info/entry_points.txt,sha256=GgkWYs0DKGHLcijMEYZGkhkHOK2RVUpjGwvl1fwyDwQ,60
57
+ pythonfmu3-0.3.0.dist-info/top_level.txt,sha256=6ne7bh_cME1hepxCx1BG8N5QVhVAufrp7LLok6vq7nE,11
58
+ pythonfmu3-0.3.0.dist-info/RECORD,,