Skip to content

Commit 889a7bb

Browse files
expand array var capabilities (#32)
1 parent 283fe70 commit 889a7bb

File tree

11 files changed

+537
-134
lines changed

11 files changed

+537
-134
lines changed

examples/alltypes.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from pythonfmu3 import Fmi3Causality, Fmi3Variability, Dimension, Fmi3Slave, Fmi3Status, Float64, Int32, Int64, UInt64, String, Boolean
2+
3+
4+
TYPES = [UInt64, Float64, Boolean, Int32, Int64]
5+
CAUSALITY = [Fmi3Causality.output, Fmi3Causality.input]
6+
type_map = {
7+
UInt64: int,
8+
Float64: float,
9+
Int32: int,
10+
Int64: int,
11+
Boolean: bool
12+
}
13+
14+
def var_names(var_type, causality):
15+
return f"{var_type.__name__.lower()}_{causality.name.lower()}"
16+
17+
def init_var(var_type, causality):
18+
return type_map[var_type]()
19+
20+
def create_vars(self):
21+
for var_type in TYPES:
22+
for causality in CAUSALITY:
23+
name = var_names(var_type, causality)
24+
if var_type == Float64:
25+
var = var_type(name, causality=causality, variability=Fmi3Variability.continuous)
26+
else:
27+
var = var_type(name, causality=causality, variability=Fmi3Variability.discrete)
28+
setattr(self, name, init_var(var_type, causality))
29+
self.register_variable(var)
30+
31+
class AllTypes(Fmi3Slave):
32+
33+
def __init__(self, **kwargs):
34+
super().__init__(**kwargs)
35+
36+
self.author = "Stephen Smith"
37+
self.description = "All types example"
38+
39+
self.time = 0.0
40+
41+
self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous))
42+
43+
create_vars(self)
44+
45+
46+
def do_step(self, current_time: float, step_size: float) -> Fmi3Status:
47+
# feedthrough
48+
for var_type in TYPES:
49+
input_var = getattr(self, var_names(var_type, Fmi3Causality.input))
50+
setattr(self, var_names(var_type, Fmi3Causality.output), input_var)
51+
52+
return True

examples/arraytypes.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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_random_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+
setattr(self, name, np.random.choice(a=[False, True], size=SIZE).astype(bool))
50+
elif var_type == Int32 or var_type == Int64 or var_type == UInt64:
51+
setattr(self, name, np.random.randint(0, 100, size=SIZE).astype(TYPE_MAP[var_type]))
52+
else:
53+
setattr(self, name, np.random.rand(SIZE).astype(TYPE_MAP[var_type]))
54+
55+
class ArrayTypes(Fmi3Slave):
56+
57+
def __init__(self, **kwargs):
58+
super().__init__(**kwargs)
59+
60+
self.author = "Stephen Smith"
61+
self.description = "All types example"
62+
63+
self.time = 0.0
64+
65+
self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous))
66+
67+
create_vars(self)
68+
69+
70+
def do_step(self, current_time: float, step_size: float) -> Fmi3Status:
71+
generate_random_data(self)
72+
return True
73+
74+

pythonfmu3/fmi3slave.py

Lines changed: 57 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,7 @@ def to_xml(self, model_options: Dict[str, str] = dict()) -> Element:
183183
initial_unknown = list(
184184
filter(lambda v: (v.causality == Fmi3Causality.output and (v.initial in allowed_variability))
185185
or v.causality == Fmi3Causality.calculatedParameter
186-
or v in continuous_state_derivatives and v.initial in allowed_variability
187-
or v.variability == Fmi3Variability.continuous and v.initial in allowed_variability and v.causality != Fmi3Causality.independent, self.vars.values())
186+
or v in continuous_state_derivatives and v.initial in allowed_variability, self.vars.values())
188187
)
189188

190189
for v in outputs:
@@ -282,10 +281,13 @@ def get_int32(self, vrs: List[int]) -> List[int]:
282281
for vr in vrs:
283282
var = self.vars[vr]
284283
if isinstance(var, Int32):
285-
refs.append(int(var.getter()))
284+
if len(var.dimensions) == 0:
285+
refs.append(int(var.getter()))
286+
else:
287+
refs.extend(map(int, var.getter()))
286288
else:
287289
raise TypeError(
288-
f"Variable with valueReference={vr} is not of type Integer!"
290+
f"Variable with valueReference={vr} is not of type Int32!"
289291
)
290292
return refs
291293

@@ -294,7 +296,10 @@ def get_int64(self, vrs: List[int]) -> List[int]:
294296
for vr in vrs:
295297
var = self.vars[vr]
296298
if isinstance(var, (Enumeration, Int64)):
297-
refs.append(int(var.getter()))
299+
if len(var.dimensions) == 0:
300+
refs.append(int(var.getter()))
301+
else:
302+
refs.extend(map(int, var.getter()))
298303
else:
299304
raise TypeError(
300305
f"Variable with valueReference={vr} is not of type Int64!"
@@ -306,11 +311,14 @@ def get_uint64(self, vrs: List[int]) -> List[ctypes.c_uint64]:
306311
for vr in vrs:
307312
var = self.vars[vr]
308313
if isinstance(var, UInt64):
309-
val = var.getter()
310-
refs.append(val if isinstance(val, ctypes.c_uint64) else ctypes.c_uint64(val))
314+
if len(var.dimensions) == 0:
315+
val = var.getter()
316+
refs.append(ctypes.c_uint64(val) if not isinstance(val, ctypes.c_uint64) else val)
317+
else:
318+
refs.extend(map(ctypes.c_uint64, var.getter()))
311319
else:
312320
raise TypeError(
313-
f"Variable with valueReference={vr} is not of type UInt64!"
321+
f"Variable with valueReference={vr} is not of type Uint64!"
314322
)
315323
return refs
316324

@@ -325,7 +333,7 @@ def get_float64(self, vrs: List[int]) -> List[float]:
325333
refs.extend(var.getter())
326334
else:
327335
raise TypeError(
328-
f"Variable with valueReference={vr} is not of type Real!"
336+
f"Variable with valueReference={vr} is not of type Float64!"
329337
)
330338
return refs
331339

@@ -334,7 +342,11 @@ def get_boolean(self, vrs: List[int]) -> List[bool]:
334342
for vr in vrs:
335343
var = self.vars[vr]
336344
if isinstance(var, Boolean):
337-
refs.append(bool(var.getter()))
345+
if len(var.dimensions) == 0:
346+
refs.append(bool(var.getter()))
347+
else:
348+
refs.extend(var.getter())
349+
338350
else:
339351
raise TypeError(
340352
f"Variable with valueReference={vr} is not of type Boolean!"
@@ -354,30 +366,48 @@ def get_string(self, vrs: List[int]) -> List[str]:
354366
return refs
355367

356368
def set_int32(self, vrs: List[int], values: List[int]):
357-
for vr, value in zip(vrs, values):
369+
offset = 0
370+
for vr in vrs:
358371
var = self.vars[vr]
359372
if isinstance(var, Int32):
360-
var.setter(value)
373+
size = var.size(self.vars)
374+
if size > 1:
375+
var.setter(values[offset:offset+size])
376+
else:
377+
var.setter(values[offset])
378+
offset += size
361379
else:
362380
raise TypeError(
363-
f"Variable with valueReference={vr} is not of type Integer!"
381+
f"Variable with valueReference={vr} is not of type Int32!"
364382
)
365383

366384
def set_int64(self, vrs: List[int], values: List[int]):
367-
for vr, value in zip(vrs, values):
385+
offset = 0
386+
for vr in vrs:
368387
var = self.vars[vr]
369388
if isinstance(var, (Enumeration, Int64)):
370-
var.setter(value)
389+
size = var.size(self.vars)
390+
if size > 1:
391+
var.setter(values[offset:offset+size])
392+
else:
393+
var.setter(values[offset])
394+
offset += size
371395
else:
372396
raise TypeError(
373-
f"Variable with valueReference={vr} is not of type Integer!"
397+
f"Variable with valueReference={vr} is not of type Int64!"
374398
)
375399

376400
def set_uint64(self, vrs: List[int], values: List[int]):
377-
for vr, value in zip(vrs, values):
401+
offset = 0
402+
for vr in vrs:
378403
var = self.vars[vr]
379404
if isinstance(var, UInt64):
380-
var.setter(value)
405+
size = var.size(self.vars)
406+
if size > 1:
407+
var.setter(values[offset:offset+size])
408+
else:
409+
var.setter(values[offset])
410+
offset += size
381411
else:
382412
raise TypeError(
383413
f"Variable with valueReference={vr} is not of type UInt64!"
@@ -396,14 +426,20 @@ def set_float64(self, vrs: List[int], values: List[float]):
396426
offset += size
397427
else:
398428
raise TypeError(
399-
f"Variable with valueReference={vr} is not of type Real!"
429+
f"Variable with valueReference={vr} is not of type Float64!"
400430
)
401431

402432
def set_boolean(self, vrs: List[int], values: List[bool]):
403-
for vr, value in zip(vrs, values):
433+
offset = 0
434+
for vr in vrs:
404435
var = self.vars[vr]
405436
if isinstance(var, Boolean):
406-
var.setter(value)
437+
size = var.size(self.vars)
438+
if size > 1:
439+
var.setter(values[offset:offset+size])
440+
else:
441+
var.setter(values[offset])
442+
offset += size
407443
else:
408444
raise TypeError(
409445
f"Variable with valueReference={vr} is not of type Boolean!"

pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_cs.cpp

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ void SlaveInstance::SetFloat64(
6666
void SlaveInstance::SetInt32(
6767
const FMIValueReference /*vr*/[],
6868
std::size_t nvr,
69-
const FMIInt32 /*value*/[])
69+
const FMIInt32 /*value*/[],
70+
std::size_t nValues)
7071
{
7172
if (nvr != 0) {
7273
throw std::logic_error("Attempted to set nonexistent variable");
@@ -76,7 +77,8 @@ void SlaveInstance::SetInt32(
7677
void SlaveInstance::SetInt64(
7778
const FMIValueReference /*vr*/[],
7879
std::size_t nvr,
79-
const FMIInt64 /*value*/[])
80+
const FMIInt64 /*value*/[],
81+
std::size_t nValues)
8082
{
8183
if (nvr != 0) {
8284
throw std::logic_error("Attempted to set nonexistent variable");
@@ -86,7 +88,8 @@ void SlaveInstance::SetInt64(
8688
void SlaveInstance::SetUInt64(
8789
const FMIValueReference /*vr*/[],
8890
std::size_t nvr,
89-
const FMIUInt64 /*value*/[])
91+
const FMIUInt64 /*value*/[],
92+
std::size_t nValues)
9093
{
9194
if (nvr != 0) {
9295
throw std::logic_error("Attempted to set nonexistent variable");
@@ -97,7 +100,8 @@ void SlaveInstance::SetUInt64(
97100
void SlaveInstance::SetBoolean(
98101
const FMIValueReference /*vr*/[],
99102
std::size_t nvr,
100-
const FMIBoolean /*value*/[])
103+
const FMIBoolean /*value*/[],
104+
std::size_t nValues)
101105
{
102106
if (nvr != 0) {
103107
throw std::logic_error("Attempted to set nonexistent variable");
@@ -108,7 +112,8 @@ void SlaveInstance::SetBoolean(
108112
void SlaveInstance::SetString(
109113
const FMIValueReference /*vr*/[],
110114
std::size_t nvr,
111-
const FMIString /*value*/[])
115+
const FMIString /*value*/[],
116+
std::size_t nValues)
112117
{
113118
if (nvr != 0) {
114119
throw std::logic_error("Attempted to set nonexistent variable");
@@ -131,7 +136,8 @@ void SlaveInstance::GetFloat64(
131136
void SlaveInstance::GetInt32(
132137
const FMIValueReference /*vr*/[],
133138
std::size_t nvr,
134-
FMIInt32 /*value*/[]) const
139+
FMIInt32 /*value*/[],
140+
std::size_t nValues) const
135141
{
136142
if (nvr != 0) {
137143
throw std::logic_error("Attempted to get nonexistent variable");
@@ -142,7 +148,8 @@ void SlaveInstance::GetInt32(
142148
void SlaveInstance::GetInt64(
143149
const FMIValueReference /*vr*/[],
144150
std::size_t nvr,
145-
FMIInt64 /*value*/[]) const
151+
FMIInt64 /*value*/[],
152+
std::size_t nValues) const
146153
{
147154
if (nvr != 0) {
148155
throw std::logic_error("Attempted to get nonexistent variable");
@@ -153,7 +160,8 @@ void SlaveInstance::GetInt64(
153160
void SlaveInstance::GetUInt64(
154161
const FMIValueReference /*vr*/[],
155162
std::size_t nvr,
156-
FMIUInt64 /*value*/[]) const
163+
FMIUInt64 /*value*/[],
164+
std::size_t nValues) const
157165
{
158166
if (nvr != 0) {
159167
throw std::logic_error("Attempted to get nonexistent variable");
@@ -164,7 +172,8 @@ void SlaveInstance::GetUInt64(
164172
void SlaveInstance::GetBoolean(
165173
const FMIValueReference /*vr*/[],
166174
std::size_t nvr,
167-
FMIBoolean /*value*/[]) const
175+
FMIBoolean /*value*/[],
176+
std::size_t nValues) const
168177
{
169178
if (nvr != 0) {
170179
throw std::logic_error("Attempted to set nonexistent variable");
@@ -175,7 +184,8 @@ void SlaveInstance::GetBoolean(
175184
void SlaveInstance::GetString(
176185
const FMIValueReference /*vr*/[],
177186
std::size_t nvr,
178-
FMIString /*value*/[]) const
187+
FMIString /*value*/[],
188+
std::size_t nValues) const
179189
{
180190
if (nvr != 0) {
181191
throw std::logic_error("Attempted to set nonexistent variable");

0 commit comments

Comments
 (0)