Skip to content

Commit

Permalink
Merge branch 'release/v0.3.10'
Browse files Browse the repository at this point in the history
  • Loading branch information
t-sommer committed Jun 7, 2022
2 parents c01eb7b + 8e9a126 commit b76dfc8
Show file tree
Hide file tree
Showing 9 changed files with 81 additions and 48 deletions.
1 change: 1 addition & 0 deletions build_binaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
check_call([
'cmake',
'-D', f'CVODE_INSTALL_DIR=../sundials-5.3.0/{platform}/static/install',
'-D', 'CMAKE_OSX_ARCHITECTURES=arm64;x86_64',
'-S', 'src',
'-B', build_dir
] + cmake_options)
Expand Down
2 changes: 2 additions & 0 deletions build_cvode.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
'-D', f'CMAKE_INSTALL_PREFIX=sundials-5.3.0/{platform}/static/install',
'-D', 'CMAKE_USER_MAKE_RULES_OVERRIDE=../OverrideMSVCFlags.cmake',
'-D', 'EXAMPLES_ENABLE_C=OFF',
'-D', 'CMAKE_OSX_ARCHITECTURES=arm64;x86_64',
'-S', 'sundials-5.3.0',
'-B', f'sundials-5.3.0/{platform}/static'
] + cmake_options)
Expand All @@ -67,6 +68,7 @@
'-D', 'EXAMPLES_ENABLE_C=OFF',
'-D', f'CMAKE_INSTALL_PREFIX=sundials-5.3.0/{platform}/dynamic/install',
'-D', 'CMAKE_USER_MAKE_RULES_OVERRIDE=../OverrideMSVCFlags.cmake',
'-D', 'CMAKE_OSX_ARCHITECTURES=arm64;x86_64',
'-S', 'sundials-5.3.0',
'-B', f'sundials-5.3.0/{platform}/dynamic'
] + cmake_options)
Expand Down
14 changes: 14 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
## v0.3.10 (2022-06-07)

### Bug fixes

- Fix architecture for 32-bit x86 in __init__.py (#398)
- Enable compilation of FMI 3.0 FMUs in GUI (#396)

### Enhancements

- Use Plotly as default in plot_result()
- Add markers option to plot_result()
- Add parameter intermediate_update to instantiate_fmu()
- Build macOS binaries as universal 2

## v0.3.9 (2022-05-11)

### Enhancements
Expand Down
8 changes: 4 additions & 4 deletions fmpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
import _ctypes
from typing import Union, IO, List

__version__ = '0.3.9'
__version__ = '0.3.10'

# experimental
plot_library = 'matplotlib' # 'plotly'
# library to use in plot_result()
plot_library = 'plotly' # or 'matplotlib'


# determine the platform
Expand Down Expand Up @@ -57,7 +57,7 @@
architecture = 'x86_64'
else:
platform += '32'
architecture = 'i686'
architecture = 'x86'

platform_tuple = architecture + '-' + system

Expand Down
32 changes: 16 additions & 16 deletions fmpy/fmi3.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,6 @@
fmi3UnlockPreemptionCallback = CFUNCTYPE(None)


def intermediateUpdate(instanceEnvironment: fmi3InstanceEnvironment,
intermediateUpdateTime: fmi3Float64,
intermediateVariableSetRequested: fmi3Boolean,
intermediateVariableGetAllowed: fmi3Boolean,
intermediateStepFinished: fmi3Boolean,
canReturnEarly: fmi3Boolean,
earlyReturnRequested: POINTER(fmi3Boolean),
earlyReturnTime: POINTER(fmi3Float64)) -> None:

earlyReturnRequested.contents = fmi3False


def printLogMessage(instanceEnvironment: fmi3InstanceEnvironment,
status: fmi3Status,
category: fmi3String,
Expand Down Expand Up @@ -842,7 +830,7 @@ def deserializeFMUState(self, serializedState, state=None):

# Getting partial derivatives

def getDirectionalDerivative(self, unknowns: Sequence[int], knowns: Sequence[int], seed: Sequence[float], nSensitivity: int) -> List[float]:
def getDirectionalDerivative(self, unknowns: Sequence[int], knowns: Sequence[int], seed: Sequence[float], nSensitivity: int = None) -> List[float]:
""" Get the directional derivatives
Parameters:
Expand All @@ -858,14 +846,18 @@ def getDirectionalDerivative(self, unknowns: Sequence[int], knowns: Sequence[int
unknowns = (fmi3ValueReference * len(unknowns))(*unknowns)
knowns = (fmi3ValueReference * len(knowns))(*knowns)
seed = (fmi3Float64 * len(seed))(*seed)

if nSensitivity is None:
nSensitivity = len(unknowns)

sensitivity = (fmi3Float64 * nSensitivity)()

self.fmi3GetDirectionalDerivative(self.component, unknowns, len(unknowns), knowns, len(knowns), seed, len(seed),
sensitivity, len(sensitivity))

return list(sensitivity)

def getAdjointDerivative(self, unknowns: Sequence[int], knowns: Sequence[int], seed: Sequence[float], nSensitivity: int) -> List[float]:
def getAdjointDerivative(self, unknowns: Sequence[int], knowns: Sequence[int], seed: Sequence[float], nSensitivity: int = None) -> List[float]:
""" Get adjoint derivatives
Parameters:
Expand All @@ -881,6 +873,10 @@ def getAdjointDerivative(self, unknowns: Sequence[int], knowns: Sequence[int], s
unknowns = (fmi3ValueReference * len(unknowns))(*unknowns)
knowns = (fmi3ValueReference * len(knowns))(*knowns)
seed = (fmi3Float64 * len(seed))(*seed)

if nSensitivity is None:
nSensitivity = len(unknowns)

sensitivity = (fmi3Float64 * nSensitivity)()

self.fmi3GetAdjointDerivative(self.component, unknowns, len(unknowns), knowns, len(knowns), seed, len(seed),
Expand Down Expand Up @@ -957,11 +953,15 @@ def __init__(self, instanceName=None, **kwargs):

super(FMU3Slave, self).__init__(**kwargs)

def instantiate(self, visible=False, loggingOn=False, eventModeUsed=False, earlyReturnAllowed=False, logMessage=None):
def instantiate(self, visible=False, loggingOn=False, eventModeUsed=False, earlyReturnAllowed=False, logMessage=None, intermediateUpdate=None):

# save callbacks from GC
self.logMessage = fmi3LogMessageCallback(printLogMessage if logMessage is None else logMessage)
self.intermediateUpdate = fmi3IntermediateUpdateCallback(intermediateUpdate)

if intermediateUpdate is None:
self.intermediateUpdate = fmi3IntermediateUpdateCallback()
else:
self.intermediateUpdate = fmi3IntermediateUpdateCallback(intermediateUpdate)

resourcePath = os.path.join(self.unzipDirectory, 'resources') + os.path.sep

Expand Down
2 changes: 1 addition & 1 deletion fmpy/gui/MainWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ def load(self, filename):
# actions
self.ui.actionValidateFMU.setEnabled(True)

can_compile = md.fmiVersion == '2.0' and 'c-code' in platforms
can_compile = md.fmiVersion != '1.0' and 'c-code' in platforms

self.ui.actionCompileDarwinBinary.setEnabled(can_compile and fmpy.system == 'darwin')
self.ui.actionCompileLinuxBinary.setEnabled(can_compile and fmpy.system in ['linux', 'windows'])
Expand Down
12 changes: 7 additions & 5 deletions fmpy/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ def simulate_fmu(filename,
return result


def instantiate_fmu(unzipdir, model_description, fmi_type=None, visible=False, debug_logging=False, logger=None, fmi_call_logger=None, library_path=None, early_return_allowed=False, event_mode_used=False):
def instantiate_fmu(unzipdir, model_description, fmi_type=None, visible=False, debug_logging=False, logger=None, fmi_call_logger=None, library_path=None, early_return_allowed=False, event_mode_used=False, intermediate_update=None):
"""
Create an instance of fmpy.fmi1._FMU (see simulate_fmu() for documentation of the parameters).
"""
Expand All @@ -786,14 +786,15 @@ def instantiate_fmu(unzipdir, model_description, fmi_type=None, visible=False, d
is_fmi1 = model_description.fmiVersion == '1.0'
is_fmi2 = model_description.fmiVersion == '2.0'

if logger is not None:
if logger is not None and (is_fmi1 or is_fmi2):

if is_fmi1:
callbacks = fmi1CallbackFunctions()
callbacks.logger = fmi1CallbackLoggerTYPE(logger)
callbacks.allocateMemory = fmi1CallbackAllocateMemoryTYPE(calloc)
callbacks.freeMemory = fmi1CallbackFreeMemoryTYPE(free)
callbacks.stepFinished = None
elif is_fmi2:
else:
callbacks = fmi2CallbackFunctions()
callbacks.logger = fmi2CallbackLoggerTYPE(logger)
callbacks.allocateMemory = fmi2CallbackAllocateMemoryTYPE(calloc)
Expand All @@ -803,7 +804,7 @@ def instantiate_fmu(unzipdir, model_description, fmi_type=None, visible=False, d
from .logging import addLoggerProxy
addLoggerProxy(byref(callbacks))
except Exception as e:
print("Failed to add logger proxy function. %s" % e)
print(f"Failed to add logger proxy function. {e}")
else:
callbacks = None

Expand All @@ -820,7 +821,8 @@ def instantiate_fmu(unzipdir, model_description, fmi_type=None, visible=False, d
else:
fmu = fmi3.FMU3Slave(**fmu_args)
fmu.instantiate(visible=visible, loggingOn=debug_logging, eventModeUsed=event_mode_used,
earlyReturnAllowed=early_return_allowed, logMessage=logger)
earlyReturnAllowed=early_return_allowed, logMessage=logger,
intermediateUpdate=intermediate_update)

elif fmi_type in [None, 'ModelExchange'] and model_description.modelExchange is not None:

Expand Down
56 changes: 35 additions & 21 deletions fmpy/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ def validate_result(result, reference, stop_time=None):
return rel_out


def create_plotly_figure(result, names=None, events=False, time_unit=None):
def create_plotly_figure(result, names=None, events=False, time_unit=None, markers=False):

import plotly.graph_objects as go
from plotly.subplots import make_subplots
Expand Down Expand Up @@ -311,15 +311,21 @@ def create_plotly_figure(result, names=None, events=False, time_unit=None):
y = y * display_unit.factor + display_unit.offset
unit = display_unit.name

line = dict(color='#636efa', width=1)
args = dict(
x=time,
name=name,
line=dict(color='#636efa', width=1),
mode='lines+markers' if markers else None,
marker=dict(color='#636efa', size=5)
)

if y.dtype in [np.float32, np.float64]:
trace = go.Scatter(x=time, y=y, name=name, line=line)
trace = go.Scatter(y=y, **args)
elif y.dtype == bool:
trace = go.Scatter(x=time, y=y.astype(int), name=name, line=line, fill='tozeroy', fillcolor='rgba(0,0,255,0.1)', line_shape='hv')
trace = go.Scatter(y=y.astype(int), fill='tozeroy', fillcolor='rgba(0,0,255,0.1)', line_shape='hv', **args)
fig['layout'][f'yaxis{i + 1}'].update(tickvals=[0, 1], ticktext=['false', 'true'], range=[-0.1, 1.1], fixedrange=True)
else:
trace = go.Scatter(x=time, y=y, name=name, line=line, line_shape='hv')
trace = go.Scatter(y=y, line_shape='hv', **args)

fig.add_trace(trace, row=i + 1, col=1)

Expand All @@ -330,22 +336,19 @@ def create_plotly_figure(result, names=None, events=False, time_unit=None):
fig.add_vline(x=t_event, line={'color': '#fbe424', 'width': 1})

fig['layout']['height'] = 160 * len(names) + 30 * max(0, 5 - len(names))
fig['layout']['margin']['t'] = 30
fig['layout']['margin']['b'] = 0
fig['layout']['margin']['r'] = 30
fig['layout']['plot_bgcolor'] = 'rgba(0,0,0,0)'
fig['layout'][f'xaxis{len(names)}'].update(title=f'time [{time_unit}]')

axes_attrs = dict(showgrid=True, gridwidth=1, ticklen=0, gridcolor='LightGrey', linecolor='black', showline=True, zerolinewidth=1, zerolinecolor='LightGrey')
fig.update_xaxes(zeroline=True, **axes_attrs)
axes_attrs = dict(showgrid=True, gridwidth=1, ticklen=0, gridcolor='LightGrey', linecolor='black', showline=True,
zerolinewidth=1, zerolinecolor='LightGrey')
fig.update_xaxes(range=(time[0], time[-1]), **axes_attrs)
fig.update_yaxes(**axes_attrs)

fig.update_layout(showlegend=False)
fig.update_layout(showlegend=False, margin=dict(t=30, b=0, r=30), plot_bgcolor='rgba(0,0,0,0)')

return fig


def plot_result(result, reference=None, names=None, filename=None, window_title=None, events=False):
def plot_result(result, reference=None, names=None, filename=None, window_title=None, events=False, markers=False):
""" Plot a collection of time series.
Parameters:
Expand All @@ -355,12 +358,13 @@ def plot_result(result, reference=None, names=None, filename=None, window_title=
filename: when provided the plot is saved as `filename` instead of showing the figure
window_title: title for the figure window
events: draw vertical lines at events
markers: show markers
"""

from . import plot_library

if plot_library == 'plotly':
figure = create_plotly_figure(result, names=names, events=events)
figure = create_plotly_figure(result, names=names, events=events, markers=markers)
if filename is None:
figure.show()
else:
Expand Down Expand Up @@ -750,6 +754,8 @@ def compile_dll(model_description, sources_dir, compiler=None, target_platform=N
if compiler is None:
if target_platform in ['win32', 'win64', 'x86_64-windows']:
compiler = 'vc'
elif target_platform in ['darwin64', 'x86_64-darwin', 'aarch64-darwin']:
compiler = 'clang'
else:
compiler = 'gcc'

Expand Down Expand Up @@ -837,20 +843,28 @@ def compile_dll(model_description, sources_dir, compiler=None, target_platform=N
command = f'{cc} -c {compiler_options} -I. -I{include_dir} {definitions} {sources}'
command += f' && {cc} -static-libgcc -shared -o{target} *.o -lm'

elif target_platform in ['darwin64', 'x86_64-darwin']:
else:
raise Exception(f'The target platform "{target_platform}" is not supported for the gcc compiler.')

elif compiler == 'clang':

definitions = ' '.join(f' -D{d}' for d in preprocessor_definitions)

if target_platform in ['darwin64', 'x86_64-darwin']:

target = model_identifier + '.dylib'
target = f'{model_identifier}.dylib'

if compiler_options is None:
compiler_options = ''
compiler_options = '-arch x86_64 -arch arm64'

command = f'gcc -c {compiler_options} -I. -I{include_dir} {definitions} {sources}'
command += f' && gcc -shared -o{target} *.o -lm'
command = f'clang -c {compiler_options} -I. -I{include_dir} {definitions} {sources}'
command += f' && clang -shared -arch x86_64 -arch arm64 -o{target} *.o -lm'

else:
raise Exception("Unsupported target platform for selected compiler: '%s'" % compiler)
raise Exception(f'The target platform "{target_platform}" is not supported for the clang compiler.')

else:
raise Exception("Unsupported compiler: '%s'" % compiler)
raise Exception(f'The compiler "{compiler}" is not supported.')

print(sources_dir)
print(command)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
extras_require['complete'] = sorted(set(sum(extras_require.values(), [])))

setup(name='FMPy',
version='0.3.9',
version='0.3.10',
description="Simulate Functional Mock-up Units (FMUs) in Python",
long_description=long_description,
author="Torsten Sommer",
Expand Down

0 comments on commit b76dfc8

Please sign in to comment.