Nektar++
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:
[legend]

Public Member Functions

def __init__ (self, model, warn_only=None, show_xml_context_only=False)
 
def __del__ (self)
 
def try_convert (self, func, *args, **kwargs)
 
def add_special_conversion (self, from_units, to_units, converter)
 
def modify_rhs (self, expr, operator, var)
 
def times_rhs_by (self, expr, var)
 
def divide_rhs_by (self, expr, var)
 
def convert_assignments (self, exprs)
 
def convert_constant (self, value, from_units, to_units, comp)
 
def convert_mapping (self, mapping, comp1, comp2, var1, var2)
 
def convert_connections (self, connections)
 
def add_conversions_for_component (self, comp)
 
def add_all_conversions (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)
 

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 (self)
 
def _cleanup_logger (self)
 
def _apply_special_conversion_for_nested_expr (self, expr, defn_units, desired_units)
 
def _check_special_conversion (self, expr)
 

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

◆ __init__()

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

Reimplemented from CellMLToNektar.processors.ModelModifier.

Definition at line 752 of file processors.py.

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

References CellMLToNektar.processors.UnitsConverter.__init__().

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

◆ __del__()

def CellMLToNektar.processors.UnitsConverter.__del__ (   self)

Definition at line 762 of file processors.py.

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

References CellMLToNektar.processors.UnitsConverter._cleanup_logger().

Member Function Documentation

◆ _apply_special_conversion_for_nested_expr()

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.

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

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

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

◆ _check_special_conversion()

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.

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

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

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

◆ _cleanup_logger()

def CellMLToNektar.processors.UnitsConverter._cleanup_logger (   self)
private
Flush logger & remove handler.

Definition at line 774 of file processors.py.

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

References CellMLToNektar.processors.UnitsConverter._log_handler.

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

◆ _setup_logger()

def CellMLToNektar.processors.UnitsConverter._setup_logger (   self)
private

Definition at line 765 of file processors.py.

765 def _setup_logger(self):
766 logger = logging.getLogger('units-converter')
767 logger.setLevel(logging.WARNING)
768 formatter = logging.Formatter(fmt="%(name)s: %(message)s")
769 handler = logging.StreamHandler(sys.stderr)
770 handler.setFormatter(formatter)
771 logger.addHandler(handler)
772 self._log_handler = handler
773

◆ add_all_conversions()

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.

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

References CellMLToNektar.processors.UnitsConverter.convert_assignments(), CellMLToNektar.processors.UnitsConverter.convert_mapping(), CellMLToNektar.processors.ModelModifier.model, CellMLToNektar.pycml.cellml_variable.model(), CellMLToNektar.pycml.mathml.model(), and CellMLToNektar.translators.CellMLTranslator.model.

◆ add_conversions_for_component()

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.

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

References CellMLToNektar.processors.UnitsConverter._apply_special_conversion_for_nested_expr(), CellMLToNektar.processors.UnitsConverter.convert_assignments(), CellMLToNektar.processors.UnitsConverter.convert_mapping(), CellMLToNektar.processors.ModelModifier.model, CellMLToNektar.pycml.cellml_variable.model(), CellMLToNektar.pycml.mathml.model(), CellMLToNektar.translators.CellMLTranslator.model, and CellMLToNektar.processors.UnitsConverter.special_conversions.

◆ add_special_conversion()

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.

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

References CellMLToNektar.processors.UnitsConverter.special_conversions.

◆ convert_assignments()

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.

889 def convert_assignments(self, exprs):
890 """Apply conversions to any assignments in the given iterable."""
891 boolean = self.model.get_units_by_name('cellml:boolean')
892 for expr in exprs:
893 if isinstance(expr, mathml_apply):
894# print 'Converting? assignment', element_xpath(expr)
895 if self.special_conversions:
896 self.try_convert(self._check_special_conversion, expr)
897 self.try_convert(expr._set_in_units, boolean)
898
def get_units_by_name(self, uname)
Definition: pycml.py:2725

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

◆ convert_connections()

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.

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

References CellMLToNektar.processors.UnitsConverter.convert_mapping(), CellMLToNektar.processors.ModelModifier.model, CellMLToNektar.pycml.cellml_variable.model(), CellMLToNektar.pycml.mathml.model(), and CellMLToNektar.translators.CellMLTranslator.model.

◆ convert_constant()

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.

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

References CellMLToNektar.processors.UnitsConverter._check_special_conversion(), CellMLToNektar.processors.ModelModifier.add_expr_to_comp(), CellMLToNektar.pycml.cellml_model.add_units(), CellMLToNektar.pycml.cellml_component.add_units(), CellMLToNektar.processors.ModelModifier.add_units(), CellMLToNektar.processors.ModelModifier.model, CellMLToNektar.pycml.cellml_variable.model(), CellMLToNektar.pycml.mathml.model(), CellMLToNektar.translators.CellMLTranslator.model, CellMLToNektar.processors.ModelModifier.remove_expr(), CellMLToNektar.processors.UnitsConverter.special_conversions, and CellMLToNektar.processors.UnitsConverter.try_convert().

◆ convert_mapping()

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.

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

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

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

◆ divide_rhs_by()

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.

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

References CellMLToNektar.processors.UnitsConverter.modify_rhs().

◆ modify_rhs()

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.

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

References CellMLToNektar.processors.ModelModifier.connect_variables().

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

◆ times_rhs_by()

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.

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

References CellMLToNektar.processors.UnitsConverter.modify_rhs().

◆ try_convert()

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.

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

References tinysimd.log(), CellMLToNektar.processors.UnitsConverter.show_xml_context_only, CellMLToNektar.pycml.MathsError.show_xml_context_only(), and CellMLToNektar.processors.UnitsConverter.warn_only.

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

Member Data Documentation

◆ _converted_mappings

CellMLToNektar.processors.UnitsConverter._converted_mappings
private

◆ _log_handler

CellMLToNektar.processors.UnitsConverter._log_handler
private

◆ show_xml_context_only

CellMLToNektar.processors.UnitsConverter.show_xml_context_only

Definition at line 757 of file processors.py.

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

◆ special_conversions

CellMLToNektar.processors.UnitsConverter.special_conversions

◆ warn_only

CellMLToNektar.processors.UnitsConverter.warn_only

Definition at line 756 of file processors.py.

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