.. index:: OMSysIdent

OMSysIdent
==========

OMSysIdent is a module for the parameter estimation of behavioral models
(wrapped as FMUs) on top of the OMSimulator API.
It uses the Ceres solver (http://ceres-solver.org/) for the optimization task.

It is an optional module which can be disabled. Please check the build files
for your platform for the respective flags.

.. index:: OMSysIdent; Examples

Examples
########

There are examples in the testsuite below the subfolder `OMSysIdent` which use
the scripting API. In addition there are examples which directly use
the C API within the module's source code folder (`src/OMSysIdentLib`).

Below is a basic example from the testsuite (`HelloWorld_cs_Fit.lua`) which
uses the Lua scripting API. It determines the parameters for the following
"hello world" style Modelica model:

.. code-block:: Modelica

  model HelloWorld
    parameter Real a = -1;
    parameter Real x_start = 1;
    Real x(start=x_start, fixed=true);
  equation
    der(x) = a*x;
  end HelloWorld;

The goal is to estimate the value of the coefficent `a` and the initial value
`x_start` of the state variable `x`. Instead of real measurements, the script
simply uses simulation data generated from the `HelloWorld` examples as
measurement data. The array `data_time` contains the time instants at which a
sample is taken and the array `data_x` contains the value of `x` that
corresponds to the respective time instant.

The estimation parameters are defined by calls to function
`omsi_addParameter(..)` in which the name of the parameter and a first guess
for the parameter's value is stated.

.. code-block:: lua
  :caption: HelloWorld_cs_Fit.lua
  :name: HelloWorld_cs_Fit-lua

  oms_setTempDirectory("./HelloWorld_cs_Fit/")
  oms_newModel("HelloWorld_cs_Fit")
  oms_addSystem("HelloWorld_cs_Fit.root", oms_system_wc)

  -- add FMU
  oms_addSubModel("HelloWorld_cs_Fit.root.HelloWorld", "../FMUs/HelloWorld.fmu")

  -- create system identification model for model
  simodel = omsi_newSysIdentModel("HelloWorld_cs_Fit");

  -- Data generated from simulating HelloWorld.mo for 1.0s with Euler and 0.1s step size
  kNumSeries = 1;
  kNumObservations = 11;
  data_time = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1};
  inputvars = {};
  measurementvars = {"HelloWorld_cs_Fit.root.HelloWorld.x"};
  data_x = {1, 0.9, 0.8100000000000001, 0.7290000000000001, 0.6561, 0.5904900000000001, 0.5314410000000001, 0.4782969000000001, 0.43046721, 0.387420489, 0.3486784401};

  omsi_initialize(simodel, kNumSeries, data_time, inputvars, measurementvars)
  -- omsi_describe(simodel)

  omsi_addParameter(simodel, "HelloWorld_cs_Fit.root.HelloWorld.x_start", 0.5);
  omsi_addParameter(simodel, "HelloWorld_cs_Fit.root.HelloWorld.a", -0.5);
  omsi_addMeasurement(simodel, 0, "HelloWorld_cs_Fit.root.HelloWorld.x", data_x);
  -- omsi_describe(simodel)

  omsi_setOptions_max_num_iterations(simodel, 25)
  omsi_solve(simodel, "BriefReport")

  status, simodelstate = omsi_getState(simodel);
  -- print(status, simodelstate)

  status, startvalue1, estimatedvalue1 = omsi_getParameter(simodel, "HelloWorld_cs_Fit.root.HelloWorld.a")
  status, startvalue2, estimatedvalue2 = omsi_getParameter(simodel, "HelloWorld_cs_Fit.root.HelloWorld.x_start")
  -- print("HelloWorld.a startvalue=" .. startvalue1 .. ", estimatedvalue=" .. estimatedvalue1)
  -- print("HelloWorld.x_start startvalue=" .. startvalue2 .. ", estimatedvalue=" .. estimatedvalue2)
  is_OK1 = estimatedvalue1 > -1.1 and estimatedvalue1 < -0.9
  is_OK2 = estimatedvalue2 > 0.9 and estimatedvalue2 < 1.1
  print("HelloWorld.a estimation is OK: " .. tostring(is_OK1))
  print("HelloWorld.x_start estimation is OK: " .. tostring(is_OK2))

  omsi_freeSysIdentModel(simodel)

  oms_terminate("HelloWorld_cs_Fit")
  oms_delete("HelloWorld_cs_Fit")

Running the script generates the following console output:

::

  iter      cost      cost_change  |gradient|   |step|    tr_ratio  tr_radius  ls_iter  iter_time  total_time
   0  4.034320e-01    0.00e+00    2.19e+00   0.00e+00   0.00e+00  1.00e+04        0    2.35e-02    2.35e-02
   1  3.821520e-02    3.65e-01    4.11e-01   9.87e-01   9.06e-01  2.15e+04        1    2.90e-02    5.25e-02
   2  6.837776e-04    3.75e-02    5.19e-02   3.58e-01   9.83e-01  6.46e+04        1    2.77e-02    8.02e-02
   3  1.354499e-07    6.84e-04    6.08e-04   4.58e-02   1.00e+00  1.94e+05        1    2.96e-02    1.10e-01
   4  5.854620e-15    1.35e-07    1.09e-07   7.22e-04   1.00e+00  5.82e+05        1    3.08e-02    1.41e-01
   5  1.160287e-25    5.85e-15    2.26e-13   1.59e-07   1.00e+00  1.74e+06        1    2.86e-02    1.69e-01
  Ceres Solver Report: Iterations: 6, Initial cost: 4.034320e-01, Final cost: 1.160287e-25, Termination: CONVERGENCE

  =====================================
  Total duration for parameter estimation: 169msec.
  Result of parameter estimation (check 'Termination' status above whether solver converged):

  HelloWorld_cs_Fit.HelloWorld:a(start=-0.5, *estimate*=-1.04807)
  HelloWorld_cs_Fit.HelloWorld:x_start(start=0.5, *estimate*=1)

  =====================================
  0	convergence
  HelloWorld.a startvalue=-0.5, estimatedvalue=-1.0480741793778
  HelloWorld.x_start startvalue=0.5, estimatedvalue=0.99999999999972
  HelloWorld.a estimation is OK: true
  HelloWorld.x_start estimation is OK: true
  info:    Logging information has been saved to "HelloWorld_cs_Fit.log"

.. index:: OMSysIdent; Scripting Commands

Lua Scripting Commands
######################

.. include:: OMSysIdentLua.inc
