Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
Public Member Functions | Private Member Functions | Private Attributes | List of all members
CellMLToNektar.processors.InterfaceGenerator Class Reference
Inheritance diagram for CellMLToNektar.processors.InterfaceGenerator:
Inheritance graph
[legend]
Collaboration diagram for CellMLToNektar.processors.InterfaceGenerator:
Collaboration graph
[legend]

Public Member Functions

def __init__
 
def add_input
 
def add_output
 
def add_output_function
 
def make_var_constant
 
def make_var_computed_constant
 
def finalize
 
def get_interface_component
 
- Public Member Functions inherited from CellMLToNektar.processors.ModelModifier
def __init__
 
def finalize
 
def create_new_component
 
def connect_variables
 
def remove_connection
 
def remove_connections
 
def add_variable
 
def add_units
 
def add_expr_to_comp
 
def remove_expr
 
def remove_definition
 
def del_attr
 
def set_units_converter
 
def get_units_converter
 

Private Member Functions

def _transform_derivatives_on_rhs
 
def _transform_derivative_on_rhs
 
def _split_ode
 
def _add_all_odes_to_interface
 

Private Attributes

 _interface_component
 
 _interface_component_name
 

Additional Inherited Members

- Public Attributes inherited from CellMLToNektar.processors.ModelModifier
 model
 
 connections_made
 

Detailed Description

Class for generating an interface between a CellML model and external code.

This contains functionality for users to describe the interface desired by the external code, i.e.
which variables are inputs and/or outputs, and expected units.  It will then create a new component
within the CellML model containing these variables, and add units conversions where required.  The
external code then only needs to interact with this new component.

Definition at line 533 of file processors.py.

Constructor & Destructor Documentation

def CellMLToNektar.processors.InterfaceGenerator.__init__ (   self,
  model,
  name = 'interface',
  units_converter = None 
)

Definition at line 541 of file processors.py.

542  def __init__(self, model, name='interface', units_converter=None):
543  super(InterfaceGenerator, self).__init__(model)
545  self._interface_component_name = name
546  self.set_units_converter(units_converter)

Member Function Documentation

def CellMLToNektar.processors.InterfaceGenerator._add_all_odes_to_interface (   self)
private
All the derivatives should be considered as model outputs, and state variables as model inputs.

For any that haven't been done explicitly, this method will add the corresponding state variable
as an input, with its original units, which has the desired effect.

Definition at line 725 of file processors.py.

References CellMLToNektar.processors.InterfaceGenerator.add_input(), and CellMLToNektar.processors.InterfaceGenerator.get_interface_component().

Referenced by CellMLToNektar.processors.InterfaceGenerator.finalize().

726  def _add_all_odes_to_interface(self):
727  """All the derivatives should be considered as model outputs, and state variables as model inputs.
728 
729  For any that haven't been done explicitly, this method will add the corresponding state variable
730  as an input, with its original units, which has the desired effect.
731  """
732  comp = self.get_interface_component()
733  for var in self.model.find_state_vars():
734  if var.component is not comp:
735  self.add_input(var, var.get_units())
def CellMLToNektar.processors.InterfaceGenerator._split_ode (   self,
  newVar,
  oldVar 
)
private
Split an ODE definition so the derivative goes into the interface component.

The RHS stays where it is, and is assigned to a new variable, which is connected to the interface
component and assigned to the new derivative.  newVar is the new state variable in the interface
component, and oldVar will soon be mapped to it by the caller.

Any other equations in the model which use the derivative are transformed to use the new variable
instead.

Definition at line 692 of file processors.py.

References CellMLToNektar.processors.ModelModifier._uniquify_var_name(), CellMLToNektar.processors.ModelModifier.add_expr_to_comp(), CellMLToNektar.processors.InterfaceGenerator.add_input(), CellMLToNektar.processors.InterfaceGenerator.add_output(), CellMLToNektar.processors.ModelModifier.add_variable(), CellMLToNektar.pycml.extract(), CellMLToNektar.processors.ModelModifier.model, CellMLToNektar.pycml.quotient(), and CellMLToNektar.processors.ModelModifier.remove_expr().

Referenced by CellMLToNektar.processors.InterfaceGenerator.add_input().

693  def _split_ode(self, newVar, oldVar):
694  """Split an ODE definition so the derivative goes into the interface component.
695 
696  The RHS stays where it is, and is assigned to a new variable, which is connected to the interface
697  component and assigned to the new derivative. newVar is the new state variable in the interface
698  component, and oldVar will soon be mapped to it by the caller.
699 
700  Any other equations in the model which use the derivative are transformed to use the new variable
701  instead.
702  """
703  # Get the free variable in the interface component
704  free_var = self.model.find_free_vars()[0]
705  if free_var.component is not newVar.component:
706  free_var = self.add_input(free_var, free_var.get_units())
707  # Add a new variable to assign the RHS to, with units of the original derivative
708  deriv_name = self._uniquify_var_name(u'd_%s_d_%s' % (oldVar.name, free_var.name), oldVar.component)
709  orig_ode = oldVar.get_all_expr_dependencies()[0]
710  orig_rhs_var = self.add_variable(oldVar.component, deriv_name, orig_ode.eq.lhs.get_units().extract())
711  # Add an output version of this in the interface, with desired units
712  desired_units = newVar.get_units().quotient(free_var.get_units())
713  mapped_rhs_var = self.add_output(orig_rhs_var, desired_units, annotate=False)
714  # Replace the original ODE with an assignment
715  orig_rhs = orig_ode.eq.rhs
716  orig_ode.safe_remove_child(orig_rhs)
717  self.remove_expr(orig_ode)
718  self.add_expr_to_comp(oldVar.component,
719  mathml_apply.create_new(self.model, u'eq',
720  [orig_rhs_var.name, orig_rhs]))
721  # Create a new ODE in the interface component
722  new_ode = mathml_diff.create_new(self.model, free_var.name, newVar.name, mapped_rhs_var.name)
723  self.add_expr_to_comp(newVar.component, new_ode)
724  new_ode.classify_variables(root=True, dependencies_only=True)
def CellMLToNektar.processors.InterfaceGenerator._transform_derivative_on_rhs (   self,
  expr 
)
private
Transform a derivative on the RHS of an equation to refer to the defining variable.

Helper method used by self._transform_derivatives_on_rhs to do the actual transformation.

Definition at line 675 of file processors.py.

References CellMLToNektar.processors.ModelModifier.connect_variables().

Referenced by CellMLToNektar.processors.InterfaceGenerator._transform_derivatives_on_rhs().

676  def _transform_derivative_on_rhs(self, expr):
677  """Transform a derivative on the RHS of an equation to refer to the defining variable.
678 
679  Helper method used by self._transform_derivatives_on_rhs to do the actual transformation.
680  """
681  # Find the variable to use
682  dep_var = expr.diff.dependent_variable.get_source_variable(recurse=True)
683  indep_var = expr.diff.independent_variable.get_source_variable(recurse=True)
684  ode = dep_var.get_ode_dependency(indep_var)
685  rhs_var = ode.eq.rhs.variable.get_source_variable(recurse=True)
686  # Ensure there's something mapped to it in this component
687  rhs_var = self.connect_variables(rhs_var, (expr.component.name, rhs_var.name))
688  # Update this expression
689  parent = expr.xml_parent
690  parent.xml_insert_after(expr, mathml_ci.create_new(parent, rhs_var.name))
691  parent.safe_remove_child(expr)
def CellMLToNektar.processors.InterfaceGenerator._transform_derivatives_on_rhs (   self)
private
Transform any equations with derivatives on the RHS to use the variable defining it instead.

self._split_ode must have been used for all derivatives before calling this method.  This means
that each ODE now has a variable to which the RHS is assigned.  Rather than using the derivative
directly, which could break the dependency chain if units conversions are used for time, equations
should refer to this new variable instead.

Definition at line 664 of file processors.py.

References CellMLToNektar.processors.ModelModifier._process_operator(), and CellMLToNektar.processors.InterfaceGenerator._transform_derivative_on_rhs().

Referenced by CellMLToNektar.processors.InterfaceGenerator.finalize().

666  """Transform any equations with derivatives on the RHS to use the variable defining it instead.
667 
668  self._split_ode must have been used for all derivatives before calling this method. This means
669  that each ODE now has a variable to which the RHS is assigned. Rather than using the derivative
670  directly, which could break the dependency chain if units conversions are used for time, equations
671  should refer to this new variable instead.
672  """
673  for expr in self.model.search_for_assignments():
674  self._process_operator(list(expr.operands())[1], u'diff', self._transform_derivative_on_rhs)
def CellMLToNektar.processors.InterfaceGenerator.add_input (   self,
  var,
  units,
  annotate = True,
  convert_initial_value = True 
)
Specify a variable as an input to the model.

var should be a cellml_variable object already existing in the model.
units should be a suitable input to self._get_units_object.

If adding both State and Free variables as inputs, make sure to add the Free variable first,
otherwise you will not be able to specify units for it.

Set annotate to False if you do not wish a Constant variable to be annotated as a modifiable
parameter.

If a units converter has been supplied, we will also try to units-convert initial values.
This may not be possible if special conversions are used, since they may involve variables
whose values are not known at this time.  If this is the case, set convert_initial_value to
False to avoid applying the conversion.  A proper solution requires CellML 1.1 features.

The new variable added to the interface component is returned.

Definition at line 547 of file processors.py.

References CellMLToNektar.processors.ModelModifier._convert_initial_value(), CellMLToNektar.processors.ModelModifier._get_units_object(), CellMLToNektar.processors.InterfaceGenerator._split_ode(), CellMLToNektar.processors.ModelModifier._update_connections(), CellMLToNektar.processors.ModelModifier.add_variable(), CellMLToNektar.processors.ModelModifier.del_attr(), and CellMLToNektar.processors.InterfaceGenerator.get_interface_component().

Referenced by CellMLToNektar.processors.InterfaceGenerator._add_all_odes_to_interface(), and CellMLToNektar.processors.InterfaceGenerator._split_ode().

548  def add_input(self, var, units, annotate=True, convert_initial_value=True):
549  """Specify a variable as an input to the model.
550 
551  var should be a cellml_variable object already existing in the model.
552  units should be a suitable input to self._get_units_object.
553 
554  If adding both State and Free variables as inputs, make sure to add the Free variable first,
555  otherwise you will not be able to specify units for it.
556 
557  Set annotate to False if you do not wish a Constant variable to be annotated as a modifiable
558  parameter.
559 
560  If a units converter has been supplied, we will also try to units-convert initial values.
561  This may not be possible if special conversions are used, since they may involve variables
562  whose values are not known at this time. If this is the case, set convert_initial_value to
563  False to avoid applying the conversion. A proper solution requires CellML 1.1 features.
564 
565  The new variable added to the interface component is returned.
566  """
567  assert isinstance(var, cellml_variable)
568  units = self._get_units_object(units)
569  var = var.get_source_variable(recurse=True) # Ensure we work with source variables only
570  var_name = var.fullname(cellml=True)
571  # Check that the variable has a suitable type to be an input
572  t = var.get_type()
573  if t == VarTypes.Computed:
574  raise ModelModificationError("Cannot specify computed variable " + var.fullname() + " as an input")
575  elif t not in [VarTypes.Constant, VarTypes.Free, VarTypes.State]:
576  raise ModelModificationError("Variable " + var.fullname() + " has unexpected type " + str(t))
577  # Add a new variable with desired units to the interface component
578  comp = self.get_interface_component()
579  newvar = self.add_variable(comp, var_name, units, id=var.cmeta_id,
580  initial_value=self._convert_initial_value(var, units, convert_initial_value),
581  interfaces={u'public': u'out'})
582  newvar._set_type(t)
583  # Remove initial value and id from the original, if they exist
584  self.del_attr(var, u'initial_value')
585  self.del_attr(var, u'id', NSS['cmeta'])
586  # If the original variable was a state variable, split the defining equation
587  if t == VarTypes.State:
588  self._split_ode(newvar, var)
589  # Annotate the new variable as a parameter if the original was a constant
590  if t == VarTypes.Constant and annotate:
591  newvar.set_is_modifiable_parameter(True)
592 
593  self._update_connections(var, newvar)
594  return newvar
def CellMLToNektar.processors.InterfaceGenerator.add_output (   self,
  var,
  units,
  annotate = True 
)
Specify a variable as an output of the model.

var should be a cellml_variable object already existing in the model.
units should be a suitable input to self._get_units_object.
The new variable will take the cmeta:id of the original, and hence existing metadata
annotations will refer to the new variable.
If annotate is set to True, the new variable will also be annotated as a derived quantity.

The new variable added to the interface component is returned.

Definition at line 595 of file processors.py.

References CellMLToNektar.processors.ModelModifier._get_units_object(), CellMLToNektar.processors.ModelModifier.add_variable(), CellMLToNektar.processors.ModelModifier.connect_variables(), CellMLToNektar.processors.ModelModifier.del_attr(), and CellMLToNektar.processors.InterfaceGenerator.get_interface_component().

Referenced by CellMLToNektar.processors.InterfaceGenerator._split_ode(), and CellMLToNektar.processors.InterfaceGenerator.add_output_function().

596  def add_output(self, var, units, annotate=True):
597  """Specify a variable as an output of the model.
598 
599  var should be a cellml_variable object already existing in the model.
600  units should be a suitable input to self._get_units_object.
601  The new variable will take the cmeta:id of the original, and hence existing metadata
602  annotations will refer to the new variable.
603  If annotate is set to True, the new variable will also be annotated as a derived quantity.
604 
605  The new variable added to the interface component is returned.
606  """
607  assert isinstance(var, cellml_variable)
608  units = self._get_units_object(units)
609  var = var.get_source_variable(recurse=True)
610  var_name = var.fullname(cellml=True)
611  comp = self.get_interface_component()
612  newvar = self.add_variable(comp, var_name, units, id=var.cmeta_id)
613  self.del_attr(var, u'id', NSS['cmeta'])
614  self.connect_variables(var, newvar)
615  if annotate:
616  newvar.set_is_derived_quantity(True)
617  return newvar
def CellMLToNektar.processors.InterfaceGenerator.add_output_function (   self,
  resultName,
  operator,
  argVars,
  units 
)
Add an output that's defined as a (MathML) function of existing model variables.

The desired units are those of the function's result.  The function arguments will be
imported with their units as given by the model, and the function calculated.  This result
will then be units-converted if necessary.

The new variable added to the interface component is returned.

Definition at line 618 of file processors.py.

References CellMLToNektar.processors.ModelModifier._get_units_object(), CellMLToNektar.processors.ModelModifier.add_expr_to_comp(), CellMLToNektar.processors.InterfaceGenerator.add_output(), CellMLToNektar.processors.ModelModifier.add_variable(), CellMLToNektar.processors.InterfaceGenerator.get_interface_component(), and CellMLToNektar.processors.ModelModifier.model.

619  def add_output_function(self, resultName, operator, argVars, units):
620  """Add an output that's defined as a (MathML) function of existing model variables.
621 
622  The desired units are those of the function's result. The function arguments will be
623  imported with their units as given by the model, and the function calculated. This result
624  will then be units-converted if necessary.
625 
626  The new variable added to the interface component is returned.
627  """
628  # Add the result variable
629  comp = self.get_interface_component()
630  units = self._get_units_object(units)
631  result_var = self.add_variable(comp, resultName, units)
632  result_var.set_pe_keep(True)
633  # Map the argument variables
634  operands = []
635  for var in argVars:
636  operands.append(self.add_output(var, var.get_units(), annotate=False).name)
637  # Create the new function and assign it to result_var
638  expr = mathml_apply.create_new(self.model, operator, operands)
639  assign = mathml_apply.create_new(self.model, u'eq', [result_var.name, expr])
640  self.add_expr_to_comp(comp, assign)
641  return result_var
def CellMLToNektar.processors.InterfaceGenerator.finalize (   self,
  args,
  kwargs 
)
Override finalize to also set up standard interface elements not defined individually.

Definition at line 658 of file processors.py.

References CellMLToNektar.processors.InterfaceGenerator._add_all_odes_to_interface(), and CellMLToNektar.processors.InterfaceGenerator._transform_derivatives_on_rhs().

659  def finalize(self, *args, **kwargs):
660  """Override finalize to also set up standard interface elements not defined individually."""
663  super(InterfaceGenerator, self).finalize(*args, **kwargs)
def CellMLToNektar.processors.InterfaceGenerator.get_interface_component (   self)
Get the new component that will contain the interface.

The name will be self._interface_component_name, unless a component with that name already exists,
in which case underscores will be added to the component name to make it unique.

Definition at line 736 of file processors.py.

References CellMLToNektar.processors.InterfaceGenerator._interface_component, CellMLToNektar.processors.InterfaceGenerator._interface_component_name, and CellMLToNektar.processors.ModelModifier.create_new_component().

Referenced by CellMLToNektar.processors.InterfaceGenerator._add_all_odes_to_interface(), CellMLToNektar.processors.InterfaceGenerator.add_input(), CellMLToNektar.processors.InterfaceGenerator.add_output(), and CellMLToNektar.processors.InterfaceGenerator.add_output_function().

737  def get_interface_component(self):
738  """Get the new component that will contain the interface.
739 
740  The name will be self._interface_component_name, unless a component with that name already exists,
741  in which case underscores will be added to the component name to make it unique.
742  """
743  if self._interface_component is None:
745  self.model.interface_component_name = unicode(self._interface_component_name)
746  assert not self._interface_component.ignore_component_name
747  return self._interface_component
748 
def CellMLToNektar.processors.InterfaceGenerator.make_var_computed_constant (   self,
  var,
  value 
)
Turn a variable into a Computed variable with constant value definition.

Definition at line 649 of file processors.py.

References CellMLToNektar.processors.ModelModifier.add_expr_to_comp(), CellMLToNektar.processors.ModelModifier.model, and CellMLToNektar.processors.ModelModifier.remove_definition().

650  def make_var_computed_constant(self, var, value):
651  """Turn a variable into a Computed variable with constant value definition."""
652  self.remove_definition(var)
653  var.clear_dependency_info()
654  defn = mathml_apply.create_new(self.model, u'eq',
655  [var.name, (unicode(str(value)), var.get_units().name)])
656  self.add_expr_to_comp(var.component, defn)
657  var._set_type(VarTypes.Computed)
def CellMLToNektar.processors.InterfaceGenerator.make_var_constant (   self,
  var,
  value 
)
Turn a variable into a constant.

Definition at line 642 of file processors.py.

References CellMLToNektar.processors.ModelModifier.remove_definition().

643  def make_var_constant(self, var, value):
644  """Turn a variable into a constant."""
645  self.remove_definition(var)
646  var.clear_dependency_info()
647  var.initial_value = unicode(str(value))
648  var._set_type(VarTypes.Constant)

Member Data Documentation

CellMLToNektar.processors.InterfaceGenerator._interface_component
private

Definition at line 543 of file processors.py.

Referenced by CellMLToNektar.processors.InterfaceGenerator.get_interface_component().

CellMLToNektar.processors.InterfaceGenerator._interface_component_name
private

Definition at line 544 of file processors.py.

Referenced by CellMLToNektar.processors.InterfaceGenerator.get_interface_component().