myokit 1.37.5__py3-none-any.whl → 1.39.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. myokit/__init__.py +5 -0
  2. myokit/_datablock.py +6 -5
  3. myokit/_expressions.py +6 -1
  4. myokit/_model_api.py +44 -18
  5. myokit/_myokit_version.py +1 -1
  6. myokit/_parsing.py +8 -2
  7. myokit/_sim/cvodessim.py +26 -0
  8. myokit/formats/__init__.py +37 -0
  9. myokit/formats/ansic/_ewriter.py +1 -1
  10. myokit/formats/axon/_abf.py +43 -9
  11. myokit/formats/cellml/v1/__init__.py +5 -5
  12. myokit/formats/cellml/v1/_api.py +220 -122
  13. myokit/formats/cellml/v1/_parser.py +91 -87
  14. myokit/formats/cellml/v1/_writer.py +13 -6
  15. myokit/formats/cellml/v2/__init__.py +5 -8
  16. myokit/formats/cellml/v2/_api.py +182 -106
  17. myokit/formats/cellml/v2/_parser.py +68 -64
  18. myokit/formats/cellml/v2/_writer.py +7 -3
  19. myokit/formats/heka/_patchmaster.py +71 -14
  20. myokit/formats/mathml/_parser.py +106 -67
  21. myokit/gui/source.py +18 -12
  22. myokit/lib/hh.py +21 -37
  23. myokit/tests/test_cellml_v1_api.py +227 -33
  24. myokit/tests/test_cellml_v1_parser.py +48 -17
  25. myokit/tests/test_cellml_v1_writer.py +14 -4
  26. myokit/tests/test_cellml_v2_api.py +132 -114
  27. myokit/tests/test_cellml_v2_parser.py +31 -1
  28. myokit/tests/test_cellml_v2_writer.py +8 -1
  29. myokit/tests/test_datalog.py +17 -0
  30. myokit/tests/test_expressions.py +61 -0
  31. myokit/tests/test_formats.py +99 -0
  32. myokit/tests/test_formats_mathml_content.py +97 -37
  33. myokit/tests/test_formats_python.py +1 -1
  34. myokit/tests/test_model_building.py +2 -0
  35. myokit/tests/test_parsing.py +32 -0
  36. myokit/tests/test_simulation_cvodes.py +10 -4
  37. myokit/tests/test_variable.py +10 -7
  38. {myokit-1.37.5.dist-info → myokit-1.39.0.dist-info}/METADATA +22 -7
  39. {myokit-1.37.5.dist-info → myokit-1.39.0.dist-info}/RECORD +43 -43
  40. {myokit-1.37.5.dist-info → myokit-1.39.0.dist-info}/WHEEL +1 -1
  41. {myokit-1.37.5.dist-info → myokit-1.39.0.dist-info}/entry_points.txt +0 -0
  42. {myokit-1.37.5.dist-info → myokit-1.39.0.dist-info/licenses}/LICENSE.txt +0 -0
  43. {myokit-1.37.5.dist-info → myokit-1.39.0.dist-info}/top_level.txt +0 -0
@@ -52,9 +52,9 @@ class CellMLParsingError(myokit.ImportError):
52
52
  """
53
53
  def __init__(self, message, element=None):
54
54
  if element is not None:
55
- try: # pragma: no cover
55
+ try:
56
56
  line = str(element.sourceline)
57
- message = 'Error on line ' + line + '. ' + message
57
+ message = f'Error on line {line}. {message}'
58
58
  except AttributeError:
59
59
  pass
60
60
  super().__init__(message)
@@ -91,7 +91,7 @@ class CellMLParser:
91
91
  if element.text is not None:
92
92
  if element.text.strip():
93
93
  raise CellMLParsingError(
94
- 'Text found in ' + self._tag(element, name) + '.', element)
94
+ f'Text found in {self._tag(element, name)}.', element)
95
95
 
96
96
  # Not extension namespaces
97
97
  not_ext_ns = (
@@ -108,9 +108,8 @@ class CellMLParser:
108
108
  # Check for trailing text
109
109
  if child.tail is not None and child.tail.strip():
110
110
  raise CellMLParsingError(
111
- 'Text found in ' + self._tag(element, name)
112
- + ' (after ' + self._tag(child) + ' element).',
113
- child)
111
+ f'Text found in {self._tag(element, name)} (after'
112
+ f' {self._tag(child)} element).', child)
114
113
 
115
114
  # Check if allowed
116
115
  if str(child.tag) in allowed:
@@ -120,8 +119,8 @@ class CellMLParser:
120
119
  ns = split(child.tag)[0]
121
120
  if ns in not_ext_ns:
122
121
  raise CellMLParsingError(
123
- 'Unexpected content type in ' + self._tag(element, name)
124
- + ', found element of type ' + self._tag(child) + '.',
122
+ f'Unexpected content type in {self._tag(element, name)},'
123
+ f' found element of type {self._tag(child)}.',
125
124
  child)
126
125
  else:
127
126
  # Check if CellML appearing in non-CellML elements
@@ -145,8 +144,8 @@ class CellMLParser:
145
144
  if key not in allowed:
146
145
  key = self._item(ns, at)
147
146
  raise CellMLParsingError(
148
- 'Unexpected attribute ' + key + ' found in '
149
- + self._tag(element, name) + '.', element)
147
+ f'Unexpected attribute {key} found in'
148
+ f' {self._tag(element, name)}.', element)
150
149
 
151
150
  def _check_for_cellml_in_extensions(self, element):
152
151
  """
@@ -158,17 +157,15 @@ class CellMLParser:
158
157
  ns, at = split(key)
159
158
  if ns == self._ns:
160
159
  raise CellMLParsingError(
161
- 'CellML attribute ' + self._item(ns, at) + ' found'
162
- ' in extension element ' + self._tag(element)
163
- + ' (2.4.3).', element)
160
+ f'CellML attribute {self._item(ns, at)} found in extension'
161
+ f' element {self._tag(element)} (2.4.3).', element)
164
162
 
165
163
  # Check if this element has CellML children
166
164
  for child in element:
167
165
  if split(child.tag)[0] == self._ns:
168
166
  raise CellMLParsingError(
169
- 'CellML element ' + self._tag(child) + ' found inside'
170
- ' extension element ' + self._tag(element) + ' (2.4.3).',
171
- child)
167
+ f'CellML element {self._tag(child)} found inside'
168
+ f' extension element {self._tag(element)} (2.4.3).', child)
172
169
 
173
170
  # Recurse into children
174
171
  self._check_for_cellml_in_extensions(child)
@@ -193,7 +190,7 @@ class CellMLParser:
193
190
  # Check uniqueness
194
191
  if cmeta_id in self._cmeta_ids:
195
192
  raise CellMLParsingError(
196
- 'Duplicate cmeta:id "' + cmeta_id + '" (8.5.1).', element)
193
+ f'Duplicate cmeta:id "{cmeta_id}" (8.5.1).', element)
197
194
 
198
195
  # Store and return
199
196
  self._cmeta_ids.add(cmeta_id)
@@ -255,23 +252,21 @@ class CellMLParser:
255
252
  if ns is None:
256
253
  return item
257
254
  elif ns == self._ns:
258
- return 'cellml:' + item
255
+ return f'cellml:{item}'
259
256
  elif ns == cellml.NS_MATHML:
260
- return 'mathml:' + item
257
+ return f'mathml:{item}'
261
258
  elif ns == cellml.NS_RDF:
262
- return 'rdf:' + item
259
+ return f'rdf:{item}'
263
260
  elif ns == cellml.NS_CMETA:
264
- return 'cmeta:' + item
261
+ return f'cmeta:{item}'
265
262
  else:
266
- return '{' + ns + '}' + item
263
+ return f'{{{ns}}}{item}'
267
264
 
268
265
  def _join(self, element, namespace=None):
269
266
  """
270
267
  Joins a ``namespace`` and an ``element`` string into a single string.
271
268
  """
272
- if namespace is None:
273
- namespace = self._ns
274
- return '{' + namespace + '}' + element
269
+ return f'{{{self._ns if namespace is None else namespace}}}{element}'
275
270
 
276
271
  def parse(self, root):
277
272
  """
@@ -301,7 +296,7 @@ class CellMLParser:
301
296
  parser = etree.XMLParser(remove_comments=True)
302
297
  tree = etree.parse(path, parser=parser)
303
298
  except Exception as e:
304
- raise CellMLParsingError('Unable to parse XML: ' + str(e))
299
+ raise CellMLParsingError(f'Unable to parse XML: {e}')
305
300
 
306
301
  # Parse content
307
302
  return self.parse(tree.getroot())
@@ -316,7 +311,7 @@ class CellMLParser:
316
311
  try:
317
312
  root = etree.fromstring(text)
318
313
  except Exception as e:
319
- raise CellMLParsingError('Unable to parse XML: ' + str(e))
314
+ raise CellMLParsingError(f'Unable to parse XML: {e}')
320
315
 
321
316
  # Parse content
322
317
  return self.parse(root)
@@ -358,9 +353,19 @@ class CellMLParser:
358
353
  for child in self._sort_units(element, model):
359
354
  self._parse_units(child, component)
360
355
 
361
- # Create variables and set interfaces
356
+ # Create variables, set interfaces, prepare to set initial values
357
+ initial_values = []
362
358
  for child in element.findall(self._join('variable')):
363
- self._parse_variable(child, component)
359
+ init = self._parse_variable(child, component)
360
+ if init is not None:
361
+ initial_values.append(init)
362
+
363
+ # Set initial values
364
+ for child, variable, value in initial_values:
365
+ try:
366
+ variable.set_initial_value(value)
367
+ except myokit.formats.cellml.v1.CellMLError as e:
368
+ raise CellMLParsingError(str(e), child)
364
369
 
365
370
  def _parse_connection(self, element, model, connected):
366
371
  """
@@ -375,7 +380,7 @@ class CellMLParser:
375
380
  if len(map_components) != 1:
376
381
  raise CellMLParsingError(
377
382
  'A connection must contain exactly one map_components element,'
378
- ' found ' + str(len(map_components)) + ' (3.4.4.1).', element)
383
+ f' found {len(map_components)} (3.4.4.1).', element)
379
384
 
380
385
  # Check at least one map_variables is present
381
386
  map_variables = element.findall(self._join('map_variables'))
@@ -421,8 +426,8 @@ class CellMLParser:
421
426
  if c1 == c2:
422
427
  raise CellMLParsingError(
423
428
  'The component_1 and component_2 attributes in a'
424
- ' map_components element must be different, got "' + str(c1)
425
- + '" twice (3.4.5.4).', element)
429
+ f' map_components element must be different, got "{c1}"'
430
+ ' twice (3.4.5.4).', element)
426
431
 
427
432
  # Get components
428
433
  try:
@@ -430,22 +435,22 @@ class CellMLParser:
430
435
  except KeyError:
431
436
  raise CellMLParsingError(
432
437
  'A map_components component_1 attribute must refer to a'
433
- ' component in the current model, got "' + str(c1)
434
- + '" (3.4.5.2).', element)
438
+ f' component in the current model, got "{c1}" (3.4.5.2).',
439
+ element)
435
440
  try:
436
441
  c2 = model.component(c2)
437
442
  except KeyError:
438
443
  raise CellMLParsingError(
439
444
  'A map_components component_2 attribute must refer to a'
440
- ' component in the current model, got "' + str(c2)
441
- + '" (3.4.5.3).', element)
445
+ f' component in the current model, got "{c2}" (3.4.5.3).',
446
+ element)
442
447
 
443
448
  # Check components are not yet connected
444
449
  if (c1, c2) in connected:
445
450
  raise CellMLParsingError(
446
451
  'Each connection in a model must connect a unique pair of'
447
- ' components, found multiple for "' + c1.name() + '" and "'
448
- + c2.name() + '" (3.4.5.4).', element)
452
+ f' components, found multiple for "{c1.name()}" and'
453
+ f' "{c2.name()}" (3.4.5.4).', element)
449
454
  connected.add((c1, c2))
450
455
  connected.add((c2, c1))
451
456
 
@@ -484,15 +489,13 @@ class CellMLParser:
484
489
  except KeyError:
485
490
  raise CellMLParsingError(
486
491
  'A map_variables variable_1 attribute must refer to a'
487
- ' variable in component_1, got "' + str(v1) + '" (3.4.6.2).',
488
- element)
492
+ f' variable in component_1, got "{v1}" (3.4.6.2).', element)
489
493
  try:
490
494
  v2 = c2.variable(v2)
491
495
  except KeyError:
492
496
  raise CellMLParsingError(
493
497
  'A map_variables variable_2 attribute must refer to a'
494
- ' variable in component_2, got "' + str(v1) + '" (3.4.6.3).',
495
- element)
498
+ f' variable in component_2, got "{v1}" (3.4.6.3).', element)
496
499
 
497
500
  # Connect variables
498
501
  model = c1.model()
@@ -515,7 +518,7 @@ class CellMLParser:
515
518
  text = self.flatten(element)
516
519
  if text:
517
520
  if 'documentation' in model.meta:
518
- model.meta['documentation'] += '\n\n' + text
521
+ model.meta['documentation'] += f'\n\n{text}'
519
522
  else:
520
523
  model.meta['documentation'] = text
521
524
 
@@ -577,8 +580,8 @@ class CellMLParser:
577
580
  except KeyError:
578
581
  raise CellMLParsingError(
579
582
  'A component_ref\'s component attribute must reference a'
580
- ' component in the same model, got "' + component
581
- + '" (6.4.3.3).', element)
583
+ f' component in the same model, got "{component}" (6.4.3.3).',
584
+ element)
582
585
 
583
586
  # Check allowed content
584
587
  self._check_allowed_content(element, ['component_ref'], ['component'])
@@ -591,9 +594,8 @@ class CellMLParser:
591
594
  if component.parent() is not None:
592
595
  raise CellMLParsingError(
593
596
  'A component can only have a single encapsulation parent:'
594
- ' found ' + str(component) + ' with parents '
595
- + str(component.parent()) + ' and ' + str(parent)
596
- + ' (6.4.3.2).', element)
597
+ f' found {component} with parents {component.parent()} and'
598
+ f' {parent} (6.4.3.2).', element)
597
599
 
598
600
  # Set parent (won't raise CellMLErrors)
599
601
  component.set_parent(parent)
@@ -642,7 +644,7 @@ class CellMLParser:
642
644
  # Check type (only if in null namespace)
643
645
  if ns is None and rel not in ['encapsulation', 'containment']:
644
646
  raise CellMLParsingError(
645
- 'Unknown relationship type: "' + rel + '", expecting either'
647
+ f'Unknown relationship type: "{rel}", expecting either'
646
648
  ' "encapsulation" or "containment" (6.4.2.2).', element)
647
649
 
648
650
  # Check name, if given
@@ -653,11 +655,11 @@ class CellMLParser:
653
655
  'Encapsulation relationships may not define a name'
654
656
  ' attribute (6.4.2.4).', element)
655
657
 
656
- if not myokit.formats.cellml.v1.is_valid_identifier(name):
658
+ if not myokit.formats.cellml.v1.is_identifier(name):
657
659
  raise CellMLParsingError(
658
660
  'Relationship_ref name must be a valid CellML identifier,'
659
- ' but found "' + name + '" (6.4.2.3).', element)
660
- rel += ', ' + name
661
+ f' but found "{name}" (6.4.2.3).', element)
662
+ rel = f'{rel}, {name}'
661
663
 
662
664
  # Check uniqueness of relationship (only in null namespace)
663
665
  if ns is None and rel in relationships:
@@ -701,7 +703,7 @@ class CellMLParser:
701
703
  units = element.attrib[attr]
702
704
  except KeyError:
703
705
  raise CellMLParsingError(
704
- 'Numbers inside MathML must define a cellml:units'
706
+ 'Numbers inside mathml:math must define a cellml:units'
705
707
  ' attribute (4.4.3.1).', element)
706
708
 
707
709
  # Find units in component
@@ -710,14 +712,14 @@ class CellMLParser:
710
712
  units = units.myokit_unit()
711
713
  except myokit.formats.cellml.v1.UnitsError as e:
712
714
  warnings.warn(
713
- 'The units "' + str(units) + '" (referenced inside a'
714
- ' MathML equation) are not supported and have been'
715
- ' replaced by `dimensionless`. (' + str(e) + ')')
715
+ f'The units "{units}" (referenced inside a MathML'
716
+ ' equation) are not supported and have been replaced by'
717
+ f' `dimensionless`. ({e})')
716
718
  units = myokit.units.dimensionless
717
719
  except myokit.formats.cellml.v1.CellMLError:
718
720
  raise CellMLParsingError(
719
- 'Unknown unit "' + str(units) + '" referenced inside a'
720
- ' MathML equation (4.4.3.2).', element)
721
+ f'Unknown units "{units}" referenced inside a MathML'
722
+ ' equation (4.4.3.2).', element)
721
723
 
722
724
  # Create and return
723
725
  return myokit.Number(value, units)
@@ -737,8 +739,8 @@ class CellMLParser:
737
739
  if ns != cellml.NS_MATHML:
738
740
  raise CellMLParsingError(
739
741
  'The contents of a mathml:math element must be in the'
740
- ' mathml namespace, found "' + str(child.tag) + '" inside '
741
- + str(component) + '.', child)
742
+ f' mathml namespace, found "{child.tag}" inside'
743
+ f' {component}.', child)
742
744
 
743
745
  # Ignore annotations
744
746
  if el in ['annotation', 'annotation-xml']:
@@ -753,22 +755,22 @@ class CellMLParser:
753
755
  if el != 'apply':
754
756
  raise CellMLParsingError(
755
757
  'Unexpected contents in mathml:math. Expecting'
756
- ' mathml:apply but found mathml:' + el + ' inside maths'
757
- ' for ' + str(component) + '.', child)
758
+ f' mathml:apply but found mathml:{el} in maths for'
759
+ f' {component}.', child)
758
760
 
759
761
  # Parse
760
762
  eq = p.parse(child)
761
763
  if not isinstance(eq, myokit.Equal):
762
764
  raise CellMLParsingError(
763
765
  'Unexpected element in MathML, expecting a list of'
764
- ' equations, got ' + self._tag(child) + '.', child)
766
+ f' equations, got {self._tag(child)}.', child)
765
767
  lhs, rhs = eq
766
768
 
767
769
  # Check lhs
768
770
  if not isinstance(lhs, myokit.LhsExpression):
769
771
  raise CellMLParsingError(
770
772
  'Invalid expression found on the left-hand side of an'
771
- ' equation: ' + self._dae_message, child)
773
+ f' equation: {self._dae_message}', child)
772
774
 
773
775
  # Promote derivative, check non-derivatives have no initial value
774
776
  var = lhs.var()
@@ -777,15 +779,13 @@ class CellMLParser:
777
779
  elif var.initial_value() is not None:
778
780
  raise CellMLParsingError(
779
781
  'Initial value and a defining equation found for'
780
- ' non-state ' + str(var) + ': ' + self._dae_message,
781
- child)
782
+ f' non-state {var}: {self._dae_message}', child)
782
783
 
783
784
  # Check for double rhs
784
785
  if var.rhs() is not None:
785
786
  raise CellMLParsingError(
786
- 'Two defining equations found for ' + str(var) + ': '
787
- + self._dae_message,
788
- child)
787
+ f'Two defining equations found for {var}:'
788
+ f' {self._dae_message}', child)
789
789
 
790
790
  # Set rhs
791
791
  try:
@@ -1020,9 +1020,9 @@ class CellMLParser:
1020
1020
  if not children:
1021
1021
  if base == 'yes':
1022
1022
  warnings.warn(
1023
- 'Unable to parse definition for units "' + str(name) + '",'
1024
- ' using `dimensionless` instead. (Defining new base units'
1025
- ' is not supported.)')
1023
+ f'Unable to parse definition for units "{name}", using'
1024
+ ' `dimensionless` instead. (Defining new base units is not'
1025
+ ' supported.)')
1026
1026
  else:
1027
1027
  raise CellMLParsingError(
1028
1028
  'Units element with base_units="no" must contain at least'
@@ -1035,8 +1035,8 @@ class CellMLParser:
1035
1035
  myokit_unit *= self._parse_unit(child, owner)
1036
1036
  except myokit.formats.cellml.v1.UnitsError as e:
1037
1037
  warnings.warn(
1038
- 'Unable to parse definition for units "' + str(name) + '",'
1039
- ' using `dimensionless` instead. (' + str(e) + ')')
1038
+ f'Unable to parse definition for units "{name}", using'
1039
+ f' `dimensionless` instead. ({e})')
1040
1040
  myokit_unit = myokit.units.dimensionless
1041
1041
 
1042
1042
  # Add units to owner
@@ -1049,6 +1049,10 @@ class CellMLParser:
1049
1049
  """
1050
1050
  Parses a variable ``element`` and adds a variable to the given
1051
1051
  ``component``.
1052
+
1053
+ If an initial value needs to be set, returns a tuple
1054
+ ``(element, variable, initial_value_string)``. Otherwise returns
1055
+ ``None``.
1052
1056
  """
1053
1057
  # Check name is present
1054
1058
  try:
@@ -1076,9 +1080,8 @@ class CellMLParser:
1076
1080
  variable = component.add_variable(name, units, pub, pri)
1077
1081
  except myokit.formats.cellml.v1.UnitsError as e:
1078
1082
  warnings.warn(
1079
- 'The units "' + str(units) + '" (assigned to a variable)'
1080
- ' are not supported and have been replaced by'
1081
- ' `dimensionless`. (' + str(e) + ')')
1083
+ f'The units "{units}" (assigned to a variable) are not'
1084
+ f' supported and were replaced by `dimensionless`. ({e})')
1082
1085
  units = 'dimensionless'
1083
1086
  variable = component.add_variable(name, units, pub, pri)
1084
1087
 
@@ -1097,9 +1100,10 @@ class CellMLParser:
1097
1100
  ]
1098
1101
  self._check_allowed_content(element, [], attr, name)
1099
1102
 
1100
- # Set initial value
1101
- variable.set_initial_value(
1102
- element.attrib.get('initial_value', None))
1103
+ # Store initial value, to parse later
1104
+ init = element.attrib.get('initial_value', None)
1105
+ if init is not None:
1106
+ return (element, variable, init)
1103
1107
 
1104
1108
  except myokit.formats.cellml.v1.CellMLError as e:
1105
1109
  raise CellMLParsingError(str(e), element)
@@ -1149,14 +1153,14 @@ class CellMLParser:
1149
1153
  # Check doesn't shadow an si unit
1150
1154
  if name in si_units:
1151
1155
  raise CellMLParsingError(
1152
- 'Units name "' + name + '" overlaps with a predefined name'
1153
- ' in ' + self._tag(element) + ' (5.4.1.2).', element)
1156
+ f'Units name "{name}" overlaps with a predefined name'
1157
+ f' in {self._tag(element)} (5.4.1.2).', element)
1154
1158
 
1155
1159
  # Check for duplicates
1156
1160
  if name in local_units:
1157
1161
  raise CellMLParsingError(
1158
- 'Duplicate units definition "' + name + '" in '
1159
- + self._tag(element) + '.', element)
1162
+ f'Duplicate units definition "{name}" in'
1163
+ f' {self._tag(element)}.', element)
1160
1164
  local_units[name] = units
1161
1165
 
1162
1166
  # Component units can shadow model units, so if known units are
@@ -1196,8 +1200,8 @@ class CellMLParser:
1196
1200
  deps.difference_update(fresh)
1197
1201
  else:
1198
1202
  raise CellMLParsingError(
1199
- 'Unable to resolve network of units in '
1200
- + self._tag(element) + ' (5.4.2.2).', element)
1203
+ 'Unable to resolve network of units in'
1204
+ f' {self._tag(element)} (5.4.2.2).', element)
1201
1205
  return ordered
1202
1206
 
1203
1207
  def _tag(self, element, name=None):
@@ -1214,6 +1218,6 @@ class CellMLParser:
1214
1218
  ns, el = split(element.tag)
1215
1219
  tag = self._item(ns, el)
1216
1220
  if ns == self._ns and name is not None:
1217
- tag += '[@name="' + name + '"]'
1221
+ tag += f'[@name="{name}"]'
1218
1222
  return tag
1219
1223
 
@@ -283,7 +283,7 @@ class CellMLWriter:
283
283
  self._oxmeta_variables.items(), key=lambda x: x[0]):
284
284
  description = etree.SubElement(
285
285
  rdf, etree.QName(cellml.NS_RDF, 'Description'))
286
- description.attrib[etree.QName(cellml.NS_RDF, 'about')] = '#' + cid
286
+ description.attrib[etree.QName(cellml.NS_RDF, 'about')] = f'#{cid}'
287
287
  iz = etree.SubElement(
288
288
  description, etree.QName(cellml.NS_BQBIOL, 'is'))
289
289
  iz.attrib[etree.QName(cellml.NS_RDF, 'resource')] = \
@@ -352,11 +352,18 @@ class CellMLWriter:
352
352
  element.attrib['private_interface'] = variable.private_interface()
353
353
 
354
354
  # Add initial value
355
- if variable.initial_value() is not None:
356
- value = myokit.float.str(variable.initial_value()).strip()
357
- if value[-4:] == 'e+00':
358
- value = value[:-4]
359
- element.attrib['initial_value'] = value
355
+ init = variable.initial_value()
356
+ if init is not None:
357
+ if isinstance(init, myokit.Number):
358
+ value = myokit.float.str(variable.initial_value()).strip()
359
+ if value[-4:] == 'e+00':
360
+ value = value[:-4]
361
+ element.attrib['initial_value'] = value
362
+ elif isinstance(init, myokit.Name):
363
+ element.attrib['initial_value'] = init.var().name()
364
+ else: # pragma: no cover
365
+ raise Exception(
366
+ f'Unexpected type for initial value: {type(init)}.')
360
367
 
361
368
  # Add cmeta id
362
369
  cid = variable.cmeta_id()
@@ -7,28 +7,25 @@
7
7
  from ._api import ( # noqa
8
8
  AnnotatableElement,
9
9
  CellMLError,
10
+ Component,
10
11
  clean_identifier,
11
12
  create_unit_name,
12
- Component,
13
+ is_identifier,
13
14
  Model,
14
15
  Units,
15
16
  Variable,
16
- is_basic_real_number_string,
17
- is_identifier,
18
- is_integer_string,
19
- is_real_number_string,
20
17
  )
21
18
 
22
19
  from ._parser import ( # noqa
23
- parse_file,
24
- parse_string,
25
20
  CellMLParser,
26
21
  CellMLParsingError,
22
+ parse_file,
23
+ parse_string,
27
24
  )
28
25
 
29
26
  from ._writer import ( # noqa
27
+ CellMLWriter,
30
28
  write_file,
31
29
  write_string,
32
- CellMLWriter,
33
30
  )
34
31