Skip to content

Commit

Permalink
Add getDirectionalDerivative()
Browse files Browse the repository at this point in the history
  • Loading branch information
t-sommer committed May 16, 2018
1 parent 2f21177 commit 0b62d01
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 0 deletions.
6 changes: 6 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## v0.2.4 (unreleased)

- `NEW` getDirectionalDerivative()


## v0.2.3 (2018-04-11)

- `NEW` Allow simulation of extracted FMUs and pre-loaded model descriptions
Expand All @@ -16,6 +21,7 @@
- `FIXED` Handling of time events
- `FIXED` Conversion of Boolean start values


## v0.2.2 (2018-03-13)

- `NEW` FMI 2.0 state serialization functions added
Expand Down
27 changes: 27 additions & 0 deletions fmpy/fmi2.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ def __init__(self, **kwargs):
[fmi2Component, POINTER(fmi2Byte), c_size_t, POINTER(fmi2FMUstate)],
fmi2Status)

# Getting partial derivatives
self._fmi2Function('fmi2GetDirectionalDerivative',
['component', 'vUnknown_ref', 'nUnknown', 'vKnown_ref', 'nKnown', 'dvKnown', 'dvUnknown'],
[fmi2Component, POINTER(fmi2ValueReference), c_size_t, POINTER(fmi2ValueReference), c_size_t, POINTER(fmi2Real), POINTER(fmi2Real)],
fmi2Status)

def _fmi2Function(self, fname, argnames, argtypes, restype):

if not hasattr(self.dll, fname):
Expand Down Expand Up @@ -335,6 +341,27 @@ def deSerializeFMUstate(self, serializedState, state):
buffer = create_string_buffer(serializedState)
self.fmi2DeSerializeFMUstate(self.component, buffer, len(buffer), byref(state))

def getDirectionalDerivative(self, vUnknown_ref, vKnown_ref, dvKnown):
""" Get the partial derivative
Parameters:
vUnknown_ref a list of value references of the unknowns
vKnown_ref a list of value references of the knowns
dvKnown a list of delta values (one per known)
Returns:
a list of the partial derivatives (one per unknown)
"""

vUnknown_ref = (fmi2ValueReference * len(vUnknown_ref))(*vUnknown_ref)
vKnown_ref = (fmi2ValueReference * len(vKnown_ref))(*vKnown_ref)
dvKnown = (fmi2Real * len(dvKnown))(*dvKnown)
dvUnknown = (fmi2Real * len(vUnknown_ref))()

self.fmi2GetDirectionalDerivative(self.component, vUnknown_ref, len(vUnknown_ref), vKnown_ref, len(vKnown_ref), dvKnown, dvUnknown)

return list(dvUnknown)


class FMU2Model(_FMU2):
""" Base class for FMI 2.0 model exchange FMUs """
Expand Down
63 changes: 63 additions & 0 deletions tests/test_get_directional_derivative.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import unittest
from shutil import rmtree
from unittest import skipIf

from fmpy import platform, read_model_description, extract
from fmpy.util import download_test_file
from fmpy.fmi2 import FMU2Slave


class GetDirectionalDerivativeTest(unittest.TestCase):

@skipIf(platform not in ['win32', 'win64'], "Current platform not supported by this FMU")
def test_get_directional_derivative(self):

fmu_filename = 'Rectifier.fmu'

download_test_file('2.0', 'CoSimulation', 'Dymola', '2017', 'Rectifier', fmu_filename)

model_description = read_model_description(filename=fmu_filename)

unzipdir = extract(fmu_filename)

fmu = FMU2Slave(guid=model_description.guid,
unzipDirectory=unzipdir,
modelIdentifier=model_description.coSimulation.modelIdentifier)

fmu.instantiate()
fmu.setupExperiment()
fmu.enterInitializationMode()

# get the partial derivative for an initial unknown
unknown = model_description.initialUnknowns[1]

self.assertEqual('iAC[1]', unknown.variable.name)

vrs_unknown = [unknown.variable.valueReference]
vrs_known = [v.valueReference for v in unknown.dependencies]
dv_known = [1.0] * len(unknown.dependencies)

partial_der = fmu.getDirectionalDerivative(vUnknown_ref=vrs_unknown, vKnown_ref=vrs_known, dvKnown=dv_known)

self.assertEqual([-2.0], partial_der)

fmu.exitInitializationMode()

# get the partial derivative for three output variables
unknowns = model_description.outputs[4:7]

self.assertEqual(['uAC[1]', 'uAC[2]', 'uAC[3]'], [u.variable.name for u in unknowns])

vrs_unknown = [u.variable.valueReference for u in unknowns]
vrs_known = [v.valueReference for v in unknowns[0].dependencies]
dv_known = [1.0] * len(vrs_known)

partial_der = fmu.getDirectionalDerivative(vUnknown_ref=vrs_unknown, vKnown_ref=vrs_known, dvKnown=dv_known)

self.assertAlmostEqual(-1500, partial_der[0])
self.assertAlmostEqual(0, partial_der[1])
self.assertAlmostEqual(1500, partial_der[2])

fmu.terminate()
fmu.freeInstance()
rmtree(unzipdir)

0 comments on commit 0b62d01

Please sign in to comment.