pythonfmu3 0.3.2__py3-none-any.whl → 0.3.4__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.
@@ -285,13 +285,16 @@ void PySlaveInstance::SetFloat64(const cppfmu::FMIValueReference* vr, std::size_
285
285
  });
286
286
  }
287
287
 
288
- void PySlaveInstance::SetInt32(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIInt32* values)
288
+ void PySlaveInstance::SetInt32(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIInt32* values, std::size_t nValues)
289
289
  {
290
- py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
290
+ py_safe_run([this, &vr, nvr, &values, nValues](PyGILState_STATE gilState) {
291
291
  PyObject* vrs = PyList_New(nvr);
292
- PyObject* refs = PyList_New(nvr);
292
+ PyObject* refs = PyList_New(nValues);
293
293
  for (int i = 0; i < nvr; i++) {
294
294
  PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
295
+ }
296
+
297
+ for (int i = 0; i < nValues; i++) {
295
298
  PyList_SetItem(refs, i, Py_BuildValue("i", values[i]));
296
299
  }
297
300
 
@@ -306,13 +309,15 @@ void PySlaveInstance::SetInt32(const cppfmu::FMIValueReference* vr, std::size_t
306
309
  });
307
310
  }
308
311
 
309
- void PySlaveInstance::SetInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIInt64* values)
312
+ void PySlaveInstance::SetInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIInt64* values, std::size_t nValues)
310
313
  {
311
- py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
314
+ py_safe_run([this, &vr, nvr, &values, nValues](PyGILState_STATE gilState) {
312
315
  PyObject* vrs = PyList_New(nvr);
313
- PyObject* refs = PyList_New(nvr);
316
+ PyObject* refs = PyList_New(nValues);
314
317
  for (int i = 0; i < nvr; i++) {
315
318
  PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
319
+ }
320
+ for (int i = 0; i < nValues; i++) {
316
321
  PyList_SetItem(refs, i, Py_BuildValue("L", values[i]));
317
322
  }
318
323
 
@@ -327,13 +332,15 @@ void PySlaveInstance::SetInt64(const cppfmu::FMIValueReference* vr, std::size_t
327
332
  });
328
333
  }
329
334
 
330
- void PySlaveInstance::SetUInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIUInt64* values)
335
+ void PySlaveInstance::SetUInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIUInt64* values, std::size_t nValues)
331
336
  {
332
- py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
337
+ py_safe_run([this, &vr, nvr, &values, nValues](PyGILState_STATE gilState) {
333
338
  PyObject* vrs = PyList_New(nvr);
334
- PyObject* refs = PyList_New(nvr);
339
+ PyObject* refs = PyList_New(nValues);
335
340
  for (int i = 0; i < nvr; i++) {
336
341
  PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
342
+ }
343
+ for (int i = 0; i < nValues; i++) {
337
344
  PyList_SetItem(refs, i, Py_BuildValue("K", values[i]));
338
345
  }
339
346
 
@@ -348,13 +355,15 @@ void PySlaveInstance::SetUInt64(const cppfmu::FMIValueReference* vr, std::size_t
348
355
  });
349
356
  }
350
357
 
351
- void PySlaveInstance::SetBoolean(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIBoolean* values)
358
+ void PySlaveInstance::SetBoolean(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIBoolean* values, std::size_t nValues)
352
359
  {
353
- py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
360
+ py_safe_run([this, &vr, nvr, &values, nValues](PyGILState_STATE gilState) {
354
361
  PyObject* vrs = PyList_New(nvr);
355
- PyObject* refs = PyList_New(nvr);
362
+ PyObject* refs = PyList_New(nValues);
356
363
  for (int i = 0; i < nvr; i++) {
357
364
  PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
365
+ }
366
+ for (int i = 0; i < nValues; i++) {
358
367
  PyList_SetItem(refs, i, PyBool_FromLong(values[i]));
359
368
  }
360
369
 
@@ -369,13 +378,15 @@ void PySlaveInstance::SetBoolean(const cppfmu::FMIValueReference* vr, std::size_
369
378
  });
370
379
  }
371
380
 
372
- void PySlaveInstance::SetString(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIString const* values)
381
+ void PySlaveInstance::SetString(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIString const* values, std::size_t nValues)
373
382
  {
374
- py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
383
+ py_safe_run([this, &vr, nvr, &values, nValues](PyGILState_STATE gilState) {
375
384
  PyObject* vrs = PyList_New(nvr);
376
385
  PyObject* refs = PyList_New(nvr);
377
386
  for (int i = 0; i < nvr; i++) {
378
387
  PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
388
+ }
389
+ for (int i = 0; i < nValues; i++) {
379
390
  PyList_SetItem(refs, i, Py_BuildValue("s", values[i]));
380
391
  }
381
392
 
@@ -413,9 +424,9 @@ void PySlaveInstance::GetFloat64(const cppfmu::FMIValueReference* vr, std::size_
413
424
  });
414
425
  }
415
426
 
416
- void PySlaveInstance::GetInt32(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIInt32* values) const
427
+ void PySlaveInstance::GetInt32(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIInt32* values, std::size_t nValues) const
417
428
  {
418
- py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
429
+ py_safe_run([this, &vr, nvr, &values, nValues](PyGILState_STATE gilState) {
419
430
  PyObject* vrs = PyList_New(nvr);
420
431
  for (int i = 0; i < nvr; i++) {
421
432
  PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
@@ -426,7 +437,7 @@ void PySlaveInstance::GetInt32(const cppfmu::FMIValueReference* vr, std::size_t
426
437
  handle_py_exception("[getInt32] PyObject_CallMethod", gilState);
427
438
  }
428
439
 
429
- for (int i = 0; i < nvr; i++) {
440
+ for (int i = 0; i < nValues; i++) {
430
441
  PyObject* value = PyList_GetItem(refs, i);
431
442
  values[i] = static_cast<cppfmu::FMIInt32>(PyLong_AsLong(value));
432
443
  }
@@ -435,9 +446,9 @@ void PySlaveInstance::GetInt32(const cppfmu::FMIValueReference* vr, std::size_t
435
446
  });
436
447
  }
437
448
 
438
- void PySlaveInstance::GetInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIInt64* values) const
449
+ void PySlaveInstance::GetInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIInt64* values, std::size_t nValues) const
439
450
  {
440
- py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
451
+ py_safe_run([this, &vr, nvr, &values, nValues](PyGILState_STATE gilState) {
441
452
  PyObject* vrs = PyList_New(nvr);
442
453
  for (int i = 0; i < nvr; i++) {
443
454
  PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
@@ -448,7 +459,7 @@ void PySlaveInstance::GetInt64(const cppfmu::FMIValueReference* vr, std::size_t
448
459
  handle_py_exception("[getInt64] PyObject_CallMethod", gilState);
449
460
  }
450
461
 
451
- for (int i = 0; i < nvr; i++) {
462
+ for (int i = 0; i < nValues; i++) {
452
463
  PyObject* value = PyList_GetItem(refs, i);
453
464
  values[i] = static_cast<cppfmu::FMIInt64>(PyLong_AsLongLong(value));
454
465
  }
@@ -457,9 +468,9 @@ void PySlaveInstance::GetInt64(const cppfmu::FMIValueReference* vr, std::size_t
457
468
  });
458
469
  }
459
470
 
460
- void PySlaveInstance::GetUInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIUInt64* values) const
471
+ void PySlaveInstance::GetUInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIUInt64* values, std::size_t nValues) const
461
472
  {
462
- py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
473
+ py_safe_run([this, &vr, nvr, &values, nValues](PyGILState_STATE gilState) {
463
474
  PyObject* vrs = PyList_New(nvr);
464
475
  for (int i = 0; i < nvr; i++) {
465
476
  PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
@@ -470,7 +481,7 @@ void PySlaveInstance::GetUInt64(const cppfmu::FMIValueReference* vr, std::size_t
470
481
  handle_py_exception("[getUInt64] PyObject_CallMethod", gilState);
471
482
  }
472
483
 
473
- for (int i = 0; i < nvr; i++) {
484
+ for (int i = 0; i < nValues; i++) {
474
485
  PyObject* item = PyList_GetItem(refs, i);
475
486
  PyObject* value = PyObject_GetAttrString(item, "value");
476
487
  if (value && PyLong_Check(value))
@@ -484,9 +495,9 @@ void PySlaveInstance::GetUInt64(const cppfmu::FMIValueReference* vr, std::size_t
484
495
  });
485
496
  }
486
497
 
487
- void PySlaveInstance::GetBoolean(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIBoolean* values) const
498
+ void PySlaveInstance::GetBoolean(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIBoolean* values, std::size_t nValues) const
488
499
  {
489
- py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
500
+ py_safe_run([this, &vr, nvr, &values, nValues](PyGILState_STATE gilState) {
490
501
  PyObject* vrs = PyList_New(nvr);
491
502
  for (int i = 0; i < nvr; i++) {
492
503
  PyList_SetItem(vrs, i, Py_BuildValue("i", vr[i]));
@@ -497,7 +508,7 @@ void PySlaveInstance::GetBoolean(const cppfmu::FMIValueReference* vr, std::size_
497
508
  handle_py_exception("[getBoolean] PyObject_CallMethod", gilState);
498
509
  }
499
510
 
500
- for (int i = 0; i < nvr; i++) {
511
+ for (int i = 0; i < nValues; i++) {
501
512
  PyObject* value = PyList_GetItem(refs, i);
502
513
  values[i] = PyObject_IsTrue(value);
503
514
  }
@@ -506,9 +517,9 @@ void PySlaveInstance::GetBoolean(const cppfmu::FMIValueReference* vr, std::size_
506
517
  });
507
518
  }
508
519
 
509
- void PySlaveInstance::GetString(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIString* values) const
520
+ void PySlaveInstance::GetString(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIString* values, std::size_t nValues) const
510
521
  {
511
- py_safe_run([this, &vr, nvr, &values](PyGILState_STATE gilState) {
522
+ py_safe_run([this, &vr, nvr, &values, nValues](PyGILState_STATE gilState) {
512
523
  clearStrBuffer();
513
524
  PyObject* vrs = PyList_New(nvr);
514
525
  for (int i = 0; i < nvr; i++) {
@@ -520,7 +531,7 @@ void PySlaveInstance::GetString(const cppfmu::FMIValueReference* vr, std::size_t
520
531
  handle_py_exception("[getString] PyObject_CallMethod", gilState);
521
532
  }
522
533
 
523
- for (int i = 0; i < nvr; i++) {
534
+ for (int i = 0; i < nValues; i++) {
524
535
  PyObject* value = PyUnicode_AsEncodedString(PyList_GetItem(refs, i), "utf-8", nullptr);
525
536
  values[i] = PyBytes_AsString(value);
526
537
  strBuffer.emplace_back(value);
@@ -34,18 +34,18 @@ public:
34
34
  cppfmu::FMIFloat64& endOfStep) override;
35
35
 
36
36
  void SetFloat64(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIFloat64* value, std::size_t nValues) override;
37
- void SetInt32(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIInt32* value) override;
38
- void SetInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIInt64* value) override;
39
- void SetUInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIUInt64* value) override;
40
- void SetBoolean(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIBoolean* value) override;
41
- void SetString(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIString const* value) override;
37
+ void SetInt32(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIInt32* value, std::size_t nValues) override;
38
+ void SetInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIInt64* value, std::size_t nValues) override;
39
+ void SetUInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIUInt64* value, std::size_t nValues) override;
40
+ void SetBoolean(const cppfmu::FMIValueReference* vr, std::size_t nvr, const cppfmu::FMIBoolean* value, std::size_t nValues) override;
41
+ void SetString(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIString const* value, std::size_t nValues) override;
42
42
 
43
43
  void GetFloat64(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIFloat64* value, std::size_t nValues) const override;
44
- void GetInt32(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIInt32* value) const override;
45
- void GetInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIInt64* value) const override;
46
- void GetUInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIUInt64* value) const override;
47
- void GetBoolean(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIBoolean* value) const override;
48
- void GetString(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIString* value) const override;
44
+ void GetInt32(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIInt32* value, std::size_t nValues) const override;
45
+ void GetInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIInt64* value, std::size_t nValues) const override;
46
+ void GetUInt64(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIUInt64* value, std::size_t nValues) const override;
47
+ void GetBoolean(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIBoolean* value, std::size_t nValues) const override;
48
+ void GetString(const cppfmu::FMIValueReference* vr, std::size_t nvr, cppfmu::FMIString* value, std::size_t nValues) const override;
49
49
 
50
50
  void GetFMUstate(fmi3FMUState& State) override;
51
51
  void SetFMUstate(const fmi3FMUState& State) override;
@@ -0,0 +1,80 @@
1
+
2
+ from pythonfmu3 import Fmi3Causality, Fmi3Variability, Dimension, Fmi3Slave, Fmi3Status, Float64, Int32, Int64, UInt64, String, Boolean
3
+
4
+ import numpy as np
5
+
6
+ SIZE = 10
7
+
8
+ TYPES = [UInt64, Float64, Boolean, Int32, Int64]
9
+ CAUSALITY = [Fmi3Causality.output, Fmi3Causality.input]
10
+
11
+ TYPE_MAP = {
12
+ UInt64: np.uint64,
13
+ Float64: np.float64,
14
+ Int32: np.int32,
15
+ Int64: np.int64,
16
+ Boolean: bool
17
+ }
18
+
19
+ def var_names(var_type, causality):
20
+ return f"{var_type.__name__.lower()}_{causality.name.lower()}"
21
+
22
+
23
+ def init_var(var_type, causality, array=True):
24
+ if array:
25
+ return np.zeros(SIZE, dtype=TYPE_MAP[var_type])
26
+ else:
27
+ return TYPE_MAP[var_type]()
28
+
29
+
30
+ def create_vars(self):
31
+ dimensions = [Dimension(start=str(SIZE))]
32
+ for var_type in TYPES:
33
+ for causality in CAUSALITY:
34
+ name = var_names(var_type, causality)
35
+ if var_type == Float64:
36
+ var = var_type(name, causality=causality, variability=Fmi3Variability.continuous, dimensions=dimensions)
37
+ else:
38
+ var = var_type(name, causality=causality, variability=Fmi3Variability.discrete, dimensions=dimensions)
39
+ setattr(self, name, init_var(var_type, causality))
40
+ self.register_variable(var)
41
+
42
+
43
+ def generate_data(self):
44
+ for var_type in TYPES:
45
+ causality = Fmi3Causality.output
46
+ name = var_names(var_type, causality)
47
+ var = getattr(self, name)
48
+ if var_type == Boolean:
49
+ data = [False, True, False, True, True, False, False, True, False, True]
50
+ setattr(self, name, np.array(data).astype(bool))
51
+ elif var_type == Int32 or var_type == Int64 or var_type == UInt64:
52
+ data = [1,2,3,4,5,6,7,8,9,10]
53
+ setattr(self, name, np.array(data).astype(TYPE_MAP[var_type]))
54
+ else:
55
+ data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]
56
+ setattr(self, name, np.array(data).astype(TYPE_MAP[var_type]))
57
+
58
+ class ArrayTypes(Fmi3Slave):
59
+
60
+
61
+ def __init__(self, **kwargs):
62
+ super().__init__(**kwargs)
63
+
64
+ self.author = "Tester"
65
+ self.description = "FMU with all basic types as arrays"
66
+
67
+ self.time = 0.0
68
+
69
+ self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous))
70
+
71
+ create_vars(self)
72
+
73
+ generate_data(self)
74
+
75
+
76
+ def do_step(self, current_time: float, step_size: float) -> Fmi3Status:
77
+ generate_data(self)
78
+ return True
79
+
80
+
@@ -0,0 +1,98 @@
1
+ import pytest
2
+ import pathlib
3
+ import re
4
+ import tempfile
5
+
6
+ def extract_python_code_from_md(md_file):
7
+ """Extract Python code blocks from markdown, excluding skip blocks"""
8
+ content = pathlib.Path(md_file).read_text()
9
+
10
+ # Find all python code blocks that aren't marked as skip
11
+ python_blocks = []
12
+
13
+ # Pattern to match python blocks but not python skip
14
+ pattern = r'```python(?!\s+skip)(?:[^\n]*)\n(.*?)\n```'
15
+ matches = re.findall(pattern, content, re.DOTALL)
16
+
17
+ for match in matches:
18
+ # Skip blocks that are wrapped in skip-test comments
19
+ if '<!-- skip-test -->' not in content.split(match)[0][-100:]:
20
+ python_blocks.append(match)
21
+
22
+ return python_blocks
23
+
24
+ @pytest.mark.doc
25
+ def test_readme():
26
+ test_dir = pathlib.Path(__file__).parent
27
+ fpath = test_dir.parent.parent / "README.md"
28
+
29
+ # extract Python code
30
+ code_blocks = extract_python_code_from_md(fpath)
31
+
32
+ namespace = {}
33
+ exec("from pythonfmu3 import *", namespace)
34
+
35
+ for i, code in enumerate(code_blocks):
36
+ try:
37
+ exec(code, namespace)
38
+ print(f"✅ Code block {i+1} executed successfully")
39
+ except Exception as e:
40
+ pytest.fail(f"Code block {i+1} failed: {e}\nCode:\n{code}")
41
+
42
+
43
+
44
+
45
+ @pytest.mark.doc
46
+ def test_cosimulation_examples():
47
+ """Test that all Python examples in usage.md actually work"""
48
+ test_dir = pathlib.Path(__file__).parent
49
+ usage_file = test_dir.parent.parent / "docs" / "usage.md"
50
+
51
+ # Extract Python code
52
+ code_blocks = extract_python_code_from_md(usage_file)
53
+
54
+ # Create a test namespace
55
+ namespace = {}
56
+ exec("from pythonfmu3 import *", namespace)
57
+
58
+ # Execute each code block
59
+ for i, code in enumerate(code_blocks):
60
+ try:
61
+ exec(code, namespace)
62
+ print(f"✅ Code block {i+1} executed successfully")
63
+ except Exception as e:
64
+ pytest.fail(f"Code block {i+1} failed: {e}\nCode:\n{code}")
65
+
66
+ assert 'LinearTransform' in namespace, "LinearTransform class not found"
67
+ assert 'PIDController' in namespace, "PIDController class not found"
68
+
69
+ # Test instantiation
70
+ lt = namespace['LinearTransform'](instance_name="test")
71
+ pc = namespace['PIDController'](instance_name="test")
72
+
73
+
74
+ @pytest.mark.doc
75
+ def test_model_exchange_examples():
76
+ """Test Model Exchange examples"""
77
+ test_dir = pathlib.Path(__file__).parent
78
+ mx_file = test_dir.parent.parent / "docs" / "usageMX.md"
79
+
80
+ code_blocks = extract_python_code_from_md(mx_file)
81
+
82
+ namespace = {}
83
+ exec("from pythonfmu3 import *", namespace)
84
+
85
+ for i, code in enumerate(code_blocks):
86
+ try:
87
+ exec(code, namespace)
88
+ except Exception as e:
89
+ pytest.fail(f"MX Code block {i+1} failed: {e}")
90
+
91
+ # Test that classes were actually created
92
+ assert 'VanDerPol' in namespace, "VanDerPol class not found"
93
+ assert 'BouncingBall' in namespace, "BouncingBall class not found"
94
+
95
+ # Test instantiation
96
+ vdp = namespace['VanDerPol'](instance_name="test")
97
+
98
+ bb = namespace['BouncingBall'](instance_name="test")
@@ -280,6 +280,57 @@ def test_integration_get(tmp_path):
280
280
  model.terminate()
281
281
  model.freeInstance()
282
282
 
283
+ @pytest.mark.integration
284
+ def test_integration_get_array(tmp_path):
285
+ script_file = Path(__file__).parent / "slaves/pythonslave_arraytypes.py"
286
+ fmu = FmuBuilder.build_FMU(script_file, dest=tmp_path, needsExecutionTool="false")
287
+ assert fmu.exists()
288
+
289
+ md = fmpy.read_model_description(fmu)
290
+ unzip_dir = fmpy.extract(fmu)
291
+
292
+ model = fmpy.fmi3.FMU3Slave(
293
+ guid=md.guid,
294
+ unzipDirectory=unzip_dir,
295
+ modelIdentifier=md.coSimulation.modelIdentifier,
296
+ instanceName='instance1')
297
+
298
+ model.instantiate()
299
+ model.enterInitializationMode()
300
+ model.exitInitializationMode()
301
+
302
+ to_test = {
303
+ "int32_output": [1,2,3,4,5,6,7,8,9,10],
304
+ "int64_output": [1,2,3,4,5,6,7,8,9,10],
305
+ "uint64_output": [1,2,3,4,5,6,7,8,9,10],
306
+ "float64_output": [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0],
307
+ "boolean_output": [False, True, False, True, True, False, False, True, False, True]
308
+ }
309
+
310
+ model_value = None
311
+ variables = mapped(md)
312
+ for key, value in to_test.items():
313
+ var = variables[key]
314
+ vrs = [var.valueReference]
315
+ if var.type == "Int32":
316
+ model_values = model.getInt32(vrs, nValues=10)
317
+ elif var.type == "Int64":
318
+ model_values = model.getInt64(vrs, nValues=10)
319
+ elif var.type == "UInt64":
320
+ model_values = model.getUInt64(vrs, nValues=10)
321
+ elif var.type == "Float64":
322
+ model_values = model.getFloat64(vrs, nValues=10)
323
+ elif var.type == "Boolean":
324
+ model_values = model.getBoolean(vrs, nValues=10)
325
+ else:
326
+ pytest.xfail("Unsupported type")
327
+
328
+ assert len(model_values) == len(value)
329
+ assert model_values == value
330
+
331
+ model.terminate()
332
+ model.freeInstance()
333
+
283
334
 
284
335
  @pytest.mark.integration
285
336
  def test_integration_read_from_file(tmp_path):
@@ -367,6 +418,61 @@ def test_integration_set(tmp_path):
367
418
  model.terminate()
368
419
  model.freeInstance()
369
420
 
421
+ @pytest.mark.integration
422
+ def test_integration_set_array(tmp_path):
423
+ script_file = Path(__file__).parent / "slaves/pythonslave_arraytypes.py"
424
+ fmu = FmuBuilder.build_FMU(script_file, dest=tmp_path, needsExecutionTool="false")
425
+ assert fmu.exists()
426
+
427
+ md = fmpy.read_model_description(fmu)
428
+ unzip_dir = fmpy.extract(fmu)
429
+
430
+ model = fmpy.fmi3.FMU3Slave(
431
+ guid=md.guid,
432
+ unzipDirectory=unzip_dir,
433
+ modelIdentifier=md.coSimulation.modelIdentifier,
434
+ instanceName='instance1')
435
+
436
+ model.instantiate()
437
+ model.enterInitializationMode()
438
+ model.exitInitializationMode()
439
+
440
+ to_test = {
441
+ "int32_input": [1,2,3,4,5,6,7,8,9,10],
442
+ "int64_input": [1,2,3,4,5,6,7,8,9,10],
443
+ "uint64_input": [1,2,3,4,5,6,7,8,9,10],
444
+ "float64_input": [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0],
445
+ "boolean_input": [False, True, False, True, True, False, False, True, False, True]
446
+ }
447
+
448
+ model_value = None
449
+ variables = mapped(md)
450
+ for key, value in to_test.items():
451
+ var = variables[key]
452
+ vrs = [var.valueReference]
453
+ if var.type == "Int32":
454
+ model.setInt32(vrs, value)
455
+ model_value = model.getInt32(vrs, nValues=10)
456
+ elif var.type == "Int64":
457
+ model.setInt64(vrs, value)
458
+ model_value = model.getInt64(vrs, nValues=10)
459
+ elif var.type == "UInt64":
460
+ model.setUInt64(vrs, value)
461
+ model_value = model.getUInt64(vrs, nValues=10)
462
+ elif var.type == "Float64":
463
+ model.setFloat64(vrs, value)
464
+ model_value = model.getFloat64(vrs,nValues=10)
465
+ elif var.type == "Boolean":
466
+ model.setBoolean(vrs, value)
467
+ model_value = model.getBoolean(vrs, nValues=10)
468
+ else:
469
+ pytest.xfail("Unsupported type")
470
+
471
+ assert list(model_value) == value
472
+
473
+ model.terminate()
474
+ model.freeInstance()
475
+
370
476
 
371
477
  @pytest.mark.integration
372
478
  def test_simple_integration_fmpy(tmp_path):