Nektar++
Public Member Functions | Private Member Functions | Private Attributes | List of all members
CellMLToNektar.processors.InterfaceGenerator Class Reference
Inheritance diagram for CellMLToNektar.processors.InterfaceGenerator:
[legend]

Public Member Functions

def __init__ (self, model, name='interface', units_converter=None)
 
def add_input (self, var, units, annotate=True, convert_initial_value=True)
 
def add_output (self, var, units, annotate=True)
 
def add_output_function (self, resultName, operator, argVars, units)
 
def make_var_constant (self, var, value)
 
def make_var_computed_constant (self, var, value)
 
def finalize (self, *args, **kwargs)
 
def get_interface_component (self)
 
- Public Member Functions inherited from CellMLToNektar.processors.ModelModifier
def __init__ (self, model)
 
def finalize (self, error_handler, pre_units_check_hook=None, check_units=True)
 
def create_new_component (self, cname)
 
def connect_variables (self, source, target)
 
def remove_connection (self, var1, var2)
 
def remove_connections (self, var)
 
def add_variable (self, comp, vname, units, **kwargs)
 
def add_units (self, units)
 
def add_expr_to_comp (self, comp, expr)
 
def remove_expr (self, expr)
 
def remove_definition (self, var, keep_initial_value=False)
 
def del_attr (self, elt, localName, ns=None)
 
def set_units_converter (self, converter)
 
def get_units_converter (self)
 

Private Member Functions

def _transform_derivatives_on_rhs (self)
 
def _transform_derivative_on_rhs (self, expr)
 
def _split_ode (self, newVar, oldVar)
 
def _add_all_odes_to_interface (self)
 

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

◆ __init__()

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

Reimplemented from CellMLToNektar.processors.ModelModifier.

Definition at line 541 of file processors.py.

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

References CellMLToNektar.processors.InterfaceGenerator.__init__().

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

Member Function Documentation

◆ _add_all_odes_to_interface()

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.

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

References CellMLToNektar.processors.InterfaceGenerator.add_input(), CellMLToNektar.processors.InterfaceGenerator.get_interface_component(), CellMLToNektar.processors.ModelModifier.model, CellMLToNektar.pycml.cellml_variable.model(), CellMLToNektar.pycml.mathml.model(), and CellMLToNektar.translators.CellMLTranslator.model.

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

◆ _split_ode()

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.

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

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.cellml_variable.model(), CellMLToNektar.pycml.mathml.model(), CellMLToNektar.translators.CellMLTranslator.model, CellMLToNektar.pycml.quotient(), and CellMLToNektar.processors.ModelModifier.remove_expr().

Referenced by CellMLToNektar.processors.InterfaceGenerator._transform_derivatives_on_rhs(), and CellMLToNektar.processors.InterfaceGenerator.add_input().

◆ _transform_derivative_on_rhs()

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.

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

References CellMLToNektar.processors.InterfaceGenerator._transform_derivatives_on_rhs(), and CellMLToNektar.processors.ModelModifier.connect_variables().

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

◆ _transform_derivatives_on_rhs()

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.

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

References CellMLToNektar.processors.ModelModifier._process_operator(), CellMLToNektar.processors.InterfaceGenerator._split_ode(), CellMLToNektar.processors.InterfaceGenerator._transform_derivative_on_rhs(), CellMLToNektar.processors.ModelModifier.model, CellMLToNektar.pycml.cellml_variable.model(), CellMLToNektar.pycml.mathml.model(), and CellMLToNektar.translators.CellMLTranslator.model.

Referenced by CellMLToNektar.processors.InterfaceGenerator._transform_derivative_on_rhs(), and CellMLToNektar.processors.InterfaceGenerator.finalize().

◆ add_input()

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.

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

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().

◆ add_output()

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.

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

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().

◆ add_output_function()

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.

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

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(), CellMLToNektar.processors.ModelModifier.model, CellMLToNektar.pycml.cellml_variable.model(), CellMLToNektar.pycml.mathml.model(), and CellMLToNektar.translators.CellMLTranslator.model.

◆ finalize()

def CellMLToNektar.processors.InterfaceGenerator.finalize (   self,
args,
**  kwargs 
)
Override finalize to also set up standard interface elements not defined individually.

Reimplemented from CellMLToNektar.processors.ModelModifier.

Definition at line 658 of file processors.py.

658 def finalize(self, *args, **kwargs):
659 """Override finalize to also set up standard interface elements not defined individually."""
660 self._add_all_odes_to_interface()
661 self._transform_derivatives_on_rhs()
662 super(InterfaceGenerator, self).finalize(*args, **kwargs)
663

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

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

◆ get_interface_component()

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.

736 def get_interface_component(self):
737 """Get the new component that will contain the interface.
738
739 The name will be self._interface_component_name, unless a component with that name already exists,
740 in which case underscores will be added to the component name to make it unique.
741 """
742 if self._interface_component is None:
743 self._interface_component = self.create_new_component(unicode(self._interface_component_name))
744 self.model.interface_component_name = unicode(self._interface_component_name)
745 assert not self._interface_component.ignore_component_name
746 return self._interface_component
747
748

References CellMLToNektar.processors.InterfaceGenerator._interface_component, CellMLToNektar.processors.InterfaceGenerator._interface_component_name, CellMLToNektar.processors.ModelModifier.create_new_component(), CellMLToNektar.processors.ModelModifier.model, CellMLToNektar.pycml.cellml_variable.model(), CellMLToNektar.pycml.mathml.model(), and CellMLToNektar.translators.CellMLTranslator.model.

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().

◆ make_var_computed_constant()

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.

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

References CellMLToNektar.processors.ModelModifier.add_expr_to_comp(), CellMLToNektar.processors.ModelModifier.model, CellMLToNektar.pycml.cellml_variable.model(), CellMLToNektar.pycml.mathml.model(), CellMLToNektar.translators.CellMLTranslator.model, and CellMLToNektar.processors.ModelModifier.remove_definition().

◆ make_var_constant()

def CellMLToNektar.processors.InterfaceGenerator.make_var_constant (   self,
  var,
  value 
)
Turn a variable into a constant.

Definition at line 642 of file processors.py.

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

References CellMLToNektar.processors.ModelModifier.remove_definition().

Member Data Documentation

◆ _interface_component

CellMLToNektar.processors.InterfaceGenerator._interface_component
private

◆ _interface_component_name

CellMLToNektar.processors.InterfaceGenerator._interface_component_name
private