Source code for jmodelica.algorithm_drivers
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2010 Modelon AB
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Module for optimization, simulation and initialization algorithms to be used
together with jmodelica.jmi.JMUModel.optimize, jmodelica.jmi.JMUModel.simulate,
jmodelica.fmi.FMUModel.simulate and jmodelica.jmi.JMUModel.initialize
respectively.
"""
#from abc import ABCMeta, abstractmethod
import logging
import numpy as N
import jmodelica
from jmodelica.io import ResultDymolaTextual
from jmodelica.optimization import ipopt
from jmodelica.initialization.ipopt import NLPInitialization
from jmodelica.initialization.ipopt import InitializationOptimizer
from jmodelica.xmlparser import XMLException
try:
from jmodelica.simulation.assimulo_interface import JMIDAE, JMIODE, FMIODE
from jmodelica.simulation.assimulo_interface import JMIDAESens
from jmodelica.simulation.assimulo_interface import write_data
from jmodelica.core import TrajectoryLinearInterpolation
from assimulo.implicit_ode import *
from assimulo.explicit_ode import *
from assimulo import implicit_ode as impl_ode
from assimulo import explicit_ode as expl_ode
from assimulo.kinsol import KINSOL
from jmodelica.initialization.assimulo_interface import JMUAlgebraic
from jmodelica.initialization.assimulo_interface import JMUAlgebraic_Exception
from jmodelica.initialization.assimulo_interface import write_resdata
assimulo_present = True
except:
logging.warning(
'Could not load Assimulo module. Check jmodelica.check_packages()')
assimulo_present = False
try:
ipopt_present = jmodelica.environ['IPOPT_HOME']
except:
ipopt_present = False
try:
import casadi
from jmodelica.optimization.casadi_collocation import *
from jmodelica.optimization.polynomial import *
casadi_present = True
except:
casadi_present = False
default_int = int
int = N.int32
N.int = N.int32
[docs]class AlgorithmBase(object):
"""
Abstract class which all algorithms that are to be used with
jmodelica.jmi.JMUModel.optimize, jmodelica.jmi.JMUModel.simulate,
jmodelica.fmi.FMUModel.simulate or jmodelica.jmi.JMUModel.initialize must
implement.
"""
# __metaclass__=ABCMeta
# @abstractmethod
def __init__(self, model, alg_args): pass
# @abstractmethod
[docs] def solve(self): pass
# @abstractmethod
[docs] def get_result(self): pass
@classmethod
[docs] def get_default_options(self): pass
[docs]class ResultBase(object):
"""
Base class for an algorithm result. All algorithms used in any of the
high-level functions should return an object which extends this class.
"""
def __init__(self, model=None, result_file_name=None, solver=None,
result_data=None, options=None):
"""
Create a result object containing the model used in the algorithm, the
name of the result file, the solver used in the algorithm, the result
data object and the object (dict) holding the options used in the
algorithm run.
Parameters::
model --
The jmi.JMUModel object for the model used in the algorithm.
result_file_name --
Name of the file containing the algorithm result created on the
file system.
solver --
The solver object used in the algorithm.
result_data --
The result data object created when running the algorithm. Holds
the whole result data matrix.
options --
The options object with the options that the algorithm was run
with.
"""
self._model = model
self._result_file_name = result_file_name
self._solver = solver
self._result_data = result_data
self._options = options
def _get_model(self):
if self._model != None:
return self._model
raise Exception("model has not been set")
def _set_model(self, model):
self._model = model
model = property(fget=_get_model, fset=_set_model, doc =
"""
Property for accessing the model that was used in the algorithm.
""")
def _get_result_file(self):
if self._result_file_name != None:
return self._result_file_name
raise Exception("result file name has not been set")
def _set_result_file(self, file_name):
self._result_file_name = result_file_name
result_file = property(fget=_get_result_file, fset=_set_result_file, doc =
"""
Property for accessing the name of the result file created in the algorithm.
""")
def _get_solver(self):
if self._solver != None:
return self._solver
raise Exception("solver has not been set")
def _set_solver(self, solver):
self._solver = solver
solver = property(fget=_get_solver, fset=_set_solver, doc =
"""
Property for accessing the solver that was used in the algorithm.
""")
def _get_result_data(self):
if self._result_data != None:
return self._result_data
raise Exception("result data has not been set")
def _set_result_data(self, result_data):
self._result_data = result_data
result_data = property(fget=_get_result_data, fset=_set_result_data, doc =
"""
Property for accessing the result data matrix that was created in the
algorithm.
""")
def _get_options(self):
if self._options != None:
return self._options
raise Exception("options has not been set")
def _set_options(self, options):
self._options = options
options = property(fget=_get_options, fset=_set_options, doc =
"""
Property for accessing he options object holding the options used in the
algorithm.
""")
[docs]class JMResultBase(ResultBase):
def __getitem__(self, key):
val = self.result_data.get_variable_data(key)
if self.is_variable(key):
return val.x
else:
#When there is a sensitivity variable (dx/dp) in the result
#the variable does not exists in the XML file, so cache the
#error and set variability to 0. If the variable does not
#exists in the result file, an error is raised prior to this.
try:
variability = self.model.get_variability(key)
except XMLException:
variability = 0
if variability == 1 or variability == 2:
#Variable is a parameter or constant
return val.x[0]
else:
time = self.result_data.get_variable_data('time')
return N.array([val.x[0]]*N.size(time.t))
#return self.result_data.get_variable_data(key)
[docs] def is_variable(self, name):
"""
Returns True if the given name corresponds to a time-varying variable.
Parameters::
name --
Name of the variable/parameter/constant.
Returns::
True if the variable is time-varying.
"""
return self.result_data.is_variable(name)
[docs] def is_negated(self, name):
return self.result_data.is_negated(name)
def _get_data_matrix(self):
return self.result_data.get_data_matrix()
data_matrix = property(fget=_get_data_matrix, doc =
"""
Property for accessing the result matrix.
""")
[docs] def get_column(self, name):
"""
Returns the column number in the data matrix where the values of the
variable are stored.
Parameters::
name --
Name of the variable/parameter/constant.
Returns::
The column number.
"""
return self.result_data.get_column(name)
[docs]class OptionBase(dict):
"""
Base class for an algorithm option class.
All algorithm option classes should extend this class.
This class extends the dict class overriding __init__, __setitem__, update
and setdefault methods with the purpose of offering a key check for the
extending classes.
The extending class can define a set of keys and default values by
overriding __init__ or when instantiating the extended class and thereby not
allow any other keys to be added to the dict.
* Example overriding __init__:
class MyOptionsClass(OptionBase):
def __init__(self, *args, **kw):
mydefaults = {'def1':1, 'def2':2}
super(MyOptionsClass,self).__init__(mydefaults)
self.update(*args, **kw)
>> opts = MyOptionsClass()
>> opts['def1'] = 3 // ok
>> opts.update({'def2':4}) // ok
>> opts['def3']= 5 // not ok
* Example setting defaults in constructor:
class MyOptionsClass(OptionBase):pass
>> opts = MyOptionsClass(def1=1, def2=2)
>> opts['def1'] = 3 // ok
>> opts.update({'def2':4}) // ok
>> opts['def3']= 5 // not ok
>> opts2 = MyOptionsClass() // this class has no restrictions on keys
>> opts2['def5'] = 'hello' //ok
"""
def __init__(self, *args, **kw):
# create dict
super(OptionBase,self).__init__(*args, **kw)
# save keys - these are now the set of allowed keys
self._keys = super(OptionBase,self).keys()
def __setitem__(self, key, value):
if self._keys:
if not key in self._keys:
raise UnrecognizedOptionError(
"The key: %s, is not a valid algorithm option" %str(key))
super(OptionBase,self).__setitem__(key, value)
[docs] def update(self, *args, **kw):
if args:
if len(args) > 1:
raise TypeError(
"update expected at most 1 arguments, got %d" % len(args))
other = dict(args[0])
for key in other:
self[key] = other[key]
for key in kw:
self[key] = kw[key]
[docs] def setdefault(self, key, value=None):
if key not in self:
self[key] = value
return self[key]
def _update_keep_dict_defaults(self, *args, **kw):
"""
Go through args/kw and for each value in a key-value-set that is a dict
- update the current dict with the new dict (don't overwrite).
"""
if args:
if len(args) > 1:
raise TypeError(
"update expected at most 1 arguments, got %d" % len(args))
other = dict(args[0])
for key in other:
if not key in self._keys:
raise UnrecognizedOptionError(
"The key: %s, is not a valid algorithm option" %str(key))
if isinstance(self[key], dict):
self[key].update(other[key])
else:
self[key] = other[key]
for key in kw:
if not key in self._keys:
raise UnrecognizedOptionError(
"The key: %s, is not a valid algorithm option" %str(key))
if isinstance(self[key], dict):
self[key].update(kw[key])
else:
self[key] = kw[key]
[docs]class IpoptInitResult(JMResultBase):
pass
[docs]class IpoptInitializationAlgOptions(OptionBase):
"""
Options for the IPOPT-based initialization algorithm.
Initialization algorithm options::
stat --
Solve a static optimization problem.
Default: False
result_file_name --
Specifies the name of the file where the optimization result is
written. Setting this option to an empty string results in a default
file name that is based on the name of the optimization class.
Default: Empty string
result_format --
Specifies in which format to write the result. Currently only
textual mode is supported.
Default: 'txt'
write_scaled_result --
Set this parameter to True to write the result to file without
taking scaling into account. If the value of scaled is False, then
the variable scaling factors of the model are used to reproduced the
unscaled variable values.
Default: False
Options are set by using the syntax for dictionaries::
>>> opts = my_model.initialize_options()
>>> opts['stat'] = True
In addition, IPOPT options can be provided in the option
IPOPT_options. For a complete list of IPOPT options, please
consult the IPOPT documentation available at
http://www.coin-or.org/Ipopt/documentation/).
Some commonly used IPOPT options are provided by default::
max_iter --
Maximum number of iterations.
Default: 3000
derivative_test --
Check the correctness of the NLP derivatives. Valid values are
'none', 'first-order', 'second-order', 'only-second-order'.
Default: 'none'
IPOPT options are set using the syntax for dictionaries::
>>> opts['IPOPT_options']['max_iter'] = 200
"""
def __init__(self, *args, **kw):
_defaults= {
'stat':False,
'result_file_name':'',
'result_format':'txt',
'write_scaled_result':False,
'IPOPT_options':{'max_iter':3000,
'derivative_test':'none'}
}
super(IpoptInitializationAlgOptions,self).__init__(_defaults)
# for those key-value-sets where the value is a dict, don't
# overwrite the whole dict but instead update the default dict
# with the new values
self._update_keep_dict_defaults(*args, **kw)
[docs]class IpoptInitializationAlg(AlgorithmBase):
"""
Initialization of a model using Ipopt.
"""
def __init__(self, model, options):
"""
Create an initialization algorithm using IpoptInitialization.
Parameters::
model --
The jmi.JMUModel object representation of the model.
options --
The options that should be used in the algorithm. For details on
the options, see:
* model.initialize_options('IpoptInitializationAlgOptions')
or look at the docstring with help:
* help(jmodelica.algorithm_drivers.IpoptInitializationAlgOptions)
Valid values are:
- A dict that overrides some or all of the default values
provided by IpoptInitializationAlgOptions. An empty dict will
thus give all options with default values.
- IpoptInitializationAlgOptions object.
"""
self.model = model
# handle options argument
if isinstance(options, dict) and not \
isinstance(options, IpoptInitializationAlgOptions):
# user has passed dict with options or empty dict = default
self.options = IpoptInitializationAlgOptions(options)
elif isinstance(options, IpoptInitializationAlgOptions):
# user has passed IpoptInitializationAlgOptions instance
self.options = options
else:
raise InvalidAlgorithmOptionException(options)
# set options
self._set_options()
if not ipopt_present:
raise Exception(
'Could not find IPOPT. Check jmodelica.check_packages()')
self.nlp = NLPInitialization(model,self.stat)
self.nlp_ipopt = InitializationOptimizer(self.nlp)
# set solver options
self._set_solver_options()
def _set_options(self):
"""
Helper function that sets options for the IpoptInitialization algorithm.
"""
self.stat=self.options['stat']
self.result_args = dict(
file_name=self.options['result_file_name'],
format=self.options['result_format'],
write_scaled_result=self.options['write_scaled_result'])
# solver options
self.solver_options = self.options['IPOPT_options']
def _set_solver_options(self):
"""
Helper function that sets options for the solver.
"""
for k, v in self.solver_options.iteritems():
print k
print v
if isinstance(v, default_int):
self.nlp_ipopt.init_opt_ipopt_set_int_option(k, v)
elif isinstance(v, float):
self.nlp_ipopt.init_opt_ipopt_set_num_option(k, v)
elif isinstance(v, basestring):
self.nlp_ipopt.init_opt_ipopt_set_string_option(k, v)
[docs] def solve(self):
"""
Solve the initialization problem using ipopt solver.
"""
self.nlp_ipopt.init_opt_ipopt_solve()
[docs] def get_result(self):
"""
Write result to file, load result data and create an IpoptInitResult
object.
Returns::
The IpoptInitResult object.
"""
self.nlp.export_result_dymola(**self.result_args)
# result file name
resultfile = self.result_args['file_name']
if not resultfile:
resultfile=self.model.get_name()+'_result.txt'
# load result file
res = ResultDymolaTextual(resultfile)
# create and return result object
return IpoptInitResult(self.model, resultfile, self.nlp_ipopt,
res, self.options)
@classmethod
[docs] def get_default_options(cls):
"""
Get an instance of the options class for the IpoptInitializationAlg
algorithm, prefilled with default values. (Class method.)
"""
return IpoptInitializationAlgOptions()
[docs]class AssimuloSimResult(JMResultBase):
pass
[docs]class AssimuloFMIAlgOptions(OptionBase):
"""
Options for the solving the FMU using the Assimulo simulation package.
Currently, the only solver in the Assimulo package that fully supports
simulation of FMUs is the solver CVode.
Assimulo options::
solver --
Specifies the simulation algorithm that is to be used. Currently the
only supported solver is 'CVode'.
Default: 'CVode'
ncp --
Number of communication points. If ncp is zero, the solver will
return the internal steps taken.
Default: '0'
initialize --
If set to True, the initializing algorithm defined in the FMU model
is invoked, otherwise it is assumed the user have manually invoked
model.initialize()
Default is True.
write_scaled_result --
Set this parameter to True to write the result to file without
taking scaling into account. If the value of scaled is False,
then the variable scaling factors of the model are used to
reproduced the unscaled variable values.
Default: False
result_file_name --
Specifies the name of the file where the simulation result is
written. Setting this option to an empty string results in a default
file name that is based on the name of the model class.
Default: Empty string
The different solvers provided by the Assimulo simulation package provides
different options. These options are given in dictionaries with names
consisting of the solver name concatenated by the string '_option'. The most
common solver options are documented below, for a complete list of options
see, http://www.jmodelica.org/assimulo
Options for CVode::
rtol --
The relative tolerance. The relative tolerance are retrieved from
the 'default experiment' section in the XML-file and if not
found are set to 1.0e-4
Default: 1.0e-4
atol --
The absolute tolerance.
Default: rtol*0.01*(nominal values of the continuous states)
discr --
The discretization method. Can be either 'BDF' or 'Adams'
Default: 'BDF'
iter --
The iteration method. Can be either 'Newton' or 'FixedPoint'
Default: 'Newton'
"""
def __init__(self, *args, **kw):
_defaults= {
'solver': 'CVode',
'ncp':0,
'initialize':True,
'write_scaled_result':False,
'result_file_name':'',
'CVode_options':{'discr':'BDF','iter':'Newton'}
}
super(AssimuloFMIAlgOptions,self).__init__(_defaults)
# for those key-value-sets where the value is a dict, don't
# overwrite the whole dict but instead update the default dict
# with the new values
self._update_keep_dict_defaults(*args, **kw)
[docs]class AssimuloFMIAlg(AlgorithmBase):
"""
Simulation algortihm for FMUs using the Assimulo package.
"""
def __init__(self,
start_time,
final_time,
input,
model,
options):
"""
Create a simulation algorithm using Assimulo.
Parameters::
model --
fmi.FMUModel object representation of the model.
options --
The options that should be used in the algorithm. For details on
the options, see:
* model.simulate_options('AssimuloFMIAlgOptions')
or look at the docstring with help:
* help(jmodelica.algorithm_drivers.AssimuloFMIAlgOptions)
Valid values are:
- A dict that overrides some or all of the default values
provided by AssimuloFMIAlgOptions. An empty dict will thus
give all options with default values.
- AssimuloFMIAlgOptions object.
"""
self.model = model
if not assimulo_present:
raise Exception(
'Could not find Assimulo package. Check jmodelica.check_packages()')
# set start time, final time and input trajectory
self.start_time = start_time
self.final_time = final_time
self.input = input
# handle options argument
if isinstance(options, dict) and not \
isinstance(options, AssimuloFMIAlgOptions):
# user has passed dict with options or empty dict = default
self.options = AssimuloFMIAlgOptions(options)
elif isinstance(options, AssimuloFMIAlgOptions):
# user has passed AssimuloFMIAlgOptions instance
self.options = options
else:
raise InvalidAlgorithmOptionException(options)
# set options
self._set_options()
input_traj = None
if self.input:
input_traj=(self.input[0],
TrajectoryLinearInterpolation(self.input[1][:,0],
self.input[1][:,1:]))
#Sets the inputs, if any
self.model.set(input_traj[0], input_traj[1].eval(self.start_time)[0,:])
# Initialize?
if self.options['initialize']:
self.model.initialize(relativeTolerance=self.solver_options['rtol'])
if not self.input:
self.probl = FMIODE(self.model, result_file_name=self.result_file_name)
else:
self.probl = FMIODE(
self.model, input_traj, result_file_name=self.result_file_name)
# instantiate solver and set options
self.simulator = self.solver(self.probl, t0=self.start_time)
self._set_solver_options()
def _set_options(self):
"""
Helper function that sets options for AssimuloFMI algorithm.
"""
# no of communication points
self.ncp = self.options['ncp']
self.write_scaled_result = self.options['write_scaled_result']
# result file name
if self.options['result_file_name'] == '':
self.result_file_name = self.model.get_name()+'_result.txt'
else:
self.result_file_name = self.options['result_file_name']
# solver
solver = self.options['solver']
if hasattr(expl_ode, solver):
self.solver = getattr(expl_ode, solver)
else:
raise InvalidAlgorithmOptionException(
"The solver: "+solver+ " is unknown.")
# solver options
self.solver_options = self.options[solver+'_options']
#Check relative tolerance
#If the tolerances are not set specifically, they are set
#according to the 'DefaultExperiment' from the XML file.
try:
self.solver_options['rtol']
except KeyError:
rtol, atol = self.model.get_tolerances()
self.solver_options['rtol'] = rtol
#Check absolute tolerance
try:
self.solver_options['atol']
except KeyError:
rtol, atol = self.model.get_tolerances()
fnbr, gnbr = self.model.get_ode_sizes()
if fnbr == 0:
self.solver_options['atol'] = 0.01*rtol
else:
self.solver_options['atol'] = atol
def _set_solver_options(self):
"""
Helper function that sets options for the solver.
"""
solver_options = self.solver_options.copy()
#loop solver_args and set properties of solver
for k, v in solver_options.iteritems():
try:
getattr(self.simulator,k)
except AttributeError:
try:
getattr(self.probl,k)
except AttributeError:
raise InvalidSolverArgumentException(v)
setattr(self.probl, k, v)
continue
setattr(self.simulator, k, v)
[docs] def solve(self):
"""
Runs the simulation.
"""
self.simulator.simulate(self.final_time, self.ncp)
[docs] def get_result(self):
"""
Write result to file, load result data and create an AssimuloSimResult
object.
Returns::
The AssimuloSimResult object.
"""
if not self.probl.write_cont:
write_data(self.simulator,self.write_scaled_result, self.result_file_name)
# load result file
res = ResultDymolaTextual(self.result_file_name)
# create and return result object
return AssimuloSimResult(self.model, self.result_file_name, self.simulator,
res, self.options)
@classmethod
[docs] def get_default_options(cls):
"""
Get an instance of the options class for the AssimuloFMIAlg algorithm,
prefilled with default values. (Class method.)
"""
return AssimuloFMIAlgOptions()
[docs]class AssimuloAlgOptions(OptionBase):
"""
Options for simulation of a JMU model using the Assimulo simulation package.
The Assimulo package contain both explicit solvers (CVode) for ODEs and
implicit solvers (IDA) for DAEs. The ODE solvers require that the problem
is written on the form, ydot = f(t,y).
Assimulo options::
solver --
Specifies the simulation algorithm that is to be used.
Default 'IDA'
ncp --
Number of communication points. If ncp is zero, the solver will
return the internal steps taken.
Default '0'
initialize --
If set to True, an algorithm for initializing the differential
equation is invoked, otherwise the differential equation is assumed
to have consistent initial conditions.
Default is True.
write_scaled_result --
Set this parameter to True to write the result to file without
taking scaling into account. If the value of scaled is False, then
the variable scaling factors of the model are used to reproduced the
unscaled variable values.
Default: False
result_file_name --
Specifies the name of the file where the simulation result is
written. Setting this option to an empty string results in a default
file name that is based on the name of the model class.
Default: Empty string
The different solvers provided by the Assimulo simulation package provides
different options. These options are given in dictionaries with names
consisting of the solver name concatenated by the string '_option'. The most
common solver options are documented below, for a complete list of options
see, http://www.jmodelica.org/assimulo
Options for IDA::
rtol --
The relative tolerance.
Default: 1.0e-6
atol --
The absolute tolerance.
Default: 1.0e-6
maxord --
The maximum order of the solver. Can range between 1 to 5. Note,
when simulating sensitivities the maximum order is limited to 4.
This is a temporary restriction.
Default: 5
sensitivity --
If set to True, sensitivities for the states with respect to
parameters set to free in the model will be calculated.
Default: False
write_cont --
Continuous writing of the result file instead. Currently only
supported when "sensitivity" is set to True.
Default: False
Options for CVode::
rtol --
The relative tolerance.
Default: 1.0e-6
atol --
The absolute tolerance.
Default: 1.0e-6
discr --
The discretization method. Can be either 'BDF' or 'Adams'.
Default: 'BDF'
iter --
The iteration method. Can be either 'Newton' or 'FixedPoint'.
Default: 'Newton'
"""
def __init__(self, *args, **kw):
_defaults= {
'solver': 'IDA',
'ncp':0,
'initialize':True,
'write_scaled_result':False,
'result_file_name':'',
'IDA_options':{'atol':1.0e-6,'rtol':1.0e-6,
'maxord':5,'sensitivity':False,
'write_cont':False},
'CVode_options':{'discr':'BDF','iter':'Newton',
'atol':1.0e-6,'rtol':1.0e-6}
}
# create options with default values
super(AssimuloAlgOptions,self).__init__(_defaults)
# for those key-value-sets where the value is a dict, don't
# overwrite the whole dict but instead update the default dict
# with the new values
self._update_keep_dict_defaults(*args, **kw)
[docs]class AssimuloAlg(AlgorithmBase):
"""
Simulation algorithm using the Assimulo package.
"""
def __init__(self,
start_time,
final_time,
input,
model,
options):
"""
Create a simulation algorithm using Assimulo.
Parameters::
model --
jmi.Model object representation of the model
options --
The options that should be used in the algorithm. For details on
the options, see:
* model.simulate_options('AssimuloAlgOptions')
or look at the docstring with help:
* help(jmodelica.algorithm_drivers.AssimuloAlgOptions)
Valid values are:
- A dict which gives AssimuloAlgOptions with default values on
all options except the ones listed in the dict. Empty dict
will thus give all options with default values.
- AssimuloAlgOptions object.
"""
self.model = model
#Internal values
self.sensitivity = False
if not assimulo_present:
raise Exception(
'Could not find Assimulo package. Check jmodelica.check_packages()')
# set start time, final time and input trajectory
self.start_time = start_time
self.final_time = final_time
self.input = input
# handle options argument
if isinstance(options, dict) and not \
isinstance(options, AssimuloAlgOptions):
# user has passed dict with options or empty dict = default
self.options = AssimuloAlgOptions(options)
elif isinstance(options, AssimuloAlgOptions):
# user has passed AssimuloAlgOptions instance
self.options = options
else:
raise InvalidAlgorithmOptionException(options)
# set options
self._set_options()
input_traj = None
if self.input:
input_traj=(self.input[0],
TrajectoryLinearInterpolation(self.input[1][:,0],
self.input[1][:,1:]))
#Sets the inputs, if any
self.model.set(input_traj[0], input_traj[1].eval(self.start_time)[0,:])
if issubclass(self.solver, Implicit_ODE):
if not self.input:
if not self.sensitivity:
self.probl = JMIDAE(model,result_file_name=self.result_file_name)
else:
self.probl = JMIDAESens(model,result_file_name=self.result_file_name)
else:
if not self.sensitivity:
self.probl = JMIDAE(model,(self.input[0],
TrajectoryLinearInterpolation(self.input[1][:,0], \
self.input[1][:,1:])), \
self.result_file_name)
else:
self.probl = JMIDAESens(model,(self.input[0],
TrajectoryLinearInterpolation(self.input[1][:,0], \
self.input[1][:,1:])), \
self.result_file_name)
else:
if not self.input:
self.probl = JMIODE(model,result_file_name=self.result_file_name)
else:
self.probl = JMIODE(model,(self.input[0],
TrajectoryLinearInterpolation(self.input[1][:,0], \
self.input[1][:,1:])), \
self.result_file_name)
# instantiate solver and set options
self.simulator = self.solver(self.probl, t0=self.start_time)
self._set_solver_options()
def _set_options(self):
"""
Helper function that sets options for Assimulo algorithm.
"""
# no of communication points
self.ncp = self.options['ncp']
# solver
solver = self.options['solver']
if hasattr(impl_ode, solver):
self.solver = getattr(impl_ode, solver)
elif hasattr(expl_ode, solver):
self.solver = getattr(expl_ode, solver)
else:
raise InvalidAlgorithmOptionException(
"The solver: "+solver+ " is unknown.")
# do initialize?
self.initialize = self.options['initialize']
# write scaled result?
self.write_scaled_result = self.options['write_scaled_result']
# result file name
if self.options['result_file_name'] == '':
self.result_file_name = self.model.get_name()+'_result.txt'
else:
self.result_file_name = self.options['result_file_name']
# solver options
self.solver_options = self.options[solver+'_options']
# sensitivity
self.sensitivity = self.solver_options.get('sensitivity',False)
#self.solver_options.pop('sensitivity',False)
# store cont is currently crucial when solving sensitivity problems
if self.sensitivity:
try:
self.solver_options['store_cont']
except KeyError:
self.solver_options['store_cont'] = True
if self.sensitivity and self.solver_options['maxord']==5:
logging.warning("Maximum order when using IDA for simulating "
"sensitivities is currently limited to 4.")
self.solver_options['maxord']=4
def _set_solver_options(self):
"""
Helper functions that sets options for the solver.
"""
#loop solver_args and set properties of solver
for k, v in self.solver_options.iteritems():
if k == 'sensitivity':
continue
try:
getattr(self.simulator,k)
except AttributeError:
try:
getattr(self.probl,k)
except AttributeError:
raise InvalidSolverArgumentException(v)
setattr(self.probl, k, v)
continue
setattr(self.simulator, k, v)
[docs] def solve(self):
"""
Runs the simulation.
"""
if self.sensitivity:
if self.initialize:
self.simulator.make_consistent('IDA_YA_YDP_INIT')
else:
# Only run initiate if model has been compiled with CppAD
# and if alg arg 'initialize' is True.
if self.model.has_cppad_derivatives() and self.initialize:
self.simulator.initiate()
self.simulator.simulate(self.final_time, self.ncp)
[docs] def get_result(self):
"""
Write result to file, load result data and create an AssimuloSimResult
object.
Returns::
The AssimuloSimResult object.
"""
if not self.probl.write_cont:
write_data(self.simulator,self.write_scaled_result, self.result_file_name)
#write_data(self.simulator,self.write_scaled_result,self.result_file_name)
# load result file
res = ResultDymolaTextual(self.result_file_name)
# create and return result object
return AssimuloSimResult(self.model, self.result_file_name, self.simulator, res,
self.options)
@classmethod
[docs] def get_default_options(cls):
"""
Get an instance of the options class for the AssimuloAlg algorithm,
prefilled with default values. (Class method.)
"""
return AssimuloAlgOptions()
[docs]class CollocationLagrangePolynomialsResult(JMResultBase):
pass
[docs]class CollocationLagrangePolynomialsAlgOptions(OptionBase):
"""
Options for optimizing JMU models using a collocation algorithm.
Collocation algorithm options::
n_e --
Number of elements of the finite element mesh.
Default: 50
n_cp --
Number of collocation points in each element. Values between 1 and
10 are supported
Default: 3
hs --
A vector containing n_e elements representing the finite element
lengths. The sum of all element should equal to 1.
Default: numpy.ones(n_e)/n_e (Uniform mesh)
blocking_factors --
A vector of blocking factors. Blocking factors are specified by a
vector of integers, where each entry in the vector corresponds to
the number of elements for which the control profile should be kept
constant. For example, the blocking factor specification [2,1,5]
means that u_0=u_1 and u_3=u_4=u_5=u_6=u_7 assuming that the number
of elements is 8. Notice that specification of blocking factors
implies that controls are present in only one collocation point
(the first) in each element. The number of constant control levels
in the optimization interval is equal to the length of the blocking
factor vector. In the example above, this implies that there are
three constant control levels. If the sum of the entries in the
blocking factor vector is not equal to the number of elements, the
vector is normalized, either by truncation (if the sum of the
entries is larger than the number of element) or by increasing the
last entry of the vector. For example, if the number of elements is
4, the normalized blocking factor vector in the example is [2,2].
If the number of elements is 10, then the normalized vector is
[2,1,7].
Default: None
init_traj --
Variable trajectory data used for initialization of the optimization
problem. The data is represented by an object of the type
jmodelica.io.DymolaResultTextual.
Default: None
result_mode --
Specifies the output format of the optimization result.
- 'default' gives the the optimization result at the collocation
points.
- 'element_interpolation' computes the values of the variable
trajectories using the collocation interpolation polynomials. The
option 'n_interpolation_points' is used to specify the number of
evaluation points within each finite element.
- 'mesh_interpolation' computes the values of the variable
trajectories at points defined by the option 'result_mesh'.
Default: 'default'
n_interpolation_points --
Number of interpolation points in each finite element if the result
reporting option result_mode is set to 'element_interpolation'.
Default: 20
result_mesh --
A vector of time points at which the the optimization result is
computed. This option is used if result_mode is set to
'mesh_interpolation'.
Default: None
result_file_name --
Specifies the name of the file where the optimization result is
written. Setting this option to an empty string results in a default
file name that is based on the name of the optimization class.
Default: Empty string
result_format --
Specifies in which format to write the result. Currently
only textual mode is supported.
Default: 'txt'
write_scaled_result --
Write the scaled optimization result if set to true. This option is
only applicable when automatic variable scaling is enabled. Only for
debugging use.
Default: False.
Options are set by using the syntax for dictionaries::
>>> opts = my_model.optimize_options()
>>> opts['n_e'] = 100
In addition, IPOPT options can be provided in the option IPOPT_options. For
a complete list of IPOPT options, please consult the IPOPT documentation
available at http://www.coin-or.org/Ipopt/documentation/).
Some commonly used IPOPT options are provided by default::
max_iter --
Maximum number of iterations.
Default: 3000
derivative_test --
Check the correctness of the NLP derivatives. Valid values are
'none', 'first-order', 'second-order', 'only-second-order'.
Default: 'none'
IPOPT options are set using the syntax for dictionaries::
>>> opts['IPOPT_options']['max_iter'] = 200
"""
def __init__(self, *args, **kw):
_defaults= {
'n_e':50,
'n_cp':3,
'hs':None,
'blocking_factors':None,
'init_traj':None,
'result_mode':'default',
'n_interpolation_points':20,
'result_mesh':None,
'result_file_name':'',
'result_format':'txt',
'write_scaled_result':False,
'IPOPT_options':{'max_iter':3000,
'derivative_test':'none'}
}
super(CollocationLagrangePolynomialsAlgOptions,self).__init__(_defaults)
# for those key-value-sets where the value is a dict, don't
# overwrite the whole dict but instead update the default dict
# with the new values
self._update_keep_dict_defaults(*args, **kw)
[docs]class CollocationLagrangePolynomialsAlg(AlgorithmBase):
"""
The algorithm is based on orthogonal collocation and relies on the solver
IPOPT for solving a non-linear programming problem.
"""
def __init__(self,
model,
options):
"""
Create a CollocationLagrangePolynomials algorithm.
Parameters::
model --
jmodelica.jmi.JMUModel model object
options --
The options that should be used by the algorithm. For
details on the options, see:
* model.simulate_options('CollocationLagrangePolynomialsAlgOptions')
or look at the docstring with help:
* help(jmodelica.algorithm_drivers.CollocationLagrangePolynomialsAlgOptions)
Valid values are:
- A dict that overrides some or all of the default values
provided by CollocationLagrangePolynomialsAlgOptions. An empty
dict will thus give all options with default values.
- A CollocationLagrangePolynomialsAlgOptions object.
"""
self.model = model
# handle options argument
if isinstance(options, dict) and not \
isinstance(options, CollocationLagrangePolynomialsAlgOptions):
# user has passed dict with options or empty dict = default
self.options = CollocationLagrangePolynomialsAlgOptions(options)
elif isinstance(options, CollocationLagrangePolynomialsAlgOptions):
# user has passed CollocationLagrangePolynomialsAlgOptions instance
self.options = options
else:
raise InvalidAlgorithmOptionException(options)
if self.options['hs'] == None:
self.options['hs'] = N.ones(self.options['n_e'])/self.options['n_e']
# set options
self._set_options()
if not ipopt_present:
raise Exception(
'Could not find IPOPT. Check jmodelica.check_packages()')
if self.blocking_factors == None:
self.nlp = ipopt.NLPCollocationLagrangePolynomials(
model,self.n_e, self.hs, self.n_cp)
else:
self.nlp = ipopt.NLPCollocationLagrangePolynomials(
model,self.n_e, self.hs, self.n_cp,
blocking_factors=self.blocking_factors)
if self.init_traj:
self.nlp.set_initial_from_dymola(self.init_traj, self.hs, 0, 0)
self.nlp_ipopt = ipopt.CollocationOptimizer(self.nlp)
# set solver options
self._set_solver_options()
def _set_options(self):
"""
Helper function that sets options for the CollocationLagrangePolynomials
algorithm.
"""
self.n_e=self.options['n_e']
self.n_cp=self.options['n_cp']
self.hs=self.options['hs']
self.blocking_factors=self.options['blocking_factors']
self.init_traj=self.options['init_traj']
#self.result_mesh=self.options['result_mesh']
self.result_mode = self.options['result_mode']
if self.result_mode == 'default':
self.result_args = dict(
file_name=self.options['result_file_name'],
format=self.options['result_format'],
write_scaled_result=self.options['write_scaled_result'])
elif self.result_mode == 'element_interpolation':
self.result_args = dict(
file_name = self.options['result_file_name'],
format = self.options['result_format'],
n_interpolation_points = self.options['n_interpolation_points'],
write_scaled_result=self.options['write_scaled_result'])
elif self.result_mode == 'mesh_interpolation':
self.result_args = dict(
file_name = self.options['result_file_name'],
format = self.options['result_format'],
mesh = self.options['result_mesh'],
write_scaled_result=self.options['write_scaled_result'])
else:
raise InvalidAlgorithmArgumentException(self.result_mesh)
# solver options
self.solver_options = self.options['IPOPT_options']
def _set_solver_options(self):
"""
Helper function that sets options for the solver.
"""
for k, v in self.solver_options.iteritems():
if isinstance(v, default_int):
self.nlp_ipopt.opt_coll_ipopt_set_int_option(k, v)
elif isinstance(v, float):
self.nlp_ipopt.opt_coll_ipopt_set_num_option(k, v)
elif isinstance(v, basestring):
self.nlp_ipopt.opt_coll_ipopt_set_string_option(k, v)
[docs] def solve(self):
"""
Solve the optimization problem using ipopt solver.
"""
self.nlp_ipopt.opt_coll_ipopt_solve()
[docs] def get_result(self):
"""
Write result to file, load result data and create an
CollocationLagrangePolynomialsResult object.
Returns::
The CollocationLagrangePolynomialsResult object.
"""
if self.result_mode=='element_interpolation':
self.nlp.export_result_dymola_element_interpolation(
**self.result_args)
elif self.result_mode=='mesh_interpolation':
self.nlp.export_result_dymola_mesh_interpolation(**self.result_args)
elif self.result_mode=='default':
self.nlp.export_result_dymola(**self.result_args)
else:
raise InvalidAlgorithmArgumentException(self.resul_mode)
# result file name
resultfile = self.result_args['file_name']
if not resultfile:
resultfile=self.model.get_name()+'_result.txt'
# load result file
res = ResultDymolaTextual(resultfile)
# create and return result object
return CollocationLagrangePolynomialsResult(self.model,
resultfile, self.nlp_ipopt, res, self.options)
@classmethod
[docs] def get_default_options(cls):
"""
Get an instance of the options class for the
CollocationLagrangePolynomialsAlg algorithm, prefilled with default
values. (Class method.)
"""
return CollocationLagrangePolynomialsAlgOptions()
[docs]class InvalidAlgorithmOptionException(Exception):
"""
Exception raised when an algorithm options argument is encountered that is
not valid.
"""
def __init__(self, arg):
self.msg='Invalid algorithm options object: '+str(arg)
def __str__(self):
return repr(self.msg)
[docs]class InvalidSolverArgumentException(Exception):
"""
Exception raised when a solver argument is encountered that does not exist.
"""
def __init__(self, arg):
self.msg='Invalid solver argument: '+str(arg)
def __str__(self):
return repr(self.msg)
[docs]class KInitSolveResult(JMResultBase):
pass
[docs]class KInitSolveAlgOptions(OptionBase):
"""
Options for the initialization of a JMU using the KInitSolve algorithm based
on the KINSOL wrapper in the assimulo package.
KInitSolve options::
use_constraints --
Boolean set to True if constraints are to be used. If set to False,
the initialization will not be constraind even if constraints are
supplied by the user. If set to True but constraints are not
supplied please see the documentation of constraints below.
Default: False
constraints --
Numpy.array that should be of same size as the number of variables.
The array contains numbers specifying what type of constraint to use
for each variable. The array contains the following number in the
ith position:
0.0 - no constraint on x[i]
1.0 - x[i] greater or equal than 0.0
-1.0 - x[i] lesser or equal than 0.0
2.0 - x[i] greater than 0.0
-2.0 - x[i] lesser than 0.0
If no constraints are supplied but use_constraints are set to True
the solver will 'guess' constraints basically meaning that the sign
of a variable is kept the same as the sign of the initial guess for
the variable.
Default: None
result_file_name --
A string containing the name of the file the results should be
written to. If not specified the name of the model will be used.
Default: ''
result_format --
A string specifying the format of the output file. So far only
'.txt' is supported
Default: '.txt'
The solver used by kinitsol is KINSOL, the options for KINSOL is passed in
the dictionary KINSOL_options. The options are listed below:
KINSOL options::
use_jac --
Boolean set to True if the jacobian supplied by the JMUmodel is to
be used in the solving of the initialization problem. If set to
False a jacobian generated by KINSOL using finite differences is
used.
Default: True
sparse --
Boolean set to True if the problem is to be treated as sparse and False
otherwise. Only works with the KINSOL option use_jac = True!
Dafault: False
verbosity --
Integer regulationg the level of information
output from KINSOL. Must be set to one of:
0: no information displayed.
1: for each nonlinear iteration display the following information:
- the scaled Euclidean ℓ2 norm of the residual evaluated at
the current iterate
- the scaled norm of the Newton step
- the number of function evaluations performed so far.
2: display level 1 output and the following values for each iteration:
- the 2-norm and infinitynorm of the scaled residual at
the current iterate
3: display level 2 output plus additional values used by the global strategy,
and statistical information for the linear solver.
Default: 0
"""
def __init__(self, *args, **kw):
_defaults= {
'use_constraints':False,
'constraints':None,
'result_file_name':'',
'result_format':'txt',
'KINSOL_options':{'use_jac':True,'sparse':False,'verbosity':0,'reg_param':0.0}
}
super(KInitSolveAlgOptions,self).__init__(_defaults)
# for those key-value-sets where the value is a dict, don't
# overwrite the whole dict but instead update the default dict
# with the new values
self._update_keep_dict_defaults(*args, **kw)
[docs]class KInitSolveAlg(AlgorithmBase):
"""
Initialization using a solver of non-linear eq-systems.
"""
def __init__(self, model, options):
"""
Create algorithm objects.
Parameters::
model --
jmodelica.jmi.JMUModel object representation of the model.
options --
The options that should be used in the algorithm. For details on
the options, see:
* model.simulate_options('KInitSolveAlgOptions')
or look at the docstring with help:
* help(jmodelica.algorithm_drivers.KInitSolveAlgOptions)
Valid values are:
- A dict which gives KInitSolveAlgOptions with default values on
all options except the ones listed in the dict. Empty dict
will thus give all options with default values.
- KInitSolveAlgOptions object.
"""
self.model = model
self.problem = JMUAlgebraic(model)
# handle options argument
if isinstance(options, dict) and not \
isinstance(options, KInitSolveAlgOptions):
# user has passed dict with options or empty dict = default
self.options = KInitSolveAlgOptions(options)
elif isinstance(options, KInitSolveAlgOptions):
# user has passed KInitSolveAlgOptions instance
self.options = options
else:
raise InvalidAlgorithmOptionException(options)
# set options
self._set_options()
# connect solver and set solver options
self.solver = KINSOL(self.problem)
self._set_solver_options()
def _set_options(self):
"""
Helper function that sets options for the KInitSolve algorithm.
"""
self.problem.set_constraints_usage(self.options['use_constraints'],
self.options['constraints'])
self.result_args = dict(file_name=self.options['result_file_name'],
format=self.options['result_format'])
self.solver_options = self.options['KINSOL_options']
def _set_solver_options(self):
"""
Helper function that sets options for the KINSOL solver.
"""
self.solver.set_jac_usage(self.solver_options['use_jac'])
self.solver.set_verbosity(self.solver_options['verbosity'])
self.solver.set_sparsity(self.solver_options['sparse'])
self.solver.set_reg_param(self.solver_options['reg_param'])
[docs] def solve(self):
"""
Functions calling the solver to solve the problem
"""
res = self.solver.solve()
dx = res[0:self.problem._dx_size]
x = res[self.problem._dx_size:self.problem._mark]
w = res[self.problem._mark:self.problem._neqF0]
self.model.real_dx = dx
self.model.real_x = x
self.model.real_w = w
[docs] def get_result(self):
"""
Write result to file, load result data and create an NLSInitResult
object.
Returns::
The NLSInitResult object.
"""
#self.solver.export_result_dymola(**self.result_args)
write_resdata(self.problem)
# result file name
resultfile = self.result_args['file_name']
if not resultfile:
resultfile=self.model.get_name()+'_result.txt'
# load result file
res = ResultDymolaTextual(resultfile)
# create and return result object
return KInitSolveResult(self.model, resultfile, self.solver, res,
self.options)
@classmethod
[docs] def get_default_options(cls):
"""
Get an instance of the options class for the KInitSolveAlg algorithm,
prefilled with default values. (Class method.)
"""
return KInitSolveAlgOptions()
[docs]class UnrecognizedOptionError(Exception): pass
[docs]class CasadiPseudoSpectral(AlgorithmBase):
"""
The algorithm is based on orthogonal collocation and relies on the solver
IPOPT for solving a non-linear programming problem.
"""
def __init__(self,
model,
options):
"""
Create a CasadiPseudoSpectral algorithm.
Parameters::
model --
jmodelica.jmi.casadiModel model object
options --
The options that should be used by the algorithm. For
details on the options, see:
* model.optimize_options('CasadiPseudoSpectral')
or look at the docstring with help:
* help(jmodelica.algorithm_drivers.CasadiPseudoSpectral)
Valid values are:
- A dict that overrides some or all of the default values
provided by CasadiPseudoSpectralOptions. An empty
dict will thus give all options with default values.
- A CasadiPseudoSpectralOptions object.
"""
self.model = model
# handle options argument
if isinstance(options, dict) and not \
isinstance(options, CasadiPseudoSpectralOptions):
# user has passed dict with options or empty dict = default
self.options = CasadiPseudoSpectralOptions(options)
elif isinstance(options, CasadiPseudoSpectralOptions):
# user has passed CasadiPseudoSpectralOptions instance
self.options = options
else:
raise InvalidAlgorithmOptionException(options)
# set options
self._set_options()
if not casadi_present:
raise Exception(
'Could not find CasADi. Check jmodelica.check_packages()')
self.nlp = PseudoSpectral(model, self.options)
if self.init_traj:
self.nlp.set_initial_from_file(self.init_traj)
# set solver options
self._set_solver_options()
def _set_options(self):
"""
Helper function that sets options for the CasadiPseudoSpectral
algorithm.
"""
self.n_e=self.options['n_e']
self.n_cp=self.options['n_cp']
self.init_traj=self.options['init_traj']
self.result_mode = self.options['result_mode']
if self.result_mode == 'default':
self.result_args = dict(
file_name=self.options['result_file_name'],
format=self.options['result_format'],
write_scaled_result=self.options['write_scaled_result'])
else:
raise InvalidAlgorithmArgumentException(self.result_mesh)
# solver options
self.solver_options = self.options['IPOPT_options']
def _set_solver_options(self):
"""
Helper function that sets options for the solver.
"""
for k, v in self.solver_options.iteritems():
self.nlp.set_ipopt_option(k, v)
[docs] def solve(self):
"""
Solve the optimization problem using ipopt solver.
"""
self.nlp.ipopt_solve()
[docs] def get_result(self):
"""
Write result to file, load result data and create an
CasadiPseudoSpectralResult object.
Returns::
The CasadiPseudoSpectralResult object.
"""
if self.result_mode=='default':
self.nlp.export_result_dymola(**self.result_args)
else:
raise InvalidAlgorithmArgumentException(self.resul_mode)
# result file name
resultfile = self.result_args['file_name']
if not resultfile:
resultfile=self.model.get_name()+'_result.txt'
# load result file
res = ResultDymolaTextual(resultfile)
# create and return result object
return CasadiPseudoSpectralResult(self.model,
resultfile, self.nlp, res, self.options)
@classmethod
[docs] def get_default_options(cls):
"""
Get an instance of the options class for the
CollocationLagrangePolynomialsAlg algorithm, prefilled with default
values. (Class method.)
"""
return CasadiPseudoSpectralOptions()
[docs]class CasadiPseudoSpectralOptions(OptionBase):
"""
Options for optimizing JMU models using a collocation algorithm.
Collocation algorithm options::
n_e --
Number of phases of the finite element mesh.
Default: 1
n_cp --
Number of collocation points in each phase (element).
Default: 20
discr --
Determines the discretization of the problem. Could be either
LG (Legendre-Gauss), LGR (Legendre-Gauss-Radau), LGL (Legendre-
Gauss-Lobatto)
Default: "LG"
link_options --
This option allows users to specify states that are allowed to be
discontinious between phases (elements). There is also an option
to include the discontinuities into the optimization problem, such
that the optimizer tries to minimize the discontinuities. If they
are included, they are included as the L2-Norm for each phase
boundary. Example, [("x",True),("y",True)]. "x" and "y" are allowed
to be discontinious and they are included into the Mayer cost for
each phase boundary as (dx^2+dy^2)^0.5.
Default: []
link_bounds --
Specifies the initial, lower and upper bounds of the links.
Default: []
free_phases --
Specifies if the location of the phases should be allowed to be
changed by the optimizer.
Default: False
phase_bounds --
Specifies the initial, lower and upper bounds of the free phases.
Default: None
n_interpolation_points --
Number of interpolation points in each finite element.
Default: None
init_traj --
Variable trajectory data used for initialization of the optimization
problem. The data is represented by an object of the type
jmodelica.io.DymolaResultTextual.
Default: None
result_mode --
Specifies the output format of the optimization result.
- 'default' gives the the optimization result at the collocation
points.
Default: 'default'
result_file_name --
Specifies the name of the file where the optimization result is
written. Setting this option to an empty string results in a default
file name that is based on the name of the optimization class.
Default: Empty string
result_format --
Specifies in which format to write the result. Currently
only textual mode is supported.
Default: 'txt'
write_scaled_result --
Write the scaled optimization result if set to true. This option is
only applicable when automatic variable scaling is enabled. Only for
debugging use.
Default: False.
Options are set by using the syntax for dictionaries::
>>> opts = my_model.optimize_options()
>>> opts['n_e'] = 100
In addition, IPOPT options can be provided in the option IPOPT_options. For
a complete list of IPOPT options, please consult the IPOPT documentation
available at http://www.coin-or.org/Ipopt/documentation/).
Some commonly used IPOPT options are provided by default::
max_iter --
Maximum number of iterations.
Default: 3000
derivative_test --
Check the correctness of the NLP derivatives. Valid values are
'none', 'first-order', 'second-order', 'only-second-order'.
Default: 'none'
IPOPT options are set using the syntax for dictionaries::
>>> opts['IPOPT_options']['max_iter'] = 200
"""
def __init__(self, *args, **kw):
_defaults= {
'n_e':1,
'n_cp':20,
'discr': "LG",
'free_phases':False,
'phase_bounds':None,
'link_bounds':[],
'link_options':[],
'n_interpolation_points':None,
'init_traj':None,
'result_mode':'default',
'result_file_name':'',
'result_format':'txt',
'write_scaled_result':False,
'IPOPT_options':{'max_iter':1000,
'derivative_test':'none'}
}
super(CasadiPseudoSpectralOptions,self).__init__(_defaults)
# for those key-value-sets where the value is a dict, don't
# overwrite the whole dict but instead update the default dict
# with the new values
self._update_keep_dict_defaults(*args, **kw)
[docs]class CasadiPseudoSpectralResult(JMResultBase):
pass
[docs]class CasadiRadauResult(JMResultBase):
pass
[docs]class CasadiRadauOptions(OptionBase):
"""
Options for optimizing JMU models using a collocation algorithm.
Collocation algorithm options::
n_e --
Number of phases of the finite element mesh.
Default: 50
n_cp --
Number of collocation points in each element.
Default: 3
Options are set by using the syntax for dictionaries::
>>> opts = my_model.optimize_options()
>>> opts['n_e'] = 100
In addition, IPOPT options can be provided in the option IPOPT_options. For
a complete list of IPOPT options, please consult the IPOPT documentation
available at http://www.coin-or.org/Ipopt/documentation/).
Some commonly used IPOPT options are provided by default::
max_iter --
Maximum number of iterations.
Default: 3000
derivative_test --
Check the correctness of the NLP derivatives. Valid values are
'none', 'first-order', 'second-order', 'only-second-order'.
Default: 'none'
IPOPT options are set using the syntax for dictionaries::
>>> opts['IPOPT_options']['max_iter'] = 200
"""
def __init__(self, *args, **kw):
_defaults= {
'n_e':50,
'n_cp':3,
'IPOPT_options':{'max_iter':1000,
'derivative_test':'none'}
}
super(CasadiRadauOptions,self).__init__(_defaults)
# for those key-value-sets where the value is a dict, don't
# overwrite the whole dict but instead update the default dict
# with the new values
self._update_keep_dict_defaults(*args, **kw)
[docs]class CasadiRadau(AlgorithmBase):
"""
The algorithm is based on orthogonal collocation and relies on the solver
IPOPT for solving a non-linear programming problem.
"""
def __init__(self,
model,
options):
"""
Create a CasadiRadau algorithm.
Parameters::
model --
jmodelica.jmi.casadiModel model object
options --
The options that should be used by the algorithm. For
details on the options, see:
* model.optimize_options('CasadiRadauOptions')
or look at the docstring with help:
* help(jmodelica.algorithm_drivers.CasadiRadauOptions)
Valid values are:
- A dict that overrides some or all of the default values
provided by CasadiRadauOptions. An empty
dict will thus give all options with default values.
- A CasadiRadauOptions object.
"""
self.model = model
# handle options argument
if isinstance(options, dict) and not \
isinstance(options, CasadiRadauOptions):
# user has passed dict with options or empty dict = default
self.options = CasadiRadauOptions(options)
elif isinstance(options, CasadiRadauOptions):
# user has passed CasadiLPMOptions instance
self.options = options
else:
raise InvalidAlgorithmOptionException(options)
# set options
self._set_options()
if not casadi_present:
raise Exception(
'Could not find CasADi. Check jmodelica.check_packages()')
self.nlp = RadauCollocator(model, self.options)
# set solver options
self._set_solver_options()
def _set_options(self):
"""
Helper function that sets options for the CasadiRadau
algorithm.
"""
self.n_e=self.options['n_e']
self.n_cp=self.options['n_cp']
# solver options
self.solver_options = self.options['IPOPT_options']
def _set_solver_options(self):
"""
Helper function that sets options for the solver.
"""
for k, v in self.solver_options.iteritems():
self.nlp.set_ipopt_option(k, v)
[docs] def solve(self):
"""
Solve the optimization problem using ipopt solver.
"""
self.nlp.ipopt_solve()
[docs] def get_result(self):
"""
Write result to file, load result data and create an
CollocationLagrangePolynomialsResult object.
Returns::
The CasadiRadauResult object.
"""
self.nlp.export_result_dymola()
# result file name
#resultfile = self.result_args['file_name']
#if not resultfile:
resultfile=self.model.get_name()+'_result.txt'
# load result file
res = ResultDymolaTextual(resultfile)
# create and return result object
return CasadiRadauResult(self.model,
resultfile, self.nlp, res, self.options)
@classmethod
[docs] def get_default_options(cls):
"""
Get an instance of the options class for the
CollocationLagrangePolynomialsAlg algorithm, prefilled with default
values. (Class method.)
"""
return CasadiRadauOptions()