Skip to content

Commit

Permalink
Merge branch 'release/v0.1.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
t-sommer committed Dec 11, 2017
2 parents 7222571 + d532f0f commit c68651b
Show file tree
Hide file tree
Showing 12 changed files with 160 additions and 65 deletions.
51 changes: 46 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,55 @@
language: python

python:
- 2.7
- 3.6
matrix:
include:
- os: linux
env:
- PYTHON_VERSION=2.7
- MINICONDA=Miniconda2-latest-Linux-x86_64.sh

- os: linux
env:
- PYTHON_VERSION=3.6
- MINICONDA=Miniconda3-latest-Linux-x86_64.sh

- os: osx
language: generic
env:
- PYTHON_VERSION=2.7
- MINICONDA=Miniconda2-latest-MacOSX-x86_64.sh

- os: osx
language: generic
env:
- PYTHON_VERSION=3.6
- MINICONDA=Miniconda3-latest-MacOSX-x86_64.sh

install:
- pip install lxml requests scipy pathlib dask[complete]
# download and install miniconda
- wget https://repo.continuum.io/miniconda/$MINICONDA -O miniconda.sh
- bash miniconda.sh -b -p $HOME/miniconda
- export PATH="$HOME/miniconda/bin:$PATH"
- hash -r
- conda config --set always_yes yes --set changeps1 no
- conda update -q conda

# useful for debugging any issues with conda
- conda info -a

# create the conda environment
- conda create -q -n test-env python=$PYTHON_VERSION
- source activate test-env

# build the wheel
- python setup.py bdist_wheel --universal

# install the wheel and its dependencies
- |
for f in dist/FMPy-*.whl; do
pip install $f
done
script:
- pip install .
- cd tests
- python -m unittest discover
- cd ..
Expand Down
15 changes: 14 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## [0.1.1] - 2017-12-11

### Added
- dependency information in setup.py
- platform check for parameter variation example

### Fixed
- FMI call logging
- plot_result() now works with older matplotlib versions

### Changed
- timeout in cross-check removed

## [0.1.0] - 2017-11-24

### Added
Expand All @@ -8,7 +21,7 @@
- experimental [System Structure and Parameterization](https://www.modelica.org/projects#ssp) support
- max. step size parameter for CVode solver

## Fixed
### Fixed
- return values in completedIntegratorStep()

## [0.0.9] - 2017-10-13
Expand Down
9 changes: 7 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,16 @@ FMPy is a free Python library to simulate `Functional Mock-up Units (FMUs) <http
Installation
------------

To install the latest release from PyPI or update an existing installation type::
To install the latest release from `PyPI <https://pypi.python.org/pypi/fmpy/>`_ or update an existing installation::

python -m pip install --upgrade fmpy

or, to install the latest development version::
To install from `conda-forge <https://conda-forge.org/>`_ into an exsisting `conda <https://conda.io/>`_ environment::

conda config --add channels conda-forge
conda install fmpy

To install the latest development version::

python -m pip install --upgrade https://github.com/CATIA-Systems/FMPy/archive/develop.zip

Expand Down
13 changes: 11 additions & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,19 @@ install:
- conda config --set always_yes yes --set changeps1 no
- conda update -q conda
- conda info -a
- conda create -q -n test-env python=%PYTHON_VERSION% numpy lxml pathlib requests pywin32 dask
- conda create -q -n test-env python=%PYTHON_VERSION%
- activate test-env

# build the wheel
- python setup.py bdist_wheel --universal

# install the wheel and its dependencies
- for %%f in (dist\FMPy-*.whl) do pip install %%f

test_script:
- pip install .
- cd tests
- python -m unittest discover

artifacts:
# archive the generated wheel in the build report
- path: dist\*
2 changes: 1 addition & 1 deletion fmpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import zipfile
from tempfile import mkdtemp

__version__ = '0.1.0'
__version__ = '0.1.1'


# determine the platform
Expand Down
16 changes: 2 additions & 14 deletions fmpy/cross_check/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,25 +60,13 @@ def simulate(options):
else:
input = None

step_size = options['step_size']

# select solver based on step_size
if step_size > 0:
solver = 'Euler'
else:
solver = 'CVode'

solver = 'CVode'

# simulate the FMU
result = fmpy.simulate_fmu(filename=options['fmu_filename'],
validate=False,
solver=solver,
step_size=step_size,
step_size=options['step_size'],
stop_time=options['stop_time'],
input=input,
output=options['output_variable_names'],
timeout=5)
output=options['output_variable_names'])

return result

Expand Down
5 changes: 4 additions & 1 deletion fmpy/examples/parameter_variation.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import numpy as np
import fmpy
from fmpy.fmi2 import FMU2Slave
from fmpy import read_model_description
from fmpy import read_model_description, platform
from fmpy.util import download_test_file
import shutil

Expand Down Expand Up @@ -111,6 +111,9 @@ def simulate_fmu(args):

def run_experiment(show_plot=True):

if platform not in ['win32', 'win64']:
raise Exception("Rectifier.fmu is only available for Windows")

print("Parameter variation on %s:" % fmu_filename)
print(" VAC", v_ac)
print(" IDC", i_dc)
Expand Down
55 changes: 44 additions & 11 deletions fmpy/fmi1.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,46 @@


class fmi1CallbackFunctions(Structure):

_fields_ = [('logger', fmi1CallbackLoggerTYPE),
('allocateMemory', fmi1CallbackAllocateMemoryTYPE),
('freeMemory', fmi1CallbackFreeMemoryTYPE),
('stepFinished', fmi1StepFinishedTYPE)]

def __str__(self):
return 'fmi1CallbackFunctions(' \
'logger=%s, ' \
'allocateMemory=%s, ' \
'freeMemory=%s, ' \
'stepFinished=%s)' % (self.logger,
self.allocateMemory,
self.freeMemory,
self.stepFinished)


class fmi1EventInfo(Structure):

_fields_ = [('iterationConverged', fmi1Boolean),
('stateValueReferencesChanged', fmi1Boolean),
('stateValuesChanged', fmi1Boolean),
('terminateSimulation', fmi1Boolean),
('upcomingTimeEvent', fmi1Boolean),
('nextEventTime', fmi1Real)]

def __str__(self):
return 'fmi1EventInfo(' \
'iterationConverged=%s, ' \
'stateValueReferencesChanged=%s, ' \
'stateValuesChanged=%s, ' \
'terminateSimulation=%s, ' \
'upcomingTimeEvent=%s, ' \
'nextEventTime=%s)' % (self.iterationConverged,
self.stateValueReferencesChanged,
self.stateValuesChanged,
self.terminateSimulation,
self.upcomingTimeEvent,
self.nextEventTime)


def logger(component, instanceName, status, category, message):
if status == fmi1Warning:
Expand Down Expand Up @@ -115,25 +141,32 @@ def _print_fmi_args(self, fname, argnames, argtypes, args, restype, res):

l = []

for n, t, v in zip(argnames, argtypes, args):
for i, (n, t, v) in enumerate(zip(argnames, argtypes, args)):

a = n + '='

if t == c_void_p: # component pointer
if t == c_void_p:
# component pointer
a += hex(v)
elif t == POINTER(c_uint): # value references
elif t == POINTER(c_uint):
# value references
a += '[' + ', '.join(map(str, v)) + ']'
elif t == POINTER(c_double):
if hasattr(v, '__len__'): # double array
if hasattr(v, '__len__'):
# c_double_Array_N
a += '[' + ', '.join(map(str, v)) + ']'
elif v == self._px: # continuous states
a += '[' + ', '.join(map(str, self.x)) + ']'
elif v == self._pdx: # derivatives
a += '[' + ', '.join(map(str, self.dx)) + ']'
elif v == self._pz: # event indicators
a += '[' + ', '.join(map(str, self.z)) + ']'
else:
a += str(v.contents.value)
# double pointers are always flowed by the size of the array
arr = np.ctypeslib.as_array(v, (args[i+1],))
a += '[' + ', '.join(map(str, arr)) + ']'
elif hasattr(v, '_obj'):
# byref object
if hasattr(v._obj, 'value'):
# pointer (e.g. c_char_p)
a += str(v._obj.value)
else:
# struct
a += str(v._obj)
else:
a += str(v)

Expand Down
10 changes: 5 additions & 5 deletions fmpy/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ def simulate_fmu(filename,
fmi_type = 'CoSimulation' if modelDescription.coSimulation is not None else 'ModelExchange'

if fmi_type not in ['ModelExchange', 'CoSimulation']:
raise Exception('fmi_tpye must be one of "ModelExchange" or "CoSimulation"')
raise Exception('fmi_type must be one of "ModelExchange" or "CoSimulation"')

defaultExperiment = modelDescription.defaultExperiment

Expand Down Expand Up @@ -331,18 +331,18 @@ def simulate_fmu(filename,
# simulate_fmu the FMU
if fmi_type == 'ModelExchange':
fmu_args['modelIdentifier'] = modelDescription.modelExchange.modelIdentifier
result = simulateME(modelDescription, fmu_args, start_time, stop_time, solver, step_size, start_values, input, output, output_interval, timeout, fmi_logging)
result = simulateME(modelDescription, fmu_args, start_time, stop_time, solver, step_size, start_values, input, output, output_interval, timeout)
elif fmi_type == 'CoSimulation':
fmu_args['modelIdentifier'] = modelDescription.coSimulation.modelIdentifier
result = simulateCS(modelDescription, fmu_args, start_time, stop_time, start_values, input, output, output_interval, timeout, fmi_logging)
result = simulateCS(modelDescription, fmu_args, start_time, stop_time, start_values, input, output, output_interval, timeout)

# clean up
shutil.rmtree(unzipdir)

return result


def simulateME(modelDescription, fmu_kwargs, start_time, stop_time, solver_name, step_size, start_values, input_signals, output, output_interval, timeout, fmi_logging):
def simulateME(modelDescription, fmu_kwargs, start_time, stop_time, solver_name, step_size, start_values, input_signals, output, output_interval, timeout):

sim_start = current_time()

Expand Down Expand Up @@ -483,7 +483,7 @@ def set_time(t):
return recorder.result()


def simulateCS(modelDescription, fmu_kwargs, start_time, stop_time, start_values, input_signals, output, output_interval, timeout, fmi_logging):
def simulateCS(modelDescription, fmu_kwargs, start_time, stop_time, start_values, input_signals, output, output_interval, timeout):

sim_start = current_time()

Expand Down
36 changes: 16 additions & 20 deletions fmpy/ssp/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,40 @@
from fmpy import read_model_description, extract
from fmpy.fmi1 import FMU1Slave
from fmpy.fmi2 import FMU2Slave
from fmpy.ssp.ssd import System, read_ssd, get_connections, find_connectors, find_components, build_path
from fmpy.ssp.ssd import System, read_ssd, get_connections, find_connectors, find_components


def get_value(component, name):
""" Get a Real variable from a component """
""" Get a variable from a component """

# vr = component.vrs[name]
variable = component.variables[name]
vr = [variable.valueReference]

if variable.type == 'Real':
return component.fmu.getReal([variable.valueReference])[0]
return component.fmu.getReal(vr)[0]
elif variable.type in ['Integer', 'Enumeration']:
return component.fmu.getInteger([variable.valueReference])[0]
return component.fmu.getInteger(vr)[0]
elif variable.type == 'Boolean':
value = component.fmu.getBoolean([variable.valueReference])[0]
# return 0.0 if value == 0 else 1.0
value = component.fmu.getBoolean(vr)[0]
return value != 0
else:
raise Exception("Unsupported type: " + variable.type)
raise Exception("Unsupported type: %s" % variable.type)


def set_value(component, name, value):
""" Set a Real variable to a component """
""" Set a variable to a component """

variable = component.variables[name]
vr = [variable.valueReference]

if variable.type == 'Real':
component.fmu.setReal([variable.valueReference], [value])
component.fmu.setReal(vr, [value])
elif variable.type in ['Integer', 'Enumeration']:
component.fmu.setInteger([variable.valueReference], [int(value)])[0]
component.fmu.setInteger(vr, [int(value)])[0]
elif variable.type == 'Boolean':
component.fmu.setBoolean([variable.valueReference], [value != 0.0])
component.fmu.setBoolean(vr, [value != 0.0])
else:
raise Exception("Unsupported type: " + variable.type)
raise Exception("Unsupported type: %s" % variable.type)


def add_path(element, path=''):
Expand Down Expand Up @@ -77,6 +77,9 @@ def instantiate_fmu(component, ssp_unzipdir, start_time, parameters={}):
# read the model description
model_description = read_model_description(fmu_filename, validate=False)

if model_description.coSimulation is None:
raise Exception("%s does not support co-simulation." % component.source)

# collect the value references
component.variables = {}
for variable in model_description.modelVariables:
Expand Down Expand Up @@ -156,18 +159,11 @@ def simulate_ssp(ssp_filename, start_time=0.0, stop_time=None, step_size=None, p
# trace connections back to the actual start connector
for a, b in connections:

# if isinstance(b.parent, System):
# continue

while isinstance(a.parent, System) and a.parent.parent is not None:
a = connections_reversed[a]

new_connections.append((a, b))

# for a, b in new_connections:
# #print(type(a.parent), a.kind, '->', type(b.parent), b.kind)
# print(a.path, '->', b.path)

connections = new_connections

# extract the SSP
Expand Down
Loading

0 comments on commit c68651b

Please sign in to comment.