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

Public Member Functions

def __init__
 
def __del__
 
def try_convert
 
def add_special_conversion
 
def modify_rhs
 
def times_rhs_by
 
def divide_rhs_by
 
def convert_assignments
 
def convert_constant
 
def convert_mapping
 
def convert_connections
 
def add_conversions_for_component
 
def add_all_conversions
 
- 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
 

Public Attributes

 warn_only
 
 show_xml_context_only
 
 special_conversions
 
- Public Attributes inherited from CellMLToNektar.processors.ModelModifier
 model
 
 connections_made
 

Private Member Functions

def _setup_logger
 
def _cleanup_logger
 
def _apply_special_conversion_for_nested_expr
 
def _check_special_conversion
 

Private Attributes

 _converted_mappings
 
 _log_handler
 

Detailed Description

Top-level interface to the units conversion code in PyCml.

Definition at line 749 of file processors.py.

Constructor & Destructor Documentation

def CellMLToNektar.processors.UnitsConverter.__init__ (   self,
  model,
  warn_only = None,
  show_xml_context_only = False 
)

Definition at line 752 of file processors.py.

753  def __init__(self, model, warn_only=None, show_xml_context_only=False):
754  super(UnitsConverter, self).__init__(model)
755  if warn_only is None:
756  warn_only = model.get_option('warn_on_units_errors')
757  self.warn_only = warn_only
758  self.show_xml_context_only = show_xml_context_only
759  self.special_conversions = {}
761  self._converted_mappings = set()
def CellMLToNektar.processors.UnitsConverter.__del__ (   self)

Definition at line 762 of file processors.py.

References CellMLToNektar.processors.UnitsConverter._cleanup_logger().

763  def __del__(self):
764  self._cleanup_logger()

Member Function Documentation

def CellMLToNektar.processors.UnitsConverter._apply_special_conversion_for_nested_expr (   self,
  expr,
  defn_units,
  desired_units 
)
private
Apply a special conversion to the given (sub-)expression.

This will get called by mathml_units_mixin._add_units_conversion if a special conversion is required by a nested sub-expression.

Definition at line 792 of file processors.py.

References CellMLToNektar.utilities.DEBUG(), and CellMLToNektar.processors.UnitsConverter.special_conversions.

Referenced by CellMLToNektar.processors.UnitsConverter.add_conversions_for_component().

793  def _apply_special_conversion_for_nested_expr(self, expr, defn_units, desired_units):
794  """Apply a special conversion to the given (sub-)expression.
795 
796  This will get called by mathml_units_mixin._add_units_conversion if a special conversion is required by a nested sub-expression.
797  """
798  for from_units, to_units in self.special_conversions.iterkeys():
799  if (from_units.dimensionally_equivalent(defn_units)
800  and to_units.dimensionally_equivalent(desired_units)):
801  # We can apply this conversion
802  expr = self.special_conversions[(from_units, to_units)](expr)
803  DEBUG('units-converter', "Used nested special conversion from", repr(from_units), "to", repr(to_units))#, "giving", expr.xml())
804  break
805 # else:
806 # print "No on nested conv from", repr(from_units), "to", repr(to_units)
807  return expr
def CellMLToNektar.processors.UnitsConverter._check_special_conversion (   self,
  expr 
)
private
Check whether a special conversion applies to the given assignment.

Special conversions allow us to do units conversion between dimensionally non-equivalent
quantities, by utilising biological knowledge.  Available special conversions are added
using the add_special_conversion method.

Definition at line 808 of file processors.py.

References CellMLToNektar.utilities.DEBUG(), and CellMLToNektar.processors.UnitsConverter.special_conversions.

Referenced by CellMLToNektar.processors.UnitsConverter.convert_assignments(), and CellMLToNektar.processors.UnitsConverter.convert_constant().

809  def _check_special_conversion(self, expr):
810  """Check whether a special conversion applies to the given assignment.
811 
812  Special conversions allow us to do units conversion between dimensionally non-equivalent
813  quantities, by utilising biological knowledge. Available special conversions are added
814  using the add_special_conversion method.
815  """
816  lhs_units = expr.eq.lhs.get_units()
817  rhs_units = expr.eq.rhs.get_units()
818  if lhs_units.dimensionally_equivalent(rhs_units):
819  return
820  for from_units, to_units in self.special_conversions.iterkeys():
821  if (from_units.dimensionally_equivalent(rhs_units)
822  and to_units.dimensionally_equivalent(lhs_units)):
823  # We can apply this conversion
824  self.special_conversions[(from_units, to_units)](expr)
825  DEBUG('units-converter', "Used special conversion from", repr(from_units), "to", repr(to_units))#, "giving", expr.xml())
826  break
827 # else:
828 # print "No on conv from", repr(from_units), "to", repr(to_units)
def CellMLToNektar.processors.UnitsConverter._cleanup_logger (   self)
private
Flush logger & remove handler.

Definition at line 774 of file processors.py.

References CellMLToNektar.processors.UnitsConverter._log_handler.

Referenced by CellMLToNektar.processors.UnitsConverter.__del__().

775  def _cleanup_logger(self):
776  """Flush logger & remove handler."""
777  logger = logging.getLogger('units-converter')
778  self._log_handler.flush()
779  logger.removeHandler(self._log_handler)
def CellMLToNektar.processors.UnitsConverter._setup_logger (   self)
private

Definition at line 765 of file processors.py.

766  def _setup_logger(self):
767  logger = logging.getLogger('units-converter')
768  logger.setLevel(logging.WARNING)
769  formatter = logging.Formatter(fmt="%(name)s: %(message)s")
770  handler = logging.StreamHandler(sys.stderr)
771  handler.setFormatter(formatter)
772  logger.addHandler(handler)
773  self._log_handler = handler
def CellMLToNektar.processors.UnitsConverter.add_all_conversions (   self)
Add all units conversions required in the given model.

Definition at line 1011 of file processors.py.

References CellMLToNektar.processors.UnitsConverter.convert_assignments(), CellMLToNektar.processors.UnitsConverter.convert_mapping(), and CellMLToNektar.processors.ModelModifier.model.

1012  def add_all_conversions(self):
1013  """Add all units conversions required in the given model."""
1014  model = self.model
1015  # Mathematical expressions
1016  self.convert_assignments(model.get_assignments())
1017  # Connections
1018  for conn in getattr(model, u'connection', []):
1019  comp1 = model.get_component_by_name(conn.map_components.component_1)
1020  comp2 = model.get_component_by_name(conn.map_components.component_2)
1021  for mapping in conn.map_variables:
1022  var1 = model.get_variable_by_name(comp1.name, mapping.variable_1)
1023  var2 = model.get_variable_by_name(comp2.name, mapping.variable_2)
1024  self.convert_mapping(mapping, comp1, comp2, var1, var2)
1025  return
def CellMLToNektar.processors.UnitsConverter.add_conversions_for_component (   self,
  comp 
)
Add all units conversions required by the given component.

This allows us to only apply the conversions required by an interface component created
by an InterfaceGenerator.

Definition at line 987 of file processors.py.

References CellMLToNektar.processors.UnitsConverter._apply_special_conversion_for_nested_expr(), CellMLToNektar.processors.UnitsConverter.convert_assignments(), CellMLToNektar.processors.UnitsConverter.convert_mapping(), CellMLToNektar.processors.ModelModifier.model, and CellMLToNektar.processors.UnitsConverter.special_conversions.

988  def add_conversions_for_component(self, comp):
989  """Add all units conversions required by the given component.
990 
991  This allows us to only apply the conversions required by an interface component created
992  by an InterfaceGenerator.
993  """
994  model = self.model
995  if self.special_conversions:
996  self.model._cml_special_units_converter = self._apply_special_conversion_for_nested_expr
997  assignments = model.search_for_assignments(comp)
998  self.convert_assignments(assignments)
999  if self.special_conversions:
1000  del self.model._cml_special_units_converter
1001  for conn in getattr(model, u'connection', []):
1002  cname1 = conn.map_components.component_1
1003  cname2 = conn.map_components.component_2
1004  if comp.name in [cname1, cname2]:
1005  comp1 = model.get_component_by_name(cname1)
1006  comp2 = model.get_component_by_name(cname2)
1007  for mapping in conn.map_variables:
1008  var1 = model.get_variable_by_name(cname1, mapping.variable_1)
1009  var2 = model.get_variable_by_name(cname2, mapping.variable_2)
1010  self.convert_mapping(mapping, comp1, comp2, var1, var2)
def CellMLToNektar.processors.UnitsConverter.add_special_conversion (   self,
  from_units,
  to_units,
  converter 
)
Add a new special conversion to the list available.

Special conversions allow us to do units conversion between dimensionally non-equivalent
quantities, by utilising biological knowledge.  The function "converter" will be called with
an assignment (top-level mathml_apply instance) that has RHS units equivalent to from_units,
and LHS units equivalent to to_units.  It should alter the equation in-place (i.e. the
object passed to it must contain the final equation) to do an appropriate units conversion,
at least so that LHS and RHS dimensions match.

Definition at line 829 of file processors.py.

References CellMLToNektar.processors.UnitsConverter.special_conversions.

830  def add_special_conversion(self, from_units, to_units, converter):
831  """Add a new special conversion to the list available.
832 
833  Special conversions allow us to do units conversion between dimensionally non-equivalent
834  quantities, by utilising biological knowledge. The function "converter" will be called with
835  an assignment (top-level mathml_apply instance) that has RHS units equivalent to from_units,
836  and LHS units equivalent to to_units. It should alter the equation in-place (i.e. the
837  object passed to it must contain the final equation) to do an appropriate units conversion,
838  at least so that LHS and RHS dimensions match.
839  """
840  self.special_conversions[(from_units, to_units)] = converter
def CellMLToNektar.processors.UnitsConverter.convert_assignments (   self,
  exprs 
)
Apply conversions to any assignments in the given iterable.

Definition at line 889 of file processors.py.

References CellMLToNektar.processors.UnitsConverter._check_special_conversion(), CellMLToNektar.processors.UnitsConverter.special_conversions, and CellMLToNektar.processors.UnitsConverter.try_convert().

Referenced by CellMLToNektar.processors.UnitsConverter.add_all_conversions(), CellMLToNektar.processors.UnitsConverter.add_conversions_for_component(), and CellMLToNektar.processors.UnitsConverter.convert_mapping().

890  def convert_assignments(self, exprs):
891  """Apply conversions to any assignments in the given iterable."""
892  boolean = self.model.get_units_by_name('cellml:boolean')
893  for expr in exprs:
894  if isinstance(expr, mathml_apply):
895 # print 'Converting? assignment', element_xpath(expr)
896  if self.special_conversions:
897  self.try_convert(self._check_special_conversion, expr)
898  self.try_convert(expr._set_in_units, boolean)
def CellMLToNektar.processors.UnitsConverter.convert_connections (   self,
  connections 
)
Add units conversions for all connections in the given set.

:param connections: a set of variable pairs representing connections.  For each pair of variables a units conversion
will be added if needed and not already performed.

Definition at line 971 of file processors.py.

References CellMLToNektar.processors.UnitsConverter.convert_mapping(), and CellMLToNektar.processors.ModelModifier.model.

972  def convert_connections(self, connections):
973  """Add units conversions for all connections in the given set.
974 
975  :param connections: a set of variable pairs representing connections. For each pair of variables a units conversion
976  will be added if needed and not already performed.
977  """
978  model = self.model
979  for conn in getattr(model, u'connection', []):
980  comp1 = model.get_component_by_name(conn.map_components.component_1)
981  comp2 = model.get_component_by_name(conn.map_components.component_2)
982  for mapping in conn.map_variables:
983  var1 = model.get_variable_by_name(comp1.name, mapping.variable_1)
984  var2 = model.get_variable_by_name(comp2.name, mapping.variable_2)
985  if frozenset([var1, var2]) in connections:
986  self.convert_mapping(mapping, comp1, comp2, var1, var2)
def CellMLToNektar.processors.UnitsConverter.convert_constant (   self,
  value,
  from_units,
  to_units,
  comp 
)
Convert a constant value into desired units.

Definition at line 899 of file processors.py.

References CellMLToNektar.processors.UnitsConverter._check_special_conversion(), CellMLToNektar.processors.ModelModifier.add_expr_to_comp(), CellMLToNektar.processors.ModelModifier.add_units(), CellMLToNektar.processors.ModelModifier.model, CellMLToNektar.processors.ModelModifier.remove_expr(), CellMLToNektar.processors.UnitsConverter.special_conversions, and CellMLToNektar.processors.UnitsConverter.try_convert().

900  def convert_constant(self, value, from_units, to_units, comp):
901  """Convert a constant value into desired units."""
902  from_units = self.add_units(from_units)
903  to_units = self.add_units(to_units)
904  expr = mathml_apply.create_new(self.model, u'eq', [(u'0', to_units.name),
905  (unicode(value), from_units.name)])
906  self.add_expr_to_comp(comp, expr)
907  # Nasty hack to make expr.is_top_level return True
908  expr._cml_assigns_to = expr.operands().next()
909  if self.special_conversions:
910  self.try_convert(self._check_special_conversion, expr)
911  self.try_convert(expr.eq.rhs._set_in_units, to_units)
912  self.remove_expr(expr)
913  return expr.eq.rhs.evaluate()
def CellMLToNektar.processors.UnitsConverter.convert_mapping (   self,
  mapping,
  comp1,
  comp2,
  var1,
  var2 
)
Apply conversions to a mapping between two variables.

Definition at line 914 of file processors.py.

References CellMLToNektar.processors.UnitsConverter._converted_mappings, CellMLToNektar.processors.ModelModifier.add_expr_to_comp(), CellMLToNektar.processors.ModelModifier.add_variable(), CellMLToNektar.processors.UnitsConverter.convert_assignments(), CellMLToNektar.utilities.DEBUG(), and CellMLToNektar.processors.ModelModifier.model.

Referenced by CellMLToNektar.processors.UnitsConverter.add_all_conversions(), CellMLToNektar.processors.UnitsConverter.add_conversions_for_component(), and CellMLToNektar.processors.UnitsConverter.convert_connections().

915  def convert_mapping(self, mapping, comp1, comp2, var1, var2):
916  """Apply conversions to a mapping between two variables."""
917  model = self.model
918  # Check for being already converted
919  var_pair = frozenset([var1, var2])
920  if var_pair in self._converted_mappings:
921  DEBUG('units-converter', 'Skipping already converted mapping', var1, '<->', var2)
922  return
923  else:
924  self._converted_mappings.add(var_pair)
925  # Ensure mapping is var1 := var2; swap vars if needed
926  swapped = False
927  try:
928  if var2.get_source_variable() is var1:
929  swapped = True
930  var1, var2 = var2, var1
931  comp1, comp2 = comp2, comp1
932  except TypeError:
933  pass
934  # Get units
935  u1 = var1.get_units()
936  u2 = var2.get_units()
937  DEBUG('units-converter', "Converting mapping of", var1, ":=", var2,
938  "(units:", repr(u1), repr(u2), ")")
939  if not u1.equals(u2):
940  # We need a conversion
941  # Add a copy of var1 to comp1, with units as var2
942  if getattr(var1, u'public_interface', '') == u'in':
943  in_interface = u'public'
944  else:
945  in_interface = u'private'
946  var1_converter = self.add_variable(comp1, var1.name + u'_converter', u2, interfaces={in_interface: u'in'})
947  var1._cml_var_type = VarTypes.Computed
948  var1._cml_source_var = None
949  delattr(var1, in_interface + u'_interface')
950  var1_converter._set_source_variable(var2)
951  # Add assignment maths for var1 := var1_converter
952  app = mathml_apply.create_new(model, u'eq', [var1.name, var1_converter.name])
953  self.add_expr_to_comp(comp1, app)
954  var1._cml_depends_on = [app]
955  app._cml_assigns_to = var1
956  # Update mapping to var1_converter := var2
957  if swapped:
958  mapping.variable_2 = var1_converter.name
959  else:
960  mapping.variable_1 = var1_converter.name
961  # Fix usage counts - var1_converter is only used by app, and so var2 usage decreases
962  var1_converter._used()
963  for _ in xrange(var1.get_usage_count()):
964  var2._decrement_usage_count()
965  # Apply units conversion to the assignment
966  self.convert_assignments([app])
967  # Add the assignment into the sorted list
968  assignments = model.get_assignments()
969  idx = assignments.index(var1)
970  assignments[idx:idx+1] = [var1_converter, app]
def CellMLToNektar.processors.UnitsConverter.divide_rhs_by (   self,
  expr,
  var 
)
Helper method of use to special units conversions.

Will modify the given expr in-place, post-dividing the RHS by a reference to the given variable
object.
Connections and variables will be added to ensure that the given variable is available in the
component in which expr appears.

Returns expr, for ease of chaining expressions.

Definition at line 877 of file processors.py.

References CellMLToNektar.processors.UnitsConverter.modify_rhs().

878  def divide_rhs_by(self, expr, var):
879  """Helper method of use to special units conversions.
880 
881  Will modify the given expr in-place, post-dividing the RHS by a reference to the given variable
882  object.
883  Connections and variables will be added to ensure that the given variable is available in the
884  component in which expr appears.
885 
886  Returns expr, for ease of chaining expressions.
887  """
888  return self.modify_rhs(expr, u'divide', var)
def CellMLToNektar.processors.UnitsConverter.modify_rhs (   self,
  expr,
  operator,
  var 
)
Helper method of use to special units conversions.

Will modify the given expr in-place, replacing the RHS by an application of the given operator.
The operands will be the existing RHS and a ci element referencing the supplied variable object.
Connections and variables will be added to ensure that the given variable is available in the
component in which expr appears.

Returns expr, for ease of chaining expressions.

Definition at line 841 of file processors.py.

References CellMLToNektar.processors.ModelModifier.connect_variables().

Referenced by CellMLToNektar.processors.UnitsConverter.divide_rhs_by(), and CellMLToNektar.processors.UnitsConverter.times_rhs_by().

842  def modify_rhs(self, expr, operator, var):
843  """Helper method of use to special units conversions.
844 
845  Will modify the given expr in-place, replacing the RHS by an application of the given operator.
846  The operands will be the existing RHS and a ci element referencing the supplied variable object.
847  Connections and variables will be added to ensure that the given variable is available in the
848  component in which expr appears.
849 
850  Returns expr, for ease of chaining expressions.
851  """
852  assert isinstance(var, cellml_variable)
853  # Ensure var is available in expr's component
854  local_var_name = var.name
855  source_comp = var.component
856  expr_comp = expr.component
857  if source_comp != expr_comp:
858  local_var = self.connect_variables(var, (expr_comp.name, var.fullname(cellml=True)))
859  local_var_name = local_var.name
860  # Change expr
861  rhs = expr.eq.rhs
862  expr.safe_remove_child(rhs)
863  new_rhs = mathml_apply.create_new(var.model, operator, [rhs, local_var_name])
864  expr.xml_append(new_rhs)
865  return expr
def CellMLToNektar.processors.UnitsConverter.times_rhs_by (   self,
  expr,
  var 
)
Helper method of use to special units conversions.

Will modify the given expr in-place, post-multiplying the RHS by a reference to the given variable object.
Connections and variables will be added to ensure that the given variable is available in the
component in which expr appears.

Returns expr, for ease of chaining expressions.

Definition at line 866 of file processors.py.

References CellMLToNektar.processors.UnitsConverter.modify_rhs().

867  def times_rhs_by(self, expr, var):
868  """Helper method of use to special units conversions.
869 
870  Will modify the given expr in-place, post-multiplying the RHS by a reference to the given variable object.
871  Connections and variables will be added to ensure that the given variable is available in the
872  component in which expr appears.
873 
874  Returns expr, for ease of chaining expressions.
875  """
876  return self.modify_rhs(expr, u'times', var)
def CellMLToNektar.processors.UnitsConverter.try_convert (   self,
  func,
  args,
  kwargs 
)
Call the given function, and log any units errors produced.

Definition at line 780 of file processors.py.

References encode, CellMLToNektar.processors.UnitsConverter.show_xml_context_only, and CellMLToNektar.processors.UnitsConverter.warn_only.

Referenced by CellMLToNektar.processors.UnitsConverter.convert_assignments(), and CellMLToNektar.processors.UnitsConverter.convert_constant().

781  def try_convert(self, func, *args, **kwargs):
782  """Call the given function, and log any units errors produced."""
783  try:
784  func(*args, **kwargs)
785  except UnitsError, e:
786  if self.show_xml_context_only:
787  e.show_xml_context_only()
788  if self.warn_only:
789  e.warn = True
790  e.level = logging.WARNING
791  logging.getLogger('units-converter').log(e.level, unicode(e).encode('UTF-8'))
#define encode(otri)

Member Data Documentation

CellMLToNektar.processors.UnitsConverter._converted_mappings
private

Definition at line 760 of file processors.py.

Referenced by CellMLToNektar.processors.UnitsConverter.convert_mapping().

CellMLToNektar.processors.UnitsConverter._log_handler
private

Definition at line 772 of file processors.py.

Referenced by CellMLToNektar.processors.UnitsConverter._cleanup_logger().

CellMLToNektar.processors.UnitsConverter.show_xml_context_only

Definition at line 757 of file processors.py.

Referenced by CellMLToNektar.processors.UnitsConverter.try_convert().

CellMLToNektar.processors.UnitsConverter.special_conversions

Definition at line 758 of file processors.py.

Referenced by CellMLToNektar.processors.UnitsConverter._apply_special_conversion_for_nested_expr(), CellMLToNektar.processors.UnitsConverter._check_special_conversion(), CellMLToNektar.processors.UnitsConverter.add_conversions_for_component(), CellMLToNektar.processors.UnitsConverter.add_special_conversion(), CellMLToNektar.processors.UnitsConverter.convert_assignments(), and CellMLToNektar.processors.UnitsConverter.convert_constant().

CellMLToNektar.processors.UnitsConverter.warn_only

Definition at line 756 of file processors.py.

Referenced by CellMLToNektar.processors.UnitsConverter.try_convert().