def test_regime(self): # Signature: name(self, name=None) # Find a regime in the component by name # from nineml.abstraction.component.componentqueryer import # ComponentClassQueryer c = Dynamics(name='cl', regimes=[ Regime('dX/dt=1/t', name='r1', transitions=On('X>X1', do=['X=X0'], to='r2')), Regime('dX/dt=1/t', name='r2', transitions=On('X>X1', do=['X=X0'], to='r3')), Regime('dX/dt=1/t', name='r3', transitions=On('X>X1', do=['X=X0'], to='r4')), Regime('dX/dt=1/t', name='r4', transitions=On('X>X1', do=['X=X0'], to='r1'))]) self.assertEqual(c.regime(name='r1').name, 'r1') self.assertEqual(c.regime(name='r2').name, 'r2') self.assertEqual(c.regime(name='r3').name, 'r3') self.assertEqual(c.regime(name='r4').name, 'r4')
def test_regime_aliases(self): a = Dynamics( name='a', aliases=[Alias('A', '4/t')], regimes=[ Regime('dX/dt=1/t + A', name='r1', transitions=On('X>X1', do=['X=X0'], to='r2')), Regime('dX/dt=1/t + A', name='r2', transitions=On('X>X1', do=['X=X0'], to='r1'), aliases=[Alias('A', '8 / t')])]) self.assertEqual(a.regime('r2').alias('A'), Alias('A', '8 / t')) self.assertRaises( NineMLUsageError, Dynamics, name='a', regimes=[ Regime('dX/dt=1/t + A', name='r1', transitions=On('X>X1', do=['X=X0'], to='r2')), Regime('dX/dt=1/t + A', name='r2', transitions=On('X>X1', do=['X=X0'], to='r1'), aliases=[Alias('A', '8 / t')])]) document = Document() a_xml = a.serialize(format='xml', version=1, document=document) b = Dynamics.unserialize(a_xml, format='xml', version=1, document=Document(un.dimensionless.clone())) self.assertEqual(a, b, "Dynamics with regime-specific alias failed xml " "roundtrip:\n{}".format(a.find_mismatch(b)))
def test_transitions(self): c = Dynamics(name='cl', regimes=[ Regime('dX1/dt=1/t', name='r1', transitions=[On('X>X1', do=['X=X0'], to='r2'), On('X>X2', do=['X=X0'], to='r3'), ] ), Regime('dX1/dt=1/t', name='r2', transitions=On('X>X1', do=['X=X0'], to='r3'),), Regime('dX2/dt=1/t', name='r3', transitions=[On('X>X1', do=['X=X0'], to='r4'), On('X>X2', do=['X=X0'], to=None)]), Regime('dX2/dt=1/t', name='r4', transitions=On('X>X1', do=['X=X0'], to=None))]) self.assertEquals(len(list(c.all_transitions())), 6) r1 = c.regime('r1') r2 = c.regime('r2') r3 = c.regime('r3') r4 = c.regime('r4') self.assertEquals(len(list(r1.transitions)), 2) self.assertEquals(len(list(r2.transitions)), 1) self.assertEquals(len(list(r3.transitions)), 2) self.assertEquals(len(list(r4.transitions)), 1) def target_regimes(regime): return unique_by_id(t.target_regime for t in regime.transitions) self.assertEquals(target_regimes(r1), [r2, r3]) self.assertEquals(target_regimes(r2), [r3]) self.assertEquals(target_regimes(r3), [r3, r4]) self.assertEquals(target_regimes(r4), [r4])
class TestUnitAssignment(TestCase): test_units = [old_div(un.mV, un.uF), un.ms * un.C / un.um, old_div(un.K ** 2, (un.uF * un.mV ** 2)), old_div(un.uF ** 3, un.um), old_div(un.cd, un.A)] test_unit_mapped = [old_div(un.mV, un.uF), un.ms * un.C / un.um, old_div(un.K ** 2, (un.uF * un.mV ** 2)), old_div(un.uF ** 3, un.um), old_div(un.cd, un.A)] def setUp(self): self.a = Dynamics( name='A', aliases=['A1 := P1 / P2', 'A2 := ARP2 + P3', 'A3 := P4 * P5', 'A4 := 1 / (P2 * P6) + ARP3', 'A5 := P7 * P8', 'A6 := P9/P10'], regimes=[ Regime('dSV1/dt = -A1 / A2', ('dSV2/dt = C1 * SV2 ** 2 + C2 * SV2 + C3 + SV3 + ' 'ARP4 / P11'), 'dSV3/dt = P12*(SV2*P13 - SV3)', name='R1')], state_variables=[StateVariable('SV1', dimension=un.dimensionless), StateVariable('SV2', dimension=un.voltage), StateVariable('SV3', dimension=old_div(un.voltage, un.time))], analog_ports=[AnalogReceivePort('ARP1', dimension=un.resistance), AnalogReceivePort('ARP2', dimension=un.charge), AnalogReceivePort('ARP3', dimension=un.conductanceDensity), AnalogReceivePort('ARP4', dimension=un.current)], parameters=[Parameter('P1', dimension=un.voltage), Parameter('P2', dimension=un.resistance), Parameter('P3', dimension=un.charge), Parameter('P4', dimension=old_div(un.length, un.current ** 2)), Parameter('P5', dimension=old_div(un.current ** 2, un.length)), Parameter('P6', dimension=un.length ** 2), Parameter('P7', dimension=old_div(un.current, un.capacitance)), Parameter('P8', dimension=un.time), Parameter('P9', dimension=old_div(un.capacitance, un.length ** 2)), Parameter('P10', dimension=old_div(un.conductance, un.length ** 2)), Parameter('P11', dimension=un.capacitance), Parameter('P12', dimension=un.per_time), Parameter('P13', dimension=un.per_time)], constants=[Constant('C1', 0.04, units=(old_div(un.unitless, (un.mV * un.ms)))), Constant('C2', 5.0, units=old_div(un.unitless, un.ms)), Constant('C3', 140.0, units=old_div(un.mV, un.ms))] ) def test_dimension_to_units(self): test_units = {old_div(un.mV, un.uF): old_div(un.mV, un.nF), old_div(un.mV, un.ms): old_div(un.mV, un.ms), old_div(un.nA, un.pF): old_div(un.mV, un.ms), old_div(un.cd, un.A): old_div(un.cd, un.nA), old_div(un.A, un.uF): old_div(un.nA, un.nF), old_div(un.nF, (un.m ** 2 * un.s)): old_div(un.S, un.cm ** 2)} TestUnitHandler1.clear_cache() for unit, unit_mapped in test_units.items(): new_unit = TestUnitHandler1.dimension_to_units(unit.dimension) self.assertEqual(new_unit, unit_mapped, "New unit mapped incorrectly {}->{} ({})" .format(unit, new_unit, unit_mapped)) def test_conversions(self): test_units = [old_div(un.mV, un.uF), un.ms * un.C / un.um, old_div(un.K ** 2, (un.uF * un.mV ** 2)), old_div(un.uF ** 3, un.um), old_div(un.cd, un.A)] for unit in test_units: scale, compound = TestUnitHandler1.dimension_to_units_compound( unit.dimension) new_scale = numpy.sum([p * u.power for u, p in compound]) self.assertEqual(scale - new_scale, 0, "Scale doesn't match in unit conversion of unit " "'{}': orig={}, inverted={}".format(unit, scale, new_scale)) x = numpy.sum(numpy.array([numpy.array(list(u.dimension)) * p for u, p in compound]), axis=0) self.assertEqual(list(unit.dimension), list(x), "Dimensions do not match original conversion of " "unit '{}'".format(unit)) def test_scaling_and_assignment(self): handler1 = TestUnitHandler1(self.a) handler2 = NestUnitHandler(self.a) self.assertEqual(handler1.scale_alias('A2'), (Expression('ARP2 + P3'), 'ms*nA'), "Difference in scaled alias {} vs {}:\n{}" .format(handler1.scale_alias('A2'), (Expression('ARP2 + P3'), 'ms*nA'), handler1.scale_alias('A2')[0].find_mismatch( Expression('ARP2 + P3')))) self.assertEqual(handler1.scale_alias('A4'), (Expression('ARP3 + 100/(P2*P6)'), 'S/cm2')) self.assertEqual(handler1.scale_alias('A5'), (Expression('P7 * P8'), 'mV')) self.assertEqual(handler1.scale_alias('A6'), (Expression('1e-3 * P9/P10'), 'ms')) self.assertEqual( handler2.scale_time_derivative(self.a.regime('R1').element('SV2')), (Expression('C1 * SV2 ** 2 + C2 * SV2 + C3 + SV3 + ' 'ARP4 / P11'), 'mV/ms')) self.assertEqual( handler2.scale_time_derivative(self.a.regime('R1').element('SV3')), (Expression('P12*(SV2*P13 - SV3)'), 'mV/ms^2')) self.assertEqual(handler1.assign_units_to_variable('P2'), '1/uS') self.assertEqual(handler1.assign_units_to_variable('P6'), 'um^2') def test_pq_round_trip(self): for unit in self.test_units: qty = Quantity(1.0, unit) pq_qty = TestUnitHandler1.to_pq_quantity(qty) new_qty = TestUnitHandler1.from_pq_quantity(pq_qty) self.assertEqual(qty.units.dimension, new_qty.units.dimension, "Python-quantities roundtrip of '{}' changed " "dimension".format(unit.name)) new_power = int(math.log10(new_qty.value) + new_qty.units.power) self.assertEqual(unit.power, new_power, "Python-quantities roundtrip of '{}' changed " "scale ({} -> {})".format(unit.name, unit.power, new_power))
class TestUnitAssignment(TestCase): test_units = [ old_div(un.mV, un.uF), un.ms * un.C / un.um, old_div(un.K**2, (un.uF * un.mV**2)), old_div(un.uF**3, un.um), old_div(un.cd, un.A) ] test_unit_mapped = [ old_div(un.mV, un.uF), un.ms * un.C / un.um, old_div(un.K**2, (un.uF * un.mV**2)), old_div(un.uF**3, un.um), old_div(un.cd, un.A) ] def setUp(self): self.a = Dynamics( name='A', aliases=[ 'A1 := P1 / P2', 'A2 := ARP2 + P3', 'A3 := P4 * P5', 'A4 := 1 / (P2 * P6) + ARP3', 'A5 := P7 * P8', 'A6 := P9/P10' ], regimes=[ Regime('dSV1/dt = -A1 / A2', ('dSV2/dt = C1 * SV2 ** 2 + C2 * SV2 + C3 + SV3 + ' 'ARP4 / P11'), 'dSV3/dt = P12*(SV2*P13 - SV3)', name='R1') ], state_variables=[ StateVariable('SV1', dimension=un.dimensionless), StateVariable('SV2', dimension=un.voltage), StateVariable('SV3', dimension=old_div(un.voltage, un.time)) ], analog_ports=[ AnalogReceivePort('ARP1', dimension=un.resistance), AnalogReceivePort('ARP2', dimension=un.charge), AnalogReceivePort('ARP3', dimension=un.conductanceDensity), AnalogReceivePort('ARP4', dimension=un.current) ], parameters=[ Parameter('P1', dimension=un.voltage), Parameter('P2', dimension=un.resistance), Parameter('P3', dimension=un.charge), Parameter('P4', dimension=old_div(un.length, un.current**2)), Parameter('P5', dimension=old_div(un.current**2, un.length)), Parameter('P6', dimension=un.length**2), Parameter('P7', dimension=old_div(un.current, un.capacitance)), Parameter('P8', dimension=un.time), Parameter('P9', dimension=old_div(un.capacitance, un.length**2)), Parameter('P10', dimension=old_div(un.conductance, un.length**2)), Parameter('P11', dimension=un.capacitance), Parameter('P12', dimension=un.per_time), Parameter('P13', dimension=un.per_time) ], constants=[ Constant('C1', 0.04, units=(old_div(un.unitless, (un.mV * un.ms)))), Constant('C2', 5.0, units=old_div(un.unitless, un.ms)), Constant('C3', 140.0, units=old_div(un.mV, un.ms)) ]) def test_dimension_to_units(self): test_units = { old_div(un.mV, un.uF): old_div(un.mV, un.nF), old_div(un.mV, un.ms): old_div(un.mV, un.ms), old_div(un.nA, un.pF): old_div(un.mV, un.ms), old_div(un.cd, un.A): old_div(un.cd, un.nA), old_div(un.A, un.uF): old_div(un.nA, un.nF), old_div(un.nF, (un.m**2 * un.s)): old_div(un.S, un.cm**2) } TestUnitHandler1.clear_cache() for unit, unit_mapped in test_units.items(): new_unit = TestUnitHandler1.dimension_to_units(unit.dimension) self.assertEqual( new_unit, unit_mapped, "New unit mapped incorrectly {}->{} ({})".format( unit, new_unit, unit_mapped)) def test_conversions(self): test_units = [ old_div(un.mV, un.uF), un.ms * un.C / un.um, old_div(un.K**2, (un.uF * un.mV**2)), old_div(un.uF**3, un.um), old_div(un.cd, un.A) ] for unit in test_units: scale, compound = TestUnitHandler1.dimension_to_units_compound( unit.dimension) new_scale = numpy.sum([p * u.power for u, p in compound]) self.assertEqual( scale - new_scale, 0, "Scale doesn't match in unit conversion of unit " "'{}': orig={}, inverted={}".format(unit, scale, new_scale)) x = numpy.sum(numpy.array( [numpy.array(list(u.dimension)) * p for u, p in compound]), axis=0) self.assertEqual( list(unit.dimension), list(x), "Dimensions do not match original conversion of " "unit '{}'".format(unit)) def test_scaling_and_assignment(self): handler1 = TestUnitHandler1(self.a) handler2 = NestUnitHandler(self.a) self.assertEqual( handler1.scale_alias('A2'), (Expression('ARP2 + P3'), 'ms*nA'), "Difference in scaled alias {} vs {}:\n{}".format( handler1.scale_alias('A2'), (Expression('ARP2 + P3'), 'ms*nA'), handler1.scale_alias('A2')[0].find_mismatch( Expression('ARP2 + P3')))) self.assertEqual(handler1.scale_alias('A4'), (Expression('ARP3 + 100/(P2*P6)'), 'S/cm2')) self.assertEqual(handler1.scale_alias('A5'), (Expression('P7 * P8'), 'mV')) self.assertEqual(handler1.scale_alias('A6'), (Expression('1e-3 * P9/P10'), 'ms')) self.assertEqual( handler2.scale_time_derivative(self.a.regime('R1').element('SV2')), (Expression('C1 * SV2 ** 2 + C2 * SV2 + C3 + SV3 + ' 'ARP4 / P11'), 'mV/ms')) self.assertEqual( handler2.scale_time_derivative(self.a.regime('R1').element('SV3')), (Expression('P12*(SV2*P13 - SV3)'), 'mV/ms^2')) self.assertEqual(handler1.assign_units_to_variable('P2'), '1/uS') self.assertEqual(handler1.assign_units_to_variable('P6'), 'um^2') def test_pq_round_trip(self): for unit in self.test_units: qty = Quantity(1.0, unit) pq_qty = TestUnitHandler1.to_pq_quantity(qty) new_qty = TestUnitHandler1.from_pq_quantity(pq_qty) self.assertEqual( qty.units.dimension, new_qty.units.dimension, "Python-quantities roundtrip of '{}' changed " "dimension".format(unit.name)) new_power = int(math.log10(new_qty.value) + new_qty.units.power) self.assertEqual( unit.power, new_power, "Python-quantities roundtrip of '{}' changed " "scale ({} -> {})".format(unit.name, unit.power, new_power))