Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions examples/alltypes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from pythonfmu3 import Fmi3Causality, Fmi3Variability, Dimension, Fmi3Slave, Fmi3Status, Float64, Int32, Int64, UInt64, String, Boolean


TYPES = [UInt64, Float64, Boolean, Int32, Int64]
CAUSALITY = [Fmi3Causality.output, Fmi3Causality.input]
type_map = {
UInt64: int,
Float64: float,
Int32: int,
Int64: int,
Boolean: bool
}

def var_names(var_type, causality):
return f"{var_type.__name__.lower()}_{causality.name.lower()}"

def init_var(var_type, causality):
return type_map[var_type]()

def create_vars(self):
for var_type in TYPES:
for causality in CAUSALITY:
name = var_names(var_type, causality)
if var_type == Float64:
var = var_type(name, causality=causality, variability=Fmi3Variability.continuous)
else:
var = var_type(name, causality=causality, variability=Fmi3Variability.discrete)
setattr(self, name, init_var(var_type, causality))
self.register_variable(var)

class AllTypes(Fmi3Slave):

def __init__(self, **kwargs):
super().__init__(**kwargs)

self.author = "Stephen Smith"
self.description = "All types example"

self.time = 0.0

self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous))

create_vars(self)


def do_step(self, current_time: float, step_size: float) -> Fmi3Status:
# feedthrough
for var_type in TYPES:
input_var = getattr(self, var_names(var_type, Fmi3Causality.input))
setattr(self, var_names(var_type, Fmi3Causality.output), input_var)

return True
74 changes: 74 additions & 0 deletions examples/arraytypes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@

from pythonfmu3 import Fmi3Causality, Fmi3Variability, Dimension, Fmi3Slave, Fmi3Status, Float64, Int32, Int64, UInt64, String, Boolean

import numpy as np

SIZE = 10

TYPES = [UInt64, Float64, Boolean, Int32, Int64]
CAUSALITY = [Fmi3Causality.output, Fmi3Causality.input]

TYPE_MAP = {
UInt64: np.uint64,
Float64: np.float64,
Int32: np.int32,
Int64: np.int64,
Boolean: bool
}

def var_names(var_type, causality):
return f"{var_type.__name__.lower()}_{causality.name.lower()}"


def init_var(var_type, causality, array=True):
if array:
return np.zeros(SIZE, dtype=TYPE_MAP[var_type])
else:
return TYPE_MAP[var_type]()


def create_vars(self):
dimensions = [Dimension(start=str(SIZE))]
for var_type in TYPES:
for causality in CAUSALITY:
name = var_names(var_type, causality)
if var_type == Float64:
var = var_type(name, causality=causality, variability=Fmi3Variability.continuous, dimensions=dimensions)
else:
var = var_type(name, causality=causality, variability=Fmi3Variability.discrete, dimensions=dimensions)
setattr(self, name, init_var(var_type, causality))
self.register_variable(var)


def generate_random_data(self):
for var_type in TYPES:
causality = Fmi3Causality.output
name = var_names(var_type, causality)
var = getattr(self, name)
if var_type == Boolean:
setattr(self, name, np.random.choice(a=[False, True], size=SIZE).astype(bool))
elif var_type == Int32 or var_type == Int64 or var_type == UInt64:
setattr(self, name, np.random.randint(0, 100, size=SIZE).astype(TYPE_MAP[var_type]))
else:
setattr(self, name, np.random.rand(SIZE).astype(TYPE_MAP[var_type]))

class ArrayTypes(Fmi3Slave):

def __init__(self, **kwargs):
super().__init__(**kwargs)

self.author = "Stephen Smith"
self.description = "All types example"

self.time = 0.0

self.register_variable(Float64("time", causality=Fmi3Causality.independent, variability=Fmi3Variability.continuous))

create_vars(self)


def do_step(self, current_time: float, step_size: float) -> Fmi3Status:
generate_random_data(self)
return True


78 changes: 57 additions & 21 deletions pythonfmu3/fmi3slave.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,7 @@ def to_xml(self, model_options: Dict[str, str] = dict()) -> Element:
initial_unknown = list(
filter(lambda v: (v.causality == Fmi3Causality.output and (v.initial in allowed_variability))
or v.causality == Fmi3Causality.calculatedParameter
or v in continuous_state_derivatives and v.initial in allowed_variability
or v.variability == Fmi3Variability.continuous and v.initial in allowed_variability and v.causality != Fmi3Causality.independent, self.vars.values())
or v in continuous_state_derivatives and v.initial in allowed_variability, self.vars.values())
)

for v in outputs:
Expand Down Expand Up @@ -282,10 +281,13 @@ def get_int32(self, vrs: List[int]) -> List[int]:
for vr in vrs:
var = self.vars[vr]
if isinstance(var, Int32):
refs.append(int(var.getter()))
if len(var.dimensions) == 0:
refs.append(int(var.getter()))
else:
refs.extend(map(int, var.getter()))
else:
raise TypeError(
f"Variable with valueReference={vr} is not of type Integer!"
f"Variable with valueReference={vr} is not of type Int32!"
)
return refs

Expand All @@ -294,7 +296,10 @@ def get_int64(self, vrs: List[int]) -> List[int]:
for vr in vrs:
var = self.vars[vr]
if isinstance(var, (Enumeration, Int64)):
refs.append(int(var.getter()))
if len(var.dimensions) == 0:
refs.append(int(var.getter()))
else:
refs.extend(map(int, var.getter()))
else:
raise TypeError(
f"Variable with valueReference={vr} is not of type Int64!"
Expand All @@ -306,11 +311,14 @@ def get_uint64(self, vrs: List[int]) -> List[ctypes.c_uint64]:
for vr in vrs:
var = self.vars[vr]
if isinstance(var, UInt64):
val = var.getter()
refs.append(val if isinstance(val, ctypes.c_uint64) else ctypes.c_uint64(val))
if len(var.dimensions) == 0:
val = var.getter()
refs.append(ctypes.c_uint64(val) if not isinstance(val, ctypes.c_uint64) else val)
else:
refs.extend(map(ctypes.c_uint64, var.getter()))
else:
raise TypeError(
f"Variable with valueReference={vr} is not of type UInt64!"
f"Variable with valueReference={vr} is not of type Uint64!"
)
return refs

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

Expand All @@ -334,7 +342,11 @@ def get_boolean(self, vrs: List[int]) -> List[bool]:
for vr in vrs:
var = self.vars[vr]
if isinstance(var, Boolean):
refs.append(bool(var.getter()))
if len(var.dimensions) == 0:
refs.append(bool(var.getter()))
else:
refs.extend(var.getter())

else:
raise TypeError(
f"Variable with valueReference={vr} is not of type Boolean!"
Expand All @@ -354,30 +366,48 @@ def get_string(self, vrs: List[int]) -> List[str]:
return refs

def set_int32(self, vrs: List[int], values: List[int]):
for vr, value in zip(vrs, values):
offset = 0
for vr in vrs:
var = self.vars[vr]
if isinstance(var, Int32):
var.setter(value)
size = var.size(self.vars)
if size > 1:
var.setter(values[offset:offset+size])
else:
var.setter(values[offset])
offset += size
else:
raise TypeError(
f"Variable with valueReference={vr} is not of type Integer!"
f"Variable with valueReference={vr} is not of type Int32!"
)

def set_int64(self, vrs: List[int], values: List[int]):
for vr, value in zip(vrs, values):
offset = 0
for vr in vrs:
var = self.vars[vr]
if isinstance(var, (Enumeration, Int64)):
var.setter(value)
size = var.size(self.vars)
if size > 1:
var.setter(values[offset:offset+size])
else:
var.setter(values[offset])
offset += size
else:
raise TypeError(
f"Variable with valueReference={vr} is not of type Integer!"
f"Variable with valueReference={vr} is not of type Int64!"
)

def set_uint64(self, vrs: List[int], values: List[int]):
for vr, value in zip(vrs, values):
offset = 0
for vr in vrs:
var = self.vars[vr]
if isinstance(var, UInt64):
var.setter(value)
size = var.size(self.vars)
if size > 1:
var.setter(values[offset:offset+size])
else:
var.setter(values[offset])
offset += size
else:
raise TypeError(
f"Variable with valueReference={vr} is not of type UInt64!"
Expand All @@ -396,14 +426,20 @@ def set_float64(self, vrs: List[int], values: List[float]):
offset += size
else:
raise TypeError(
f"Variable with valueReference={vr} is not of type Real!"
f"Variable with valueReference={vr} is not of type Float64!"
)

def set_boolean(self, vrs: List[int], values: List[bool]):
for vr, value in zip(vrs, values):
offset = 0
for vr in vrs:
var = self.vars[vr]
if isinstance(var, Boolean):
var.setter(value)
size = var.size(self.vars)
if size > 1:
var.setter(values[offset:offset+size])
else:
var.setter(values[offset])
offset += size
else:
raise TypeError(
f"Variable with valueReference={vr} is not of type Boolean!"
Expand Down
30 changes: 20 additions & 10 deletions pythonfmu3/pythonfmu-export/src/cppfmu/cppfmu_cs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ void SlaveInstance::SetFloat64(
void SlaveInstance::SetInt32(
const FMIValueReference /*vr*/[],
std::size_t nvr,
const FMIInt32 /*value*/[])
const FMIInt32 /*value*/[],
std::size_t nValues)
{
if (nvr != 0) {
throw std::logic_error("Attempted to set nonexistent variable");
Expand All @@ -76,7 +77,8 @@ void SlaveInstance::SetInt32(
void SlaveInstance::SetInt64(
const FMIValueReference /*vr*/[],
std::size_t nvr,
const FMIInt64 /*value*/[])
const FMIInt64 /*value*/[],
std::size_t nValues)
{
if (nvr != 0) {
throw std::logic_error("Attempted to set nonexistent variable");
Expand All @@ -86,7 +88,8 @@ void SlaveInstance::SetInt64(
void SlaveInstance::SetUInt64(
const FMIValueReference /*vr*/[],
std::size_t nvr,
const FMIUInt64 /*value*/[])
const FMIUInt64 /*value*/[],
std::size_t nValues)
{
if (nvr != 0) {
throw std::logic_error("Attempted to set nonexistent variable");
Expand All @@ -97,7 +100,8 @@ void SlaveInstance::SetUInt64(
void SlaveInstance::SetBoolean(
const FMIValueReference /*vr*/[],
std::size_t nvr,
const FMIBoolean /*value*/[])
const FMIBoolean /*value*/[],
std::size_t nValues)
{
if (nvr != 0) {
throw std::logic_error("Attempted to set nonexistent variable");
Expand All @@ -108,7 +112,8 @@ void SlaveInstance::SetBoolean(
void SlaveInstance::SetString(
const FMIValueReference /*vr*/[],
std::size_t nvr,
const FMIString /*value*/[])
const FMIString /*value*/[],
std::size_t nValues)
{
if (nvr != 0) {
throw std::logic_error("Attempted to set nonexistent variable");
Expand All @@ -131,7 +136,8 @@ void SlaveInstance::GetFloat64(
void SlaveInstance::GetInt32(
const FMIValueReference /*vr*/[],
std::size_t nvr,
FMIInt32 /*value*/[]) const
FMIInt32 /*value*/[],
std::size_t nValues) const
{
if (nvr != 0) {
throw std::logic_error("Attempted to get nonexistent variable");
Expand All @@ -142,7 +148,8 @@ void SlaveInstance::GetInt32(
void SlaveInstance::GetInt64(
const FMIValueReference /*vr*/[],
std::size_t nvr,
FMIInt64 /*value*/[]) const
FMIInt64 /*value*/[],
std::size_t nValues) const
{
if (nvr != 0) {
throw std::logic_error("Attempted to get nonexistent variable");
Expand All @@ -153,7 +160,8 @@ void SlaveInstance::GetInt64(
void SlaveInstance::GetUInt64(
const FMIValueReference /*vr*/[],
std::size_t nvr,
FMIUInt64 /*value*/[]) const
FMIUInt64 /*value*/[],
std::size_t nValues) const
{
if (nvr != 0) {
throw std::logic_error("Attempted to get nonexistent variable");
Expand All @@ -164,7 +172,8 @@ void SlaveInstance::GetUInt64(
void SlaveInstance::GetBoolean(
const FMIValueReference /*vr*/[],
std::size_t nvr,
FMIBoolean /*value*/[]) const
FMIBoolean /*value*/[],
std::size_t nValues) const
{
if (nvr != 0) {
throw std::logic_error("Attempted to set nonexistent variable");
Expand All @@ -175,7 +184,8 @@ void SlaveInstance::GetBoolean(
void SlaveInstance::GetString(
const FMIValueReference /*vr*/[],
std::size_t nvr,
FMIString /*value*/[]) const
FMIString /*value*/[],
std::size_t nValues) const
{
if (nvr != 0) {
throw std::logic_error("Attempted to set nonexistent variable");
Expand Down
Loading