pythonfmu3 0.3.0__tar.gz → 0.3.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. {pythonfmu3-0.3.0/pythonfmu3.egg-info → pythonfmu3-0.3.2}/PKG-INFO +1 -10
  2. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/README.md +0 -9
  3. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/__init__.py +1 -1
  4. pythonfmu3-0.3.2/pythonfmu3/_version.py +1 -0
  5. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/fmi3slave.py +13 -2
  6. pythonfmu3-0.3.2/pythonfmu3/modelexchange.py +52 -0
  7. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_cs.hpp +1 -0
  8. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/pythonfmu-export/src/cppfmu/fmi_functions.cpp +11 -1
  9. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/pythonfmu-export/src/pythonfmu/PySlaveInstance.cpp +85 -10
  10. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/pythonfmu-export/src/pythonfmu/PySlaveInstance.hpp +1 -0
  11. pythonfmu3-0.3.2/pythonfmu3/resources/binaries/x86_64-linux/libpythonfmu-export.so +0 -0
  12. pythonfmu3-0.3.2/pythonfmu3/resources/binaries/x86_64-windows/pythonfmu-export.dll +0 -0
  13. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/test_fmi3slave.py +4 -0
  14. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2/pythonfmu3.egg-info}/PKG-INFO +1 -10
  15. pythonfmu3-0.3.0/pythonfmu3/_version.py +0 -1
  16. pythonfmu3-0.3.0/pythonfmu3/modelexchange.py +0 -23
  17. pythonfmu3-0.3.0/pythonfmu3/resources/binaries/x86_64-linux/libpythonfmu-export.so +0 -0
  18. pythonfmu3-0.3.0/pythonfmu3/resources/binaries/x86_64-windows/pythonfmu-export.dll +0 -0
  19. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/LICENSE +0 -0
  20. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/MANIFEST.in +0 -0
  21. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/__main__.py +0 -0
  22. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/builder.py +0 -0
  23. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/cosimulation.py +0 -0
  24. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/default_experiment.py +0 -0
  25. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/deploy.py +0 -0
  26. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/enums.py +0 -0
  27. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/logmsg.py +0 -0
  28. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/osutil.py +0 -0
  29. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/pythonfmu-export/.clang-format +0 -0
  30. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/pythonfmu-export/CMakeLists.txt +0 -0
  31. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/pythonfmu-export/build_unix.sh +0 -0
  32. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/pythonfmu-export/build_win.sh +0 -0
  33. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/pythonfmu-export/src/CMakeLists.txt +0 -0
  34. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_common.hpp +0 -0
  35. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_cs.cpp +0 -0
  36. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/pythonfmu-export/src/fmi/fmi3FunctionTypes.h +0 -0
  37. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/pythonfmu-export/src/fmi/fmi3Functions.h +0 -0
  38. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/pythonfmu-export/src/fmi/fmi3PlatformTypes.h +0 -0
  39. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/pythonfmu-export/src/pythonfmu/IPyState.hpp +0 -0
  40. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/pythonfmu-export/src/pythonfmu/PyState.hpp +0 -0
  41. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/__init__.py +0 -0
  42. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/conftest.py +0 -0
  43. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/data/csvdemo.csv +0 -0
  44. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/data/hello.txt +0 -0
  45. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/slaves/PythonSlaveWithException.py +0 -0
  46. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/slaves/localmodule.py +0 -0
  47. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/slaves/pythonslave.py +0 -0
  48. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/slaves/pythonslaveMX.py +0 -0
  49. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/slaves/pythonslaveMXCS.py +0 -0
  50. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/slaves/pythonslave_read_file.py +0 -0
  51. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/slaves/slavewithdep.py +0 -0
  52. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/test_builder.py +0 -0
  53. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/test_deploy.py +0 -0
  54. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/test_integration.py +0 -0
  55. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/test_logger.py +0 -0
  56. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/test_multiple_fmus.py +0 -0
  57. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/test_variables.py +0 -0
  58. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/tests/utils.py +0 -0
  59. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/unit.py +0 -0
  60. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/variable_types.py +0 -0
  61. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3/variables.py +0 -0
  62. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3.egg-info/SOURCES.txt +0 -0
  63. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3.egg-info/dependency_links.txt +0 -0
  64. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3.egg-info/entry_points.txt +0 -0
  65. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3.egg-info/not-zip-safe +0 -0
  66. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3.egg-info/requires.txt +0 -0
  67. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/pythonfmu3.egg-info/top_level.txt +0 -0
  68. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/setup.cfg +0 -0
  69. {pythonfmu3-0.3.0 → pythonfmu3-0.3.2}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pythonfmu3
3
- Version: 0.3.0
3
+ Version: 0.3.2
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
@@ -44,15 +44,6 @@ This project is a fork of the original PythonFMU repository available at https:/
44
44
  Please take a look at the examples to see the supported features.
45
45
  We currently support both the Model exchange and Cosimulation Interfaces.
46
46
 
47
- For both interfaces event mode is not supported.
48
-
49
- We currently do not support the following methods (beyond a default, trivial implementation)
50
-
51
- - fmi3UpdateDiscreteStates
52
- - fmi3GetNumberOfEventindicators
53
- - fmi3GetNominalsOfContinuousStates
54
- - fmi3EvaluateDiscreteStates
55
-
56
47
  ### How do I build an FMU from python code?
57
48
 
58
49
  1. Install `pythonfmu3` package:
@@ -17,15 +17,6 @@ This project is a fork of the original PythonFMU repository available at https:/
17
17
  Please take a look at the examples to see the supported features.
18
18
  We currently support both the Model exchange and Cosimulation Interfaces.
19
19
 
20
- For both interfaces event mode is not supported.
21
-
22
- We currently do not support the following methods (beyond a default, trivial implementation)
23
-
24
- - fmi3UpdateDiscreteStates
25
- - fmi3GetNumberOfEventindicators
26
- - fmi3GetNominalsOfContinuousStates
27
- - fmi3EvaluateDiscreteStates
28
-
29
20
  ### How do I build an FMU from python code?
30
21
 
31
22
  1. Install `pythonfmu3` package:
@@ -1,7 +1,7 @@
1
1
  from ._version import __version__
2
2
  from .builder import FmuBuilder
3
3
  from .cosimulation import CoSimulation
4
- from .modelexchange import ModelExchange
4
+ from .modelexchange import ModelExchange, Fmi3UpdateDiscreteStatesResult
5
5
  from .enums import Fmi3Causality, Fmi3Initial, Fmi3Status, Fmi3Variability
6
6
  from .fmi3slave import Fmi3Slave, Fmi3SlaveBase, Fmi3StepResult
7
7
  from .variables import Boolean, Enumeration, Int32, Int64, UInt64, Float64, String, Dimension
@@ -0,0 +1 @@
1
+ __version__ = "0.3.2"
@@ -50,6 +50,7 @@ class Fmi3SlaveBase(object):
50
50
 
51
51
  def __init__(self, **kwargs):
52
52
  self.vars = OrderedDict()
53
+ self.event_indicators: List[int] = []
53
54
  self.instance_name = kwargs["instance_name"]
54
55
  self.resources = kwargs.get("resources", None)
55
56
  self.visible = kwargs.get("visible", False)
@@ -184,7 +185,8 @@ class Fmi3SlaveBase(object):
184
185
  for v in initial_unknown:
185
186
  SubElement(structure, "InitialUnknown", attrib=dict(valueReference=str(v.value_reference)))
186
187
 
187
-
188
+ for v in self.event_indicators:
189
+ SubElement(structure, "EventIndicator", attrib=dict(valueReference=str(v)))
188
190
 
189
191
  return root
190
192
 
@@ -206,7 +208,7 @@ class Fmi3SlaveBase(object):
206
208
  raise Exception(f"Unsupported type {type(var)}!")
207
209
  var.start = refs if len(getattr(var, "dimensions", [])) > 0 else refs[0]
208
210
 
209
- def register_variable(self, var: ModelVariable, nested: bool = True, var_type: Any = None):
211
+ def register_variable(self, var: ModelVariable, nested: bool = True, var_type: Any = None, has_event_indicator: bool = False):
210
212
  """Register a variable as FMU interface.
211
213
 
212
214
  Args:
@@ -238,6 +240,12 @@ class Fmi3SlaveBase(object):
238
240
  if var_type:
239
241
  self.type_definitions[var_type.name] = var_type
240
242
  var.declared_type = var_type.name
243
+
244
+ if has_event_indicator:
245
+ self.register_event_indicator(var.value_reference)
246
+
247
+ def register_event_indicator(self, vr):
248
+ self.event_indicators.append(vr)
241
249
 
242
250
  def setup_experiment(self, start_time: float):
243
251
  pass
@@ -416,6 +424,9 @@ class Fmi3SlaveBase(object):
416
424
  if v.setter is not None:
417
425
  v.setter(value)
418
426
 
427
+ def get_number_of_event_indicators(self) -> int:
428
+ return len(self.event_indicators)
429
+
419
430
  def set_continuous_states(self, values: List[float]):
420
431
  offset = 0
421
432
  continuous_state_derivatives = list(
@@ -0,0 +1,52 @@
1
+ from abc import ABC, ABCMeta, abstractmethod
2
+ from dataclasses import dataclass
3
+
4
+ @dataclass
5
+ class Fmi3UpdateDiscreteStatesResult:
6
+ discreteStateNeedsUpdate: bool = False
7
+ terminateSimulation: bool = False
8
+ nominalsOfContinuousStatesChanged: bool = False
9
+ valuesOfContinuousStatesChanged: bool = False
10
+ nextEventTimeDefined: bool = False
11
+ nextEventTime: float = 0.0
12
+
13
+ class RequireTimeMeta(ABCMeta):
14
+ def __init__(cls, name, bases, namespace):
15
+ super().__init__(name, bases, namespace)
16
+ orig_init = cls.__init__
17
+ def new_init(self, *args, **kwargs):
18
+ orig_init(self, *args, **kwargs)
19
+ if not hasattr(self, 'time'):
20
+ raise AttributeError(f"{cls.__name__} must define 'self.time' in __init__")
21
+ cls.__init__ = new_init
22
+
23
+
24
+ # model exchange mixin
25
+ class ModelExchange(ABC, metaclass=RequireTimeMeta):
26
+ """
27
+ Classes derived from ModelExchange must define a 'self.time' member variable.
28
+
29
+ Required methods to override:
30
+ - `get_continuous_state_derivatives`: Must return a list of continuous state derivatives.
31
+
32
+ Optional methods:
33
+ - `get_event_indicators`: Should return a list of event indicators.
34
+ - `update_discrete_states`: Signify converged solution at current super-dense time instant.
35
+ """
36
+
37
+ @abstractmethod
38
+ def get_continuous_state_derivatives(self):
39
+ """Return the continuous state derivatives of the model."""
40
+ pass
41
+
42
+ def get_event_indicators(self):
43
+ """Return the event indicators of the model."""
44
+ return []
45
+
46
+ def update_discrete_states(self):
47
+ """Update the discrete states of the model."""
48
+ return Fmi3UpdateDiscreteStatesResult()
49
+
50
+ def get_nominals_of_continuous_states(self, size: int) -> list[float]:
51
+ """Return the nominal values of the continuous states."""
52
+ return [1.0] * size
@@ -141,6 +141,7 @@ public:
141
141
  virtual void SetTime(cppfmu::FMIFloat64 time) = 0;
142
142
  virtual void GetNumberOfContinuousStates(std::size_t& nStates) const = 0;
143
143
  virtual void GetNumberOfEventIndicators(std::size_t& nEventIndicators) const = 0;
144
+ virtual void GetEventIndicators(cppfmu::FMIFloat64* eventIndicators, std::size_t nEventIndicators) const = 0;
144
145
  virtual void UpdateDiscreteStates(
145
146
  cppfmu::FMIBoolean* discreteStatesNeedUpdate,
146
147
  cppfmu::FMIBoolean* terminateSimulation,
@@ -622,7 +622,17 @@ fmi3Status fmi3GetEventIndicators(
622
622
  fmi3Float64 eventIndicators[],
623
623
  size_t nEventIndicators)
624
624
  {
625
- return fmi3OK;
625
+ const auto component = reinterpret_cast<Component*>(c);
626
+ try {
627
+ component->slave->GetEventIndicators(eventIndicators, nEventIndicators);
628
+ return fmi3OK;
629
+ } catch (const cppfmu::FatalError& e) {
630
+ component->logger.Log(fmi3Fatal, "", e.what());
631
+ return fmi3Fatal;
632
+ } catch (const std::exception& e) {
633
+ component->logger.Log(fmi3Error, "", e.what());
634
+ return fmi3Error;
635
+ }
626
636
  }
627
637
 
628
638
  fmi3Status fmi3GetNominalsOfContinuousStates(
@@ -542,6 +542,7 @@ void PySlaveInstance::GetContinuousStates(cppfmu::FMIFloat64* continuousStates,
542
542
  PyObject* item = PyList_GetItem(f, i);
543
543
  continuousStates[i] = static_cast<cppfmu::FMIFloat64>(PyFloat_AsDouble(item));
544
544
  }
545
+ Py_DECREF(f);
545
546
  clearLogBuffer();
546
547
  });
547
548
  }
@@ -551,6 +552,7 @@ void PySlaveInstance::GetContinuousStateDerivatives(cppfmu::FMIFloat64* continuo
551
552
  py_safe_run([this, &continuousStateDerivatives, nStates](PyGILState_STATE gilState) {
552
553
  auto f = PyObject_CallMethod(pInstance_, "get_continuous_state_derivatives", nullptr);
553
554
  if (f == nullptr) {
555
+ PyErr_Print();
554
556
  handle_py_exception("[get_continuous_state_derivatives] PyObject_CallMethod", gilState);
555
557
  }
556
558
  // Assuming f is a list of floats
@@ -558,15 +560,27 @@ void PySlaveInstance::GetContinuousStateDerivatives(cppfmu::FMIFloat64* continuo
558
560
  PyObject* item = PyList_GetItem(f, i);
559
561
  continuousStateDerivatives[i] = static_cast<cppfmu::FMIFloat64>(PyFloat_AsDouble(item));
560
562
  }
563
+ Py_DECREF(f);
561
564
  clearLogBuffer();
562
565
  });
563
566
  }
564
567
 
565
568
  void PySlaveInstance::GetNominalsOfContinuousStates(cppfmu::FMIFloat64* nominalsOfContinuousStates, std::size_t nStates) const
566
569
  {
567
- for (size_t i = 0u; i < nStates; i++) {
568
- nominalsOfContinuousStates[i] = 1.0;
569
- }
570
+ py_safe_run([this, &nominalsOfContinuousStates, nStates](PyGILState_STATE gilState) {
571
+ auto f = PyObject_CallMethod(pInstance_, "get_nominals_of_continuous_states", "(i)", static_cast<int>(nStates));
572
+ // Check if f is a valid object
573
+ if (f == nullptr) {
574
+ handle_py_exception("[getNominalContinuousStates] PyObject_CallMethod", gilState);
575
+ }
576
+ // Assuming f is a list of floats
577
+ for (std::size_t i = 0; i < nStates; i++) {
578
+ PyObject* item = PyList_GetItem(f, i);
579
+ nominalsOfContinuousStates[i] = static_cast<cppfmu::FMIFloat64>(PyFloat_AsDouble(item));
580
+ }
581
+ Py_DECREF(f);
582
+ clearLogBuffer();
583
+ });
570
584
  }
571
585
 
572
586
  void PySlaveInstance::SetContinuousStates(const cppfmu::FMIFloat64* continuousStates, std::size_t nStates)
@@ -602,9 +616,36 @@ void PySlaveInstance::GetNumberOfContinuousStates(std::size_t& nStates) const
602
616
 
603
617
  void PySlaveInstance::GetNumberOfEventIndicators(std::size_t& nIndicators) const
604
618
  {
605
- nIndicators= 0u;
619
+ py_safe_run([this, &nIndicators](PyGILState_STATE gilState) {
620
+ auto f = PyObject_CallMethod(pInstance_, "get_number_of_event_indicators", nullptr);
621
+ if (f == nullptr) {
622
+ handle_py_exception("[getNumberOfEventIndicators] PyObject_CallMethod", gilState);
623
+ }
624
+ nIndicators = static_cast<std::size_t>(PyLong_AsLong(f));
625
+ Py_DECREF(f);
626
+ clearLogBuffer();
627
+ });
606
628
  }
607
629
 
630
+ void PySlaveInstance::GetEventIndicators(cppfmu::FMIFloat64* eventIndicators, std::size_t nIndicators) const
631
+ {
632
+ py_safe_run([this, &eventIndicators, nIndicators](PyGILState_STATE gilState) {
633
+ auto f = PyObject_CallMethod(pInstance_, "get_event_indicators", nullptr);
634
+ if (f == nullptr) {
635
+ handle_py_exception("[getEventIndicators] PyObject_CallMethod", gilState);
636
+ }
637
+ // Assuming f is a list of floats
638
+ for (std::size_t i = 0; i < nIndicators; i++) {
639
+ PyObject* item = PyList_GetItem(f, i);
640
+ eventIndicators[i] = static_cast<cppfmu::FMIFloat64>(PyFloat_AsDouble(item));
641
+ }
642
+ Py_DECREF(f);
643
+ clearLogBuffer();
644
+ });
645
+
646
+ }
647
+
648
+
608
649
  void PySlaveInstance::SetTime(cppfmu::FMIFloat64 time)
609
650
  {
610
651
  py_safe_run([this, time](PyGILState_STATE gilState) {
@@ -625,12 +666,46 @@ void PySlaveInstance::UpdateDiscreteStates(
625
666
  cppfmu::FMIBoolean* nextEventTimeDefined,
626
667
  cppfmu::FMIFloat64* nextEventTime)
627
668
  {
628
- *discreteStatesNeedUpdate = false;
629
- *terminateSimulation = false;
630
- *nominalContinuousStatesChanged = false;
631
- *valuesOfContinuousStatesChanged = false;
632
- *nextEventTimeDefined = false;
633
- *nextEventTime = 0.0;
669
+ py_safe_run([this, discreteStatesNeedUpdate, terminateSimulation, nominalContinuousStatesChanged, valuesOfContinuousStatesChanged, nextEventTimeDefined, nextEventTime](PyGILState_STATE gilState) {
670
+ auto f = PyObject_CallMethod(pInstance_, "update_discrete_states", nullptr);
671
+ if (f == nullptr) {
672
+ handle_py_exception("[updateDiscreteStates] PyObject_CallMethod", gilState);
673
+ }
674
+
675
+ if (PyObject_HasAttrString(f, "discreteStatesNeedUpdate")) {
676
+ PyObject * pyDiscreteStatesNeedUpdate = PyObject_GetAttrString(f, "discreteStatesNeedUpdate");
677
+ *discreteStatesNeedUpdate = static_cast<bool>(PyObject_IsTrue(pyDiscreteStatesNeedUpdate));
678
+ Py_DECREF(pyDiscreteStatesNeedUpdate);
679
+ }
680
+ if (PyObject_HasAttrString(f, "terminateSimulation")) {
681
+ PyObject* pyTerminateSimulation = PyObject_GetAttrString(f, "terminateSimulation");
682
+ *terminateSimulation = static_cast<bool>(PyObject_IsTrue(pyTerminateSimulation));
683
+ Py_DECREF(pyTerminateSimulation);
684
+ }
685
+ if (PyObject_HasAttrString(f, "nominalContinuousStatesChanged")) {
686
+ PyObject* pyNominalContinuousStatesChanged = PyObject_GetAttrString(f, "nominalContinuousStatesChanged");
687
+ *nominalContinuousStatesChanged = static_cast<bool>(PyObject_IsTrue(pyNominalContinuousStatesChanged));
688
+ Py_DECREF(pyNominalContinuousStatesChanged);
689
+ }
690
+ if (PyObject_HasAttrString(f, "valuesOfContinuousStatesChanged")) {
691
+ PyObject* pyValuesOfContinuousStatesChanged = PyObject_GetAttrString(f, "valuesOfContinuousStatesChanged");
692
+ *valuesOfContinuousStatesChanged = static_cast<bool>(PyObject_IsTrue(pyValuesOfContinuousStatesChanged));
693
+ Py_DECREF(pyValuesOfContinuousStatesChanged);
694
+ }
695
+ if (PyObject_HasAttrString(f, "nextEventTimeDefined")) {
696
+ PyObject* pyNextEventTimeDefined = PyObject_GetAttrString(f, "nextEventTimeDefined");
697
+ *nextEventTimeDefined = static_cast<bool>(PyObject_IsTrue(pyNextEventTimeDefined));
698
+ Py_DECREF(pyNextEventTimeDefined);
699
+ }
700
+ if (nextEventTimeDefined && *nextEventTimeDefined) {
701
+ PyObject* pyNextEventTime = PyObject_GetAttrString(f, "nextEventTime");
702
+ *nextEventTime = PyFloat_AsDouble(pyNextEventTime);
703
+ Py_DECREF(pyNextEventTime);
704
+ }
705
+
706
+ Py_DECREF(f);
707
+ clearLogBuffer();
708
+ });
634
709
  }
635
710
 
636
711
  void PySlaveInstance::GetFMUstate(fmi3FMUState& state)
@@ -57,6 +57,7 @@ public:
57
57
  void GetNumberOfEventIndicators(std::size_t& nEventIndicators) const override;
58
58
  void GetContinuousStateDerivatives(cppfmu::FMIFloat64* derivatives, std::size_t nStates) const override;
59
59
  void GetNominalsOfContinuousStates(cppfmu::FMIFloat64* nominalContinuousStates, std::size_t nStates) const override;
60
+ void GetEventIndicators(cppfmu::FMIFloat64* eventIndicators, std::size_t nEventIndicators) const override;
60
61
  void SetContinuousStates(const cppfmu::FMIFloat64* continuousStates, std::size_t nStates) override;
61
62
  void SetTime(cppfmu::FMIFloat64 time) override;
62
63
  void UpdateDiscreteStates(
@@ -155,6 +155,10 @@ def test_Fmi3Slave_customized_log_categories(new_categories):
155
155
  def test_Fmi3Slave_model_exchange():
156
156
  class Slave(Fmi3Slave, ModelExchange):
157
157
 
158
+ def __init__(self, **kwargs):
159
+ super().__init__(**kwargs)
160
+ self.time = 0.0
161
+
158
162
  def get_continuous_state_derivatives(self, vals):
159
163
  return []
160
164
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pythonfmu3
3
- Version: 0.3.0
3
+ Version: 0.3.2
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
@@ -44,15 +44,6 @@ This project is a fork of the original PythonFMU repository available at https:/
44
44
  Please take a look at the examples to see the supported features.
45
45
  We currently support both the Model exchange and Cosimulation Interfaces.
46
46
 
47
- For both interfaces event mode is not supported.
48
-
49
- We currently do not support the following methods (beyond a default, trivial implementation)
50
-
51
- - fmi3UpdateDiscreteStates
52
- - fmi3GetNumberOfEventindicators
53
- - fmi3GetNominalsOfContinuousStates
54
- - fmi3EvaluateDiscreteStates
55
-
56
47
  ### How do I build an FMU from python code?
57
48
 
58
49
  1. Install `pythonfmu3` package:
@@ -1 +0,0 @@
1
- __version__ = "0.3.0"
@@ -1,23 +0,0 @@
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
File without changes
File without changes
File without changes
File without changes