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

Public Member Functions

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

 model
 
 connections_made
 

Private Member Functions

def _clear_model_caches (self)
 
def _make_connection (self, src_var, target_comp, target_vname)
 
def _find_connection_element (self, var1, var2)
 
def _create_connection_element (self, var1, var2)
 
def _update_connections (self, oldVar, newVar)
 
def _find_common_tail (self, l1, l2)
 
def _parent_path (self, comp)
 
def _process_operator (self, expr, operator, func, *args, **kwargs)
 
def _find_or_create_variable (self, cname, vname, source)
 
def _get_units_object (self, units)
 
def _uniquify_var_name (self, varname, comp)
 
def _uniquify_name (self, name, callable)
 
def _convert_initial_value (self, var, units, do_conversion=True)
 

Private Attributes

 _units_converter
 

Detailed Description

Base class supporting common model modification functionality.

This class contains the logic to deal with adding/deleting variables, components, equations, etc.
and connecting things up.  It also handles re-analysing the model when modifications have been
completed to ensure that PyCml's internal data structures are up-to-date.

Instances should be created with the model to modify as a single parameter.  Once all
modifications have been completed, the finalize method must be called to ensure later
processing of the model (e.g. code generation) will succeed.

Definition at line 47 of file processors.py.

Constructor & Destructor Documentation

◆ __init__()

def CellMLToNektar.processors.ModelModifier.__init__ (   self,
  model 
)
Constructor.

Reimplemented in CellMLToNektar.processors.InterfaceGenerator, and CellMLToNektar.processors.UnitsConverter.

Definition at line 58 of file processors.py.

58 def __init__(self, model):
59 """Constructor."""
60 self.model = model
61 self._units_converter = None
62 self.connections_made = set()
63

Member Function Documentation

◆ _clear_model_caches()

def CellMLToNektar.processors.ModelModifier._clear_model_caches (   self)
private
Clear cached links in the model, since we'll need to recompute many of them
once we've finished modifying it.  Also clears dependency information.

Definition at line 100 of file processors.py.

100 def _clear_model_caches(self):
101 """
102 Clear cached links in the model, since we'll need to recompute many of them
103 once we've finished modifying it. Also clears dependency information.
104 """
105 for comp in getattr(self.model, u'component', []):
106 for math in getattr(comp, u'math', []):
107 math._unset_cached_links()
108 for var in self.model.get_all_variables():
109 var.clear_dependency_info()
110 assignment_exprs = self.model.search_for_assignments()
111 for expr in assignment_exprs:
112 expr.clear_dependency_info()
113

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

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

◆ _convert_initial_value()

def CellMLToNektar.processors.ModelModifier._convert_initial_value (   self,
  var,
  units,
  do_conversion = True 
)
private
Convert any initial value of the given variable into the given units.

If there is no initial value, returns None.
If there is no units converter, leaves the initial_value unchanged.

Definition at line 513 of file processors.py.

513 def _convert_initial_value(self, var, units, do_conversion=True):
514 """Convert any initial value of the given variable into the given units.
515
516 If there is no initial value, returns None.
517 If there is no units converter, leaves the initial_value unchanged.
518 """
519 if not hasattr(var, u'initial_value'):
520 return None
521 value = var.initial_value
522 if value and self._units_converter and do_conversion:
523 if not var.get_units().equals(units):
524 try:
525 value = self._units_converter.convert_constant(value, var.get_units(), units, var.component)
526 except EvaluationError, e:
527 raise ModelModificationError("Cannot units-convert initial value as requires run-time information:\n"
528 + str(e))
529 return unicode(value)
530
531
532
def equals(self, other)
Definition: pycml.py:2634

References CellMLToNektar.processors.ModelModifier._units_converter, and CellMLToNektar.pycml.equals().

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

◆ _create_connection_element()

def CellMLToNektar.processors.ModelModifier._create_connection_element (   self,
  var1,
  var2 
)
private
Create a connection element connecting the given variables and add to the model.

If there's already a connection element for the relevant pair of components,
we just add another map_variables element to that.

Definition at line 249 of file processors.py.

249 def _create_connection_element(self, var1, var2):
250 """Create a connection element connecting the given variables and add to the model.
251
252 If there's already a connection element for the relevant pair of components,
253 we just add another map_variables element to that.
254 """
255 conn, swap = self._find_connection_element(var1, var2)
256 if conn:
257 if swap:
258 var1, var2 = var2, var1
259 else:
260 conn = var1.xml_create_element(u'connection', NSS[u'cml'])
261 mapc = var1.xml_create_element(u'map_components', NSS[u'cml'],
262 attributes={u'component_1': var1.component.name,
263 u'component_2': var2.component.name})
264 conn.xml_append(mapc)
265 self.model.xml_append(conn)
266 mapv = var1.xml_create_element(u'map_variables', NSS[u'cml'],
267 attributes={u'variable_1': var1.name,
268 u'variable_2': var2.name})
269 conn.xml_append(mapv)
270

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

Referenced by CellMLToNektar.processors.ModelModifier._make_connection().

◆ _find_common_tail()

def CellMLToNektar.processors.ModelModifier._find_common_tail (   self,
  l1,
  l2 
)
private
Find the first element at which both lists are identical from then on.

Definition at line 327 of file processors.py.

327 def _find_common_tail(self, l1, l2):
328 """Find the first element at which both lists are identical from then on."""
329 i = -1
330 try:
331 while l1[i] == l2[i]:
332 i -= 1
333 except IndexError:
334 # One list is the tail of the other
335 pass
336 # i now gives the last differing element
337 assert i < -1
338 return i+1
339

Referenced by CellMLToNektar.processors.ModelModifier.connect_variables().

◆ _find_connection_element()

def CellMLToNektar.processors.ModelModifier._find_connection_element (   self,
  var1,
  var2 
)
private
Find any connection element containing a connection of the given variables.

Returns a pair, the first element of which is either the element or None, and the
second of which is a boolean indicating whether the variables need to be swapped
in order to match the order of the components in the connection.

Definition at line 228 of file processors.py.

228 def _find_connection_element(self, var1, var2):
229 """Find any connection element containing a connection of the given variables.
230
231 Returns a pair, the first element of which is either the element or None, and the
232 second of which is a boolean indicating whether the variables need to be swapped
233 in order to match the order of the components in the connection.
234 """
235 cn1, cn2 = var1.component.name, var2.component.name
236 cnames = set([cn1, cn2])
237 for conn in getattr(self.model, u'connection', []):
238 mc = conn.map_components
239 if set([mc.component_1, mc.component_2]) == cnames:
240 break
241 else:
242 conn = None
243 if conn:
244 swap = conn.map_components.component_1 == cn2
245 else:
246 swap = False
247 return conn, swap
248

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

Referenced by CellMLToNektar.processors.ModelModifier._create_connection_element(), and CellMLToNektar.processors.ModelModifier.remove_connection().

◆ _find_or_create_variable()

def CellMLToNektar.processors.ModelModifier._find_or_create_variable (   self,
  cname,
  vname,
  source 
)
private
Find a given variable in the model, creating it if necessary.

We look for a variable in the component named cname with the same name as the source.
If it doesn't exist, a variable named vname will be created in that component (unless
it already exists).
The variable will become a mapped variable with the given source.
Hence if it is created it will have the same units.

Definition at line 359 of file processors.py.

359 def _find_or_create_variable(self, cname, vname, source):
360 """Find a given variable in the model, creating it if necessary.
361
362 We look for a variable in the component named cname with the same name as the source.
363 If it doesn't exist, a variable named vname will be created in that component (unless
364 it already exists).
365 The variable will become a mapped variable with the given source.
366 Hence if it is created it will have the same units.
367 """
368 try:
369 var = self.model.get_variable_by_name(cname, source.name)
370 raise KeyError()
371 except KeyError:
372 # Have we created it already?
373 try:
374 var = self.model.get_variable_by_name(cname, vname)
375 except KeyError:
376 # Create it and add to model
377 units = source.component.get_units_by_name(source.units)
378 var = self.add_variable(cname, vname, units)
379 return var
380

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

Referenced by CellMLToNektar.processors.ModelModifier._make_connection().

◆ _get_units_object()

def CellMLToNektar.processors.ModelModifier._get_units_object (   self,
  units 
)
private
Helper function to convert a units specification into a cellml_units object.

The input can be a cellml_units object, in which case we just return it.
However, it can also be a serialised CellML units definition, in which case it
will be parsed to create the object.

Definition at line 394 of file processors.py.

394 def _get_units_object(self, units):
395 """Helper function to convert a units specification into a cellml_units object.
396
397 The input can be a cellml_units object, in which case we just return it.
398 However, it can also be a serialised CellML units definition, in which case it
399 will be parsed to create the object.
400 """
401 if isinstance(units, cellml_units):
402 # We're done
403 pass
404 else:
405 units = amara_parse_cellml(unicode(units))
406 assert isinstance(units, cellml_units)
407 return units
408
def amara_parse_cellml(source, uri=None, prefixes=None)
Definition: pycml.py:191

References CellMLToNektar.pycml.amara_parse_cellml().

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

◆ _make_connection()

def CellMLToNektar.processors.ModelModifier._make_connection (   self,
  src_var,
  target_comp,
  target_vname 
)
private
Make a connection from a source variable to a given component and suggested local name.

Note that in the case that both variables already exist and are connected, the existing
connection is allowed to flow in either direction.

Definition at line 180 of file processors.py.

180 def _make_connection(self, src_var, target_comp, target_vname):
181 """Make a connection from a source variable to a given component and suggested local name.
182
183 Note that in the case that both variables already exist and are connected, the existing
184 connection is allowed to flow in either direction.
185 """
186 src_comp = src_var.component
187 target_var = self._find_or_create_variable(target_comp.name, target_vname, src_var)
188 # Sanity check the target variable
189 if (target_var.get_type() == VarTypes.Mapped
190 and target_var.get_source_variable(recurse=True) is src_var.get_source_variable(recurse=True)):
191# print "Connection exists between", src_var, "and target", target_var
192 return target_var
193 elif target_var.get_type() == VarTypes.Unknown:
194 # We've created this variable, so should be ok, but check for gotchas
195 assert not(hasattr(target_var, u'initial_value'))
196 if src_comp is target_comp.parent():
197 src_if = u'private'
198 target_if = u'public'
199 elif src_comp.parent() is target_comp:
200 src_if = u'public'
201 target_if = u'private'
202 else:
203 assert src_comp.parent() is target_comp.parent()
204 src_if = u'public'
205 target_if = u'public'
206 # One special case: if the src_var is actually obtained from a different
207 # component at this level or above, in which case we should use the real
208 # source, not that given.
209 if getattr(src_var, src_if + u'_interface', u'none') == u'in':
210 src_var = src_var.get_source_variable()
211 # Check and set the interface attributes
212# print "Connecting source", src_var, src_if, getattr(src_var, src_if + u'_interface', u'none'),
213# print "to", target_var, target_if, getattr(target_var, target_if + u'_interface', u'none')
214 assert getattr(src_var, src_if + u'_interface', u'none') != u'in'
215 assert getattr(target_var, target_if + u'_interface', u'none') != u'out'
216 src_var.xml_set_attribute((src_if + u'_interface', None), u'out')
217 target_var.xml_set_attribute((target_if + u'_interface', None), u'in')
218 # Create the connection element
219 self._create_connection_element(src_var, target_var)
220 self.connections_made.add(frozenset([src_var, target_var]))
221 # Ensure we handle a later connection attempt between these variables correctly
222 target_var._set_source_variable(src_var)
223 else:
224 # Naming conflict; try again with a different target name
225 return self._make_connection(src_var, target_comp, target_vname + u'_')
226 return target_var
227

References CellMLToNektar.processors.ModelModifier._create_connection_element(), CellMLToNektar.processors.ModelModifier._find_or_create_variable(), CellMLToNektar.processors.ModelModifier._make_connection(), and CellMLToNektar.processors.ModelModifier.connections_made.

Referenced by CellMLToNektar.processors.ModelModifier._make_connection(), and CellMLToNektar.processors.ModelModifier.connect_variables().

◆ _parent_path()

def CellMLToNektar.processors.ModelModifier._parent_path (   self,
  comp 
)
private
Return a path of components from that given to the encapsulation root.

The root is specified by None, since we're really dealing with a forest,
not a tree.

Definition at line 340 of file processors.py.

340 def _parent_path(self, comp):
341 """Return a path of components from that given to the encapsulation root.
342
343 The root is specified by None, since we're really dealing with a forest,
344 not a tree.
345 """
346 path = [comp]
347 while comp:
348 path.append(comp.parent())
349 comp = comp.parent()
350 return path
351

Referenced by CellMLToNektar.processors.ModelModifier.connect_variables().

◆ _process_operator()

def CellMLToNektar.processors.ModelModifier._process_operator (   self,
  expr,
  operator,
  func,
args,
**  kwargs 
)
private
Apply func to any application of the given operator within the given tree.

Definition at line 352 of file processors.py.

352 def _process_operator(self, expr, operator, func, *args, **kwargs):
353 """Apply func to any application of the given operator within the given tree."""
354 for elt in self.model.xml_element_children(expr):
355 self._process_operator(elt, operator, func, *args, **kwargs)
356 if isinstance(expr, mathml_apply) and expr.operator().localName == operator:
357 func(expr, *args, **kwargs)
358

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

Referenced by CellMLToNektar.processors.ModelModifier._process_operator(), and CellMLToNektar.processors.InterfaceGenerator._transform_derivatives_on_rhs().

◆ _uniquify_name()

def CellMLToNektar.processors.ModelModifier._uniquify_name (   self,
  name,
  callable 
)
private
Ensure the given name is unique within a particular context.

The context is determined by the given function: it will be passed candidate names to test
for existence, and is expected to throw iff the name is not already used.  Underscores will
be appended to the given name until callable throws, and the resulting unique name returned.

Definition at line 488 of file processors.py.

488 def _uniquify_name(self, name, callable):
489 """Ensure the given name is unique within a particular context.
490
491 The context is determined by the given function: it will be passed candidate names to test
492 for existence, and is expected to throw iff the name is not already used. Underscores will
493 be appended to the given name until callable throws, and the resulting unique name returned.
494 """
495 while True:
496 try:
497 callable(name)
498 name += u'_'
499 except:
500 break
501 return name
502

Referenced by CellMLToNektar.processors.ModelModifier._uniquify_var_name(), and CellMLToNektar.processors.ModelModifier.add_units().

◆ _uniquify_var_name()

def CellMLToNektar.processors.ModelModifier._uniquify_var_name (   self,
  varname,
  comp 
)
private
Ensure varname is unique within the given component.

Underscores will be appended to the name until it is unique.  The unique name will be returned.

Definition at line 481 of file processors.py.

481 def _uniquify_var_name(self, varname, comp):
482 """Ensure varname is unique within the given component.
483
484 Underscores will be appended to the name until it is unique. The unique name will be returned.
485 """
486 return self._uniquify_name(varname, comp.get_variable_by_name)
487

References CellMLToNektar.processors.ModelModifier._uniquify_name().

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

◆ _update_connections()

def CellMLToNektar.processors.ModelModifier._update_connections (   self,
  oldVar,
  newVar 
)
private
Change all variables connected to oldVar to be mapped to newVar instead.

Definition at line 314 of file processors.py.

314 def _update_connections(self, oldVar, newVar):
315 """Change all variables connected to oldVar to be mapped to newVar instead."""
316 vars = [v for v in self.model.get_all_variables() if v.get_source_variable(True) is oldVar]
317 # Remove old connections, including interfaces and types so creating the new connection works
318 for v in vars:
319 self.remove_connections(v)
320 self.del_attr(v, u'public_interface')
321 self.del_attr(v, u'private_interface')
322 v.clear_dependency_info()
323 # Create new connections
324 for v in vars:
325 self.connect_variables(newVar, v)
326

References CellMLToNektar.processors.ModelModifier.connect_variables(), CellMLToNektar.processors.ModelModifier.del_attr(), CellMLToNektar.processors.ModelModifier.model, CellMLToNektar.pycml.cellml_variable.model(), CellMLToNektar.pycml.mathml.model(), CellMLToNektar.translators.CellMLTranslator.model, and CellMLToNektar.processors.ModelModifier.remove_connections().

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

◆ add_expr_to_comp()

def CellMLToNektar.processors.ModelModifier.add_expr_to_comp (   self,
  comp,
  expr 
)
Add an expression to the mathematics in the given component.

comp may be a cellml_component instance or a component name.

Definition at line 434 of file processors.py.

434 def add_expr_to_comp(self, comp, expr):
435 """Add an expression to the mathematics in the given component.
436
437 comp may be a cellml_component instance or a component name.
438 """
439 if not isinstance(comp, cellml_component):
440 comp = self.model.get_component_by_name(comp)
441 if not hasattr(comp, u'math'):
442 # Create the math element
443 math = comp.xml_create_element(u'math', NSS[u'm'])
444 comp.xml_append(math)
445 # Append this expression
446 comp.math.xml_append(expr)
447

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

Referenced by CellMLToNektar.processors.InterfaceGenerator._split_ode(), CellMLToNektar.processors.InterfaceGenerator.add_output_function(), CellMLToNektar.processors.UnitsConverter.convert_constant(), CellMLToNektar.processors.UnitsConverter.convert_mapping(), and CellMLToNektar.processors.InterfaceGenerator.make_var_computed_constant().

◆ add_units()

def CellMLToNektar.processors.ModelModifier.add_units (   self,
  units 
)
Add a units definition to the model, if it doesn't already exist.

If the definition isn't in the model, at whole-model level, it will be added.  If the same
definition is already available, however, that definition should be used by preference.
Will return the actual units object to use.

Definition at line 409 of file processors.py.

409 def add_units(self, units):
410 """Add a units definition to the model, if it doesn't already exist.
411
412 If the definition isn't in the model, at whole-model level, it will be added. If the same
413 definition is already available, however, that definition should be used by preference.
414 Will return the actual units object to use.
415 """
416 units = self.model._get_units_obj(units)
417 try:
418 model_units = self.model.get_units_by_name(units.name)
419 except KeyError:
420 model_units = None
421 if model_units:
422 assert units.uniquify_tuple == model_units.uniquify_tuple
423 units = model_units
424 else:
425 units.name = self._uniquify_name(units.name, self.model.get_units_by_name)
426 self.model.add_units(units.name, units)
427 self.model.xml_append(units)
428 # Ensure referenced units exist
429 for unit in getattr(units, u'unit', []):
430 unit._set_units_element(self.add_units(unit.get_units_element()), override=True)
431 unit.units = unit.get_units_element().name
432 return units
433
def get_units_by_name(self, uname)
Definition: pycml.py:2725

References CellMLToNektar.processors.ModelModifier._uniquify_name(), CellMLToNektar.pycml.cellml_model.add_units(), CellMLToNektar.pycml.cellml_component.add_units(), CellMLToNektar.processors.ModelModifier.add_units(), CellMLToNektar.pycml.get_units_by_name(), CellMLToNektar.processors.ModelModifier.model, CellMLToNektar.pycml.cellml_variable.model(), CellMLToNektar.pycml.mathml.model(), and CellMLToNektar.translators.CellMLTranslator.model.

Referenced by CellMLToNektar.processors.ModelModifier.add_units(), CellMLToNektar.processors.ModelModifier.add_variable(), and CellMLToNektar.processors.UnitsConverter.convert_constant().

◆ add_variable()

def CellMLToNektar.processors.ModelModifier.add_variable (   self,
  comp,
  vname,
  units,
**  kwargs 
)
Add a new variable to the given component.

Remaining arguments are as for cellml_variable.create_new.
Returns the new variable object.

Definition at line 381 of file processors.py.

381 def add_variable(self, comp, vname, units, **kwargs):
382 """Add a new variable to the given component.
383
384 Remaining arguments are as for cellml_variable.create_new.
385 Returns the new variable object.
386 """
387 if not isinstance(comp, cellml_component):
388 comp = self.model.get_component_by_name(comp)
389 units = self.add_units(units)
390 var = cellml_variable.create_new(comp, vname, units.name, **kwargs)
391 comp._add_variable(var)
392 return var
393

References 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(), and CellMLToNektar.translators.CellMLTranslator.model.

Referenced by CellMLToNektar.processors.ModelModifier._find_or_create_variable(), CellMLToNektar.processors.InterfaceGenerator._split_ode(), CellMLToNektar.processors.InterfaceGenerator.add_input(), CellMLToNektar.processors.InterfaceGenerator.add_output(), CellMLToNektar.processors.InterfaceGenerator.add_output_function(), and CellMLToNektar.processors.UnitsConverter.convert_mapping().

◆ connect_variables()

def CellMLToNektar.processors.ModelModifier.connect_variables (   self,
  source,
  target 
)
Create a connection between the given source and target variables.

The variables are both specified either by a pair (cname,vname), or as cellml_variable objects.
The source variable must exist within the model, whereas the target might not, in
which case it will be created.

Note that in the case that both source and target exist, it might NOT be the case that
target obtains its value from source.  They might already be connected, and source obtains
its value from target.  Or they might both obtain their value from a common source.

If the variable names are not identical, any variables created will have the same name as the
target, if possible.  If there's an existing variable with that name, not connected to the
source, then underscores will be appended to the name to avoid conflicts.  Note that we do
check for variables in intermediate components that have the same name as the source and are
connected to it, to avoid adding unnecessary variables.

Returns the target variable object.

Definition at line 132 of file processors.py.

132 def connect_variables(self, source, target):
133 """Create a connection between the given source and target variables.
134
135 The variables are both specified either by a pair (cname,vname), or as cellml_variable objects.
136 The source variable must exist within the model, whereas the target might not, in
137 which case it will be created.
138
139 Note that in the case that both source and target exist, it might NOT be the case that
140 target obtains its value from source. They might already be connected, and source obtains
141 its value from target. Or they might both obtain their value from a common source.
142
143 If the variable names are not identical, any variables created will have the same name as the
144 target, if possible. If there's an existing variable with that name, not connected to the
145 source, then underscores will be appended to the name to avoid conflicts. Note that we do
146 check for variables in intermediate components that have the same name as the source and are
147 connected to it, to avoid adding unnecessary variables.
148
149 Returns the target variable object.
150 """
151 if isinstance(source, cellml_variable):
152 src_cname, src_vname = source.component.name, source.name
153 else:
154 src_cname, src_vname = source
155 if isinstance(target, cellml_variable):
156 target_cname, target_vname = target.component.name, target.name
157 else:
158 target_cname, target_vname = target
159 src_comp = self.model.get_component_by_name(src_cname)
160 target_comp = self.model.get_component_by_name(target_cname)
161 if src_comp == target_comp:
162 return target_comp.get_variable_by_name(target_vname)
163 # Determine encapsulation paths from target & source to the root
164 src_path = self._parent_path(src_comp)
165 target_path = self._parent_path(target_comp)
166 # At some point these will share a common path, even if it's just the root itself
167 meeting_index = self._find_common_tail(src_path, target_path)
168 # Construct path from source to target, leaving out the root (None)
169 path = src_path[:meeting_index]
170 if src_path[meeting_index]:
171 path.append(src_path[meeting_index])
172 path.extend(reversed(target_path[:meeting_index]))
173 # Traverse this path, adding connections at each step
174 next_src_var = src_comp.get_variable_by_name(src_vname)
175 for i, src_comp in enumerate(path[:-1]):
176 target_comp = path[i+1]
177 next_src_var = self._make_connection(next_src_var, target_comp, target_vname)
178 return next_src_var
179

References CellMLToNektar.processors.ModelModifier._find_common_tail(), CellMLToNektar.processors.ModelModifier._make_connection(), CellMLToNektar.processors.ModelModifier._parent_path(), 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(), CellMLToNektar.processors.ModelModifier._update_connections(), CellMLToNektar.processors.InterfaceGenerator.add_output(), and CellMLToNektar.processors.UnitsConverter.modify_rhs().

◆ create_new_component()

def CellMLToNektar.processors.ModelModifier.create_new_component (   self,
  cname 
)
Create a new component in the model, ensuring the name is unique.

If a component with name cname already exists,
underscores will be added to the component name to make it unique.

Definition at line 114 of file processors.py.

114 def create_new_component(self, cname):
115 """Create a new component in the model, ensuring the name is unique.
116
117 If a component with name cname already exists,
118 underscores will be added to the component name to make it unique.
119 """
120 while True:
121 try:
122 self.model.get_component_by_name(cname)
123 cname += u'_'
124 except KeyError:
125 # Component with this name doesn't exist
126 break
127 # Create the component
128 comp = cellml_component.create_new(self.model, cname)
129 self.model._add_component(comp)
130 return comp
131

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

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

◆ del_attr()

def CellMLToNektar.processors.ModelModifier.del_attr (   self,
  elt,
  localName,
  ns = None 
)
Delete an XML attribute from an element, if it exists.

Definition at line 474 of file processors.py.

474 def del_attr(self, elt, localName, ns=None):
475 """Delete an XML attribute from an element, if it exists."""
476 for (pyname, (qname, ns_)) in elt.xml_attributes.items():
477 _, name = SplitQName(qname)
478 if ns_ == ns and name == localName:
479 delattr(elt, pyname)
480

Referenced by CellMLToNektar.processors.ModelModifier._update_connections(), CellMLToNektar.processors.InterfaceGenerator.add_input(), CellMLToNektar.processors.InterfaceGenerator.add_output(), and CellMLToNektar.processors.ModelModifier.remove_definition().

◆ finalize()

def CellMLToNektar.processors.ModelModifier.finalize (   self,
  error_handler,
  pre_units_check_hook = None,
  check_units = True 
)
Re-do the model validation steps needed for further processing of the model.

Checks connections, etc. and builds up the dependency graph again, then performs
a topological sort.

If any errors are found during re-validation, the error_handler will be called with the
list.  Warnings are ignored.

TODO: figure out how to determine how much of this is actually needed - InterfaceGenerator
can probably get away with less work.

Reimplemented in CellMLToNektar.processors.InterfaceGenerator.

Definition at line 64 of file processors.py.

64 def finalize(self, error_handler, pre_units_check_hook=None, check_units=True):
65 """Re-do the model validation steps needed for further processing of the model.
66
67 Checks connections, etc. and builds up the dependency graph again, then performs
68 a topological sort.
69
70 If any errors are found during re-validation, the error_handler will be called with the
71 list. Warnings are ignored.
72
73 TODO: figure out how to determine how much of this is actually needed - InterfaceGenerator
74 can probably get away with less work.
75 """
76 self._clear_model_caches()
77 # We want to see any errors
78 logging_info = validator.CellMLValidator.setup_logging(show_errors=True, show_warnings=False)
79 # Re-run validation & analysis
80 self.model._check_variable_mappings()
81 if not self.model._cml_validation_errors:
82 assignment_exprs = self.model.search_for_assignments()
83 self.model._check_assigned_vars(assignment_exprs)
84 if not self.model._cml_validation_errors:
85 self.model._classify_variables(assignment_exprs)
86 self.model._order_variables(assignment_exprs)
87 if not self.model._cml_validation_errors and check_units:
88 if callable(pre_units_check_hook):
89 pre_units_check_hook()
90 self.model._check_connection_units(check_for_units_conversions=False)
91 self.model._check_dimensional_consistency(assignment_exprs,
92 xml_context=False,
93 warn_on_units_errors=self.model.get_option('warn_on_units_errors'),
94 check_for_units_conversions=False)
95 if self.model._cml_validation_errors:
96 error_handler(self.model._cml_validation_errors)
97 # Clear up logging
98 validator.CellMLValidator.cleanup_logging(logging_info)
99

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

◆ get_units_converter()

def CellMLToNektar.processors.ModelModifier.get_units_converter (   self)
Get the units converter object, if any has been set.

Definition at line 507 of file processors.py.

507 def get_units_converter(self):
508 """Get the units converter object, if any has been set."""
509 if not self._units_converter:
510 raise ModelModificationError("No units converter has been set.")
511 return self._units_converter
512

References CellMLToNektar.processors.ModelModifier._units_converter.

◆ remove_connection()

def CellMLToNektar.processors.ModelModifier.remove_connection (   self,
  var1,
  var2 
)
Remove a connection between two variables.

Removes the relevant map_variables element.
If this results in an empty connection element, removes that as well.

Definition at line 271 of file processors.py.

271 def remove_connection(self, var1, var2):
272 """Remove a connection between two variables.
273
274 Removes the relevant map_variables element.
275 If this results in an empty connection element, removes that as well.
276 """
277 conn, swap = self._find_connection_element(var1, var2)
278 if not conn:
279 raise ModelModificationError("Cannot remove non-existent connection.")
280 if swap:
281 var1, var2 = var2, var1
282 # Find the relevant map_variables element
283 mapv = conn.xml_xpath(u'cml:map_variables[@variable_1="%s" and @variable_2="%s"]'
284 % (var1.name, var2.name))
285 if not mapv:
286 raise ModelModificationError("Cannot remove non-existent connection.")
287 conn.xml_remove_child(mapv[0])
288 if not hasattr(conn, u'map_variables'):
289 conn.xml_parent.xml_remove_child(conn)
290

References CellMLToNektar.processors.ModelModifier._find_connection_element().

◆ remove_connections()

def CellMLToNektar.processors.ModelModifier.remove_connections (   self,
  var 
)
Remove all connection elements for the given variable.

Removes each relevant map_variables element.
If this results in an empty connection element, removes that as well.

Definition at line 291 of file processors.py.

291 def remove_connections(self, var):
292 """Remove all connection elements for the given variable.
293
294 Removes each relevant map_variables element.
295 If this results in an empty connection element, removes that as well.
296 """
297 cname, vname = var.component.name, var.name
298 for conn in list(getattr(self.model, u'connection', [])):
299 if cname == conn.map_components.component_1:
300 vid = u'variable_1'
301 elif cname == conn.map_components.component_2:
302 vid = u'variable_2'
303 else:
304 continue
305 for mapv in conn.map_variables:
306 if vname == getattr(mapv, vid, ''):
307 # Found a connection
308 conn.xml_remove_child(mapv)
309 if not hasattr(conn, u'map_variables'):
310 conn.xml_parent.xml_remove_child(conn)
311 # There can't be any more matching map_variables in this connection
312 break
313

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

Referenced by CellMLToNektar.processors.ModelModifier._update_connections().

◆ remove_definition()

def CellMLToNektar.processors.ModelModifier.remove_definition (   self,
  var,
  keep_initial_value = False 
)
Remove any existing definition (as an equation) of the given variable.

If keep_initial_value is False, then also remove any initial_value attribute.

If the variable is Mapped, throw a ModelModificationError.

Definition at line 456 of file processors.py.

456 def remove_definition(self, var, keep_initial_value=False):
457 """Remove any existing definition (as an equation) of the given variable.
458
459 If keep_initial_value is False, then also remove any initial_value attribute.
460
461 If the variable is Mapped, throw a ModelModificationError.
462 """
463 if var.get_type() == VarTypes.Mapped:
464 raise ModelModificationError("Cannot remove the equation defining a mapped variable - remove the definition of its source instead")
465 if not keep_initial_value:
466 self.del_attr(var, u'initial_value')
467 # Note: if this is a variable added by a protocol, then it shouldn't have
468 # any dependencies set up yet, so this is a no-op.
469 for dep in var.get_all_expr_dependencies():
470 self.remove_expr(dep)
471 # We know don't know how it will be defined
472 var.clear_dependency_info()
473

References CellMLToNektar.processors.ModelModifier.del_attr(), and CellMLToNektar.processors.ModelModifier.remove_expr().

Referenced by CellMLToNektar.processors.InterfaceGenerator.make_var_computed_constant(), and CellMLToNektar.processors.InterfaceGenerator.make_var_constant().

◆ remove_expr()

def CellMLToNektar.processors.ModelModifier.remove_expr (   self,
  expr 
)
Remove an expression (ODE or assignment) from its parent.

Definition at line 448 of file processors.py.

448 def remove_expr(self, expr):
449 """Remove an expression (ODE or assignment) from its parent."""
450 assert isinstance(expr, mathml_apply)
451 if expr.xml_parent:
452 expr.xml_parent.safe_remove_child(expr)
453 expr.xml_parent = None # Not done by Amara...
454 return expr
455

Referenced by CellMLToNektar.processors.InterfaceGenerator._split_ode(), CellMLToNektar.processors.UnitsConverter.convert_constant(), and CellMLToNektar.processors.ModelModifier.remove_definition().

◆ set_units_converter()

def CellMLToNektar.processors.ModelModifier.set_units_converter (   self,
  converter 
)
Set the object used to units-convert variable initial values.

Definition at line 503 of file processors.py.

503 def set_units_converter(self, converter):
504 """Set the object used to units-convert variable initial values."""
505 self._units_converter = converter
506

References CellMLToNektar.processors.ModelModifier._units_converter.

Member Data Documentation

◆ _units_converter

CellMLToNektar.processors.ModelModifier._units_converter
private

◆ connections_made

CellMLToNektar.processors.ModelModifier.connections_made

◆ model

CellMLToNektar.processors.ModelModifier.model

Definition at line 60 of file processors.py.

Referenced by CellMLToNektar.processors.InterfaceGenerator._add_all_odes_to_interface(), CellMLToNektar.processors.ModelModifier._clear_model_caches(), CellMLToNektar.processors.ModelModifier._create_connection_element(), CellMLToNektar.processors.ModelModifier._find_connection_element(), CellMLToNektar.processors.ModelModifier._find_or_create_variable(), CellMLToNektar.processors.ModelModifier._process_operator(), CellMLToNektar.pycml.reduce_commutative_nary._reduce(), CellMLToNektar.pycml.mathml_power._reduce(), CellMLToNektar.pycml.mathml_piecewise._set_in_units(), CellMLToNektar.pycml.cellml_variable._set_source_variable(), CellMLToNektar.processors.InterfaceGenerator._split_ode(), CellMLToNektar.processors.InterfaceGenerator._transform_derivatives_on_rhs(), CellMLToNektar.processors.ModelModifier._update_connections(), CellMLToNektar.processors.UnitsConverter.add_all_conversions(), CellMLToNektar.processors.UnitsConverter.add_conversions_for_component(), CellMLToNektar.processors.ModelModifier.add_expr_to_comp(), CellMLToNektar.processors.InterfaceGenerator.add_output_function(), CellMLToNektar.pycml.cellml_variable.add_rdf_annotation(), CellMLToNektar.processors.ModelModifier.add_units(), CellMLToNektar.processors.ModelModifier.add_variable(), CellMLToNektar.translators.CellMLTranslator.calculate_extended_dependencies(), CellMLToNektar.pycml.mathml_apply.classify_variables(), CellMLToNektar.CellMLToNektarTranslator.CellMLToNektarTranslator.code_name(), CellMLToNektar.processors.ModelModifier.connect_variables(), CellMLToNektar.processors.UnitsConverter.convert_assignments(), CellMLToNektar.processors.UnitsConverter.convert_connections(), CellMLToNektar.processors.UnitsConverter.convert_constant(), CellMLToNektar.processors.UnitsConverter.convert_mapping(), CellMLToNektar.processors.ModelModifier.create_new_component(), CellMLToNektar.processors.ModelModifier.finalize(), CellMLToNektar.pycml.mathml.get_component(), CellMLToNektar.processors.InterfaceGenerator.get_interface_component(), CellMLToNektar.pycml.cellml_variable.get_rdf_annotation(), CellMLToNektar.pycml.cellml_variable.get_rdf_annotations(), CellMLToNektar.pycml.mathml_apply.get_units(), CellMLToNektar.pycml.mathml_piecewise.get_units(), CellMLToNektar.pycml.cellml_variable.is_statically_const(), CellMLToNektar.processors.InterfaceGenerator.make_var_computed_constant(), CellMLToNektar.CellMLToNektarTranslator.CellMLToNektarTranslator.output_backward_euler_mathematics(), CellMLToNektar.CellMLToNektarTranslator.CellMLToNektarTranslator.output_constructor(), CellMLToNektar.CellMLToNektarTranslator.CellMLToNektarTranslator.output_default_stimulus(), CellMLToNektar.translators.CellMLTranslator.output_equations(), CellMLToNektar.CellMLToNektarTranslator.CellMLToNektarTranslator.output_equations(), CellMLToNektar.CellMLToNektarTranslator.CellMLToNektarTranslator.output_get_i_ionic(), CellMLToNektar.CellMLToNektarTranslator.CellMLToNektarTranslator.output_includes(), CellMLToNektar.translators.CellMLTranslator.output_mathematics(), CellMLToNektar.CellMLToNektarTranslator.CellMLToNektarTranslator.output_model_attributes(), CellMLToNektar.CellMLToNektarTranslator.CellMLToNektarTranslator.output_top_boilerplate(), CellMLToNektar.translators.CellMLTranslator.output_top_boilerplate(), CellMLToNektar.CellMLToNektarTranslator.CellMLToNektarTranslator.output_verify_state_variables(), CellMLToNektar.processors.ModelModifier.remove_connections(), CellMLToNektar.pycml.cellml_variable.remove_rdf_annotations(), CellMLToNektar.translators.CellMLTranslator.var_display_name(), and CellMLToNektar.translators.CellMLTranslator.varobj().