def test_output_filtering(self): """ Tests whether the 'outputs' argument is able to filter (presumably) unconnected nonlinear mappings from inputs and states to analog send ports """ e = Dynamics(name='E', regimes=[ Regime('dSV1/dt = -SV1 / P1', 'dSV2/dt = -SV2 / P1 + ARP1 * P2', name='R1') ], aliases=['A1:=SV1 * C1', 'A2:=SV1 * SV2'], analog_ports=[ AnalogReceivePort('ARP1', dimension=un.per_time), AnalogSendPort('A1', dimension=un.current), AnalogSendPort('A2', dimension=un.dimensionless) ], parameters=[ Parameter('P1', dimension=un.time), Parameter('P2', dimension=un.dimensionless) ], constants=[Constant('C1', 10, units=un.mA)]) self.assertFalse(e.is_linear()) self.assertTrue(e.is_linear(outputs=['A1']))
def test_good_model(self): Dynamics(name='A', aliases=['A1:=P1 * SV2', 'A2 := ARP1 + SV2', 'A3 := SV1'], state_variables=[ StateVariable('SV1', dimension=un.voltage), StateVariable('SV2', dimension=un.current) ], regimes=[ Regime('dSV1/dt = -SV1 / P2', 'dSV2/dt = A3 / ARP2 + SV2 / P2', transitions=[ On('SV1 > P3', do=[OutputEvent('emit')]), On('spikein', do=[OutputEvent('emit')]) ], name='R1'), Regime(name='R2', transitions=On('(SV1 > C1) & (SV2 < P4)', to='R1')) ], analog_ports=[ AnalogReceivePort('ARP1', dimension=un.current), AnalogReceivePort('ARP2', dimension=(un.resistance * un.time)), AnalogSendPort('A1', dimension=un.voltage * un.current), AnalogSendPort('A2', dimension=un.current) ], parameters=[ Parameter('P1', dimension=un.voltage), Parameter('P2', dimension=un.time), Parameter('P3', dimension=un.voltage), Parameter('P4', dimension=un.current) ], constants=[Constant('C1', value=1.0, units=un.mV)])
def test_delay_rand_distr(self): rand_delay_class = RandomDistribution( name="RandomDelay", parameters=[ Parameter('mean', dimension=un.dimensionless), Parameter('stddev', dimension=un.dimensionless) ], standard_library=('http://www.uncertml.org/distributions/normal')) pop1 = Population("Pop1", 100, self.celltype) pop2 = Population("Pop2", 100, self.celltype) rand_delay = RandomDistributionProperties(name="RandomDelayProps", definition=rand_delay_class, properties={ 'mean': 5.0, 'stddev': 1.0 }) rand_delay_prj = Projection( "External", pre=pop1, post=pop2, response=self.psr, plasticity=self.static_ext, connection_rule_properties=self.one_to_one, delay=RandomDistributionValue(rand_delay) * un.ms, port_connections=[('response', 'Isyn', 'post', 'Isyn'), ('plasticity', 'weight', 'response', 'weight')]) rand_distr_network = Network('rand_distr_net', populations=[pop1, pop2], projections=[rand_delay_prj]) self.assertRaises(NineMLRandomDistributionDelayException, rand_distr_network.delay_limits)
def test_nonlinear_state_assignment_in_onevent(self): """Test that nonlinear state assignements in on events""" g = Dynamics(name='G', regimes=[ Regime('dSV1/dt = -SV1 / P1', 'dSV2/dt = -SV2 / P1 + ARP1 * P2', name='R1', transitions=[ OnEvent('ERP1', state_assignments=[ StateAssignment( 'SV2', 'SV2 + A2') ]) ]) ], aliases=['A1:=SV1 * C1', 'A2:=P3 * P4 / ADP1'], analog_ports=[ AnalogReceivePort('ARP1', dimension=un.per_time), AnalogReducePort('ADP1', operator='+', dimension=un.dimensionless), AnalogSendPort('A1', dimension=un.current), AnalogSendPort('A2', dimension=un.dimensionless) ], event_ports=[EventReceivePort('ERP1')], parameters=[ Parameter('P1', dimension=un.time), Parameter('P2', dimension=un.dimensionless), Parameter('P3', dimension=un.resistance), Parameter('P4', dimension=un.conductance) ], constants=[Constant('C1', 10, units=un.nA)]) self.assertFalse(g.is_linear())
def test_internally_inconsistent(self): self.assertRaises( NineMLDimensionError, Dynamics, name='A', state_variables=[StateVariable('SV1', dimension=un.voltage)], regimes=[ Regime('dSV1/dt = SV1 + P1', name='R1'), ], parameters=[Parameter('P1', dimension=un.time)], ) self.assertRaises( NineMLDimensionError, Dynamics, name='A', state_variables=[StateVariable('SV1', dimension=un.voltage)], regimes=[ Regime('dSV1/dt = SV1/t', transitions=[On('SV1 > P1', do=[OutputEvent('emit')])], name='R1'), ], parameters=[Parameter('P1', dimension=un.time)], ) self.assertRaises( NineMLDimensionError, Dynamics, name='A', state_variables=[StateVariable('SV1', dimension=un.voltage)], regimes=[ Regime('dSV1/dt = SV1/t', transitions=[ On('SV1 > P1', do=[StateAssignment('SV1', 'SV1 + RP1')]) ], name='R1'), ], parameters=[Parameter('P1', dimension=un.voltage)], analog_ports=[AnalogReceivePort('RP1', dimension=un.time)], ) self.assertRaises( NineMLDimensionError, Dynamics, name='A', state_variables=[StateVariable('SV1', dimension=un.voltage)], regimes=[ Regime('dSV1/dt = SV1/t', transitions=[ On('(SV1 > P1) & (P2 > 0)', do=[OutputEvent('emit')]) ], name='R1'), ], parameters=[ Parameter('P1', dimension=un.time), Parameter('P2', dimension=un.dimensionless) ], )
def test_basic_linear(self): """A basic linear dynamics example""" a = Dynamics( name='A', regimes=[ Regime('dSV1/dt = -SV1 / P1', 'dSV2/dt = -SV2 / P1 + ARP1 * P2', name='R1') ], analog_ports=[AnalogReceivePort('ARP1', dimension=un.per_time)], parameters=[ Parameter('P1', dimension=un.time), Parameter('P2', dimension=un.dimensionless) ]) self.assertTrue(a.is_linear())
def test_input_multiplication_nonlinear(self): """Nonlinear due to multiplication of SV1 and SV2 in SV1 T.D.""" d = Dynamics( name='D', regimes=[ Regime('dSV1/dt = -SV1 * SV2 / P1', 'dSV2/dt = -SV2 / P1 + ARP1 * P2', name='R1') ], analog_ports=[AnalogReceivePort('ARP1', dimension=un.per_time)], parameters=[ Parameter('P1', dimension=un.time), Parameter('P2', dimension=un.dimensionless) ]) self.assertFalse(d.is_linear())
def test_nonlinear_function(self): """Nonlinear due function in SV1 T.D.""" h = Dynamics( name='H', regimes=[ Regime('dSV1/dt = -sin(SV1) / P1', 'dSV2/dt = -SV2 / P1 + ARP1 * P2', name='R1') ], analog_ports=[AnalogReceivePort('ARP1', dimension=un.per_time)], parameters=[ Parameter('P1', dimension=un.time), Parameter('P2', dimension=un.dimensionless) ]) self.assertFalse(h.is_linear())
def setUp(self): self.parameters = ['P4', 'P1', 'P3', 'P5', 'P2'] self.state_variables = ['SV3', 'SV5', 'SV4', 'SV2', 'SV1'] self.regimes = ['R2', 'R3', 'R1'] self.time_derivatives = { 'R1': ['SV5', 'SV1', 'SV4', 'SV3', 'SV2'], 'R2': ['SV2', 'SV4'], 'R3': ['SV4', 'SV2', 'SV1'] } self.aliases = ['A4', 'A3', 'A1', 'A2'] # Create a dynamics object with elements in a particular order self.d = Dynamics( name='d', parameters=[Parameter(p) for p in self.parameters], state_variables=[StateVariable(sv) for sv in self.state_variables], regimes=[ Regime(name=r, time_derivatives=[ TimeDerivative(td, '{}/t'.format(td)) for td in self.time_derivatives[r] ], transitions=[ OnCondition('SV1 > P5', target_regime_name=self.regimes[ self.regimes.index(r) - 1]) ]) for r in self.regimes ], aliases=[ Alias(a, 'P{}'.format(i + 1)) for i, a in enumerate(self.aliases) ])
def test_read_annotations_and_annotate_xml(self): param_xml = E(Parameter.nineml_type, deepcopy(annot_xml), name="P1", dimension="dimensionless") dim_xml = E(Dimension.nineml_type, deepcopy(annot_xml), name='dimensionless') doc = Document() dimension = Dimension.unserialize( dim_xml, format='xml', version=DEFAULT_VERSION, document=doc) doc.add(dimension) parameter = Parameter.unserialize( param_xml, format='xml', version=DEFAULT_VERSION, document=doc) self.assertEqual(parameter.annotations, self.annot, "{}\n\nvs\n\n{}".format(parameter.annotations, self.annot)) self.assertEqual(dimension.annotations, self.annot, "{}\n\nvs\n\n{}".format(dimension.annotations, self.annot)) re_param_xml = parameter.serialize( format='xml', version=DEFAULT_VERSION, document=doc) re_dim_xml = dimension.serialize(format='xml', version=DEFAULT_VERSION, document=doc) self.assertTrue(xml_equal(param_xml, re_param_xml, annotations=True), "\n{}\n does not equal\n\n{}".format( etree.tostring(param_xml, pretty_print=True), etree.tostring(re_param_xml, pretty_print=True))) self.assertTrue(xml_equal(dim_xml, re_dim_xml, annotations=True), "\n{}\n does not equal\n\n{}".format( etree.tostring(dim_xml, pretty_print=True), etree.tostring(re_dim_xml, pretty_print=True)))
def test_add_ninemlruntimeerror(self): """ line #: 346 message: Could not add '{}' {} to component class as it clashes with an existing element of the same name """ self.assertRaises(NineMLUsageError, dynA.add, Parameter('P1', un.dimensionless))
def test_remove_ninemlruntimeerror(self): """ line #: 358 message: Could not remove '{}' from component class as it was not found in member dictionary (use 'ignore_missing' option to ignore) """ self.assertRaises(NineMLUsageError, dynA.remove, Parameter('boogiewoogie', un.dimensionless))
def setUp(self): self.a = Dynamics( name='A', aliases=['A1:=P1 / P2', 'A2 := ARP2 + P3', 'A3 := P4 * P5'], regimes=[ Regime('dSV1/dt = -A1 / A2', aliases=[Alias('A1', 'P1 / P2 * 2')], name='R1') ], analog_ports=[ AnalogReceivePort('ARP1', dimension=un.resistance), AnalogReceivePort('ARP2', dimension=un.charge) ], 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)) ])
def test_standardize_units_ninemlruntimeerror2(self): """ line #: 268 message: Name of dimension '{}' conflicts with existing object of differring value or type '{}' and '{}' """ a = Dynamics( name='A', parameters=[ Parameter('P1', dimension=un.Dimension(name='D', t=1))], regime=Regime(name='default'), aliases=['A1 := P1 * 2']) b = Dynamics( name='B', parameters=[ Parameter('P1', dimension=un.Dimension(name='D', l=1))], regime=Regime(name='default'), aliases=['A1 := P1 * 2']) self.assertRaises( NineMLUsageError, Document, a, b)
def test_build_name_conflict(self): izhi = ninemlcatalog.load('neuron/Izhikevich.xml#Izhikevich') izhi2 = izhi.clone() izhi2.add(StateVariable('Z', dimension=un.dimensionless)) izhi2.regime('subthreshold_regime').add(TimeDerivative('Z', '1 / zp')) izhi2.add(Parameter('zp', dimension=un.time)) izhi_wrap = WithSynapses.wrap(izhi) izhi2_wrap = WithSynapses.wrap(izhi2) CellMetaClass(izhi_wrap) self.assertRaises(Pype9BuildMismatchError, CellMetaClass, izhi2_wrap)
def test_all_expressions(self): a = Dynamics( name='A', aliases=['A1:=P1 * SV2', 'A2 := ARP1 + SV2', 'A3 := SV1'], state_variables=[ StateVariable('SV1', dimension=un.voltage), StateVariable('SV2', dimension=un.current)], regimes=[ Regime( 'dSV1/dt = -SV1 / P2', 'dSV2/dt = A3 / ARP2 + SV2 / P2', transitions=[On('SV1 > P3', do=[OutputEvent('emit')]), On('spikein', do=[OutputEvent('emit')])], name='R1' ), Regime(name='R2', transitions=On('(SV1 > C1) & (SV2 < P4)', to='R1')) ], analog_ports=[AnalogReceivePort('ARP1', dimension=un.current), AnalogReceivePort('ARP2', dimension=(un.resistance * un.time)), AnalogSendPort('A1', dimension=un.voltage * un.current), AnalogSendPort('A2', dimension=un.current)], parameters=[Parameter('P1', dimension=un.voltage), Parameter('P2', dimension=un.time), Parameter('P3', dimension=un.voltage), Parameter('P4', dimension=un.current)], constants=[Constant('C1', value=1.0, units=un.mV)] ) self.assertEqual( set(a.all_expressions), set(( sympify('P1 * SV2'), sympify('ARP1 + SV2'), sympify('SV1'), sympify('-SV1 / P2'), sympify('-SV1 / P2'), sympify('A3 / ARP2 + SV2 / P2'), sympify('SV1 > P3'), sympify('(SV1 > C1) & (SV2 < P4)'))), "All expressions were not extracted from component class")
def test_mismatch_with_declared(self): self.assertRaises( NineMLDimensionError, Dynamics, name='A', state_variables=[StateVariable('SV1', dimension=un.voltage)], regimes=[ Regime('dSV1/dt = SV1/t', name='R1'), ], analog_ports=[AnalogSendPort('SV1', dimension=un.current)], ) self.assertRaises( NineMLDimensionError, Dynamics, name='A', state_variables=[StateVariable('SV1', dimension=un.voltage)], regimes=[ Regime('dSV1/dt = SV1 * P1', name='R1'), ], parameters=[Parameter('P1', dimension=un.time)], ) self.assertRaises( NineMLDimensionError, Dynamics, name='A', state_variables=[StateVariable('SV1', dimension=un.voltage)], regimes=[ Regime('dSV1/dt = SV1/t', transitions=[ On('SV1 > P1', do=[StateAssignment('SV1', 'P2')]) ], name='R1'), ], parameters=[ Parameter('P1', dimension=un.voltage), Parameter('P2', dimension=un.time) ], )
def test_multi_regime_nonlinear(self): """Nonlinear due to multiple regimes""" b = Dynamics( name='B', regimes=[ Regime('dSV1/dt = -SV1 / P1', transitions=[OnEvent('ERP1', target_regime_name='R2')], name='R1'), Regime('dSV1/dt = -SV1 / P1', transitions=[OnEvent('ERP1', target_regime_name='R1')], name='R2') ], event_ports=[EventReceivePort('ERP1')], parameters=[Parameter('P1', dimension=un.time)]) self.assertFalse(b.is_linear())
def test_on_condition_state_assignment_nonlinear(self): """ Nonlinear due to a state assignment in on-condition (i.e. piece-wise dynamics """ c = Dynamics(name='C', regimes=[ Regime('dSV1/dt = -P1 * SV1', transitions=[ OnCondition('SV1 > 10', state_assignments=[ StateAssignment('SV1', 20) ]) ], name='R1') ], parameters=[Parameter('P1', dimension=un.per_time)]) self.assertFalse(c.is_linear())
def test_equals_with_annotations_ns(self): a = Dynamics(name='D', parameters=[Parameter('P', dimension=un.dimensionless)], aliases=[Alias('A', 'P')]) b = a.clone() c = a.clone() d = a.clone() e = a.clone() a.parameter('P').annotations.set(('annot1', 'dummy_ns'), 'val1', 1.0) b.parameter('P').annotations.set(('annot1', 'dummy_ns'), 'val1', 1.0) c.parameter('P').annotations.set(('annot1', 'dummy_ns'), 'val1', 2.0) e.parameter('P').annotations.set(('annot1', 'dummy_ns2'), 'val1', 1.0) self.assertTrue(a.equals(b, annotations_ns=['dummy_ns'])) self.assertTrue(a.equals(c)) self.assertFalse(a.equals(c, annotations_ns=['dummy_ns'])) self.assertTrue(a.equals(d)) self.assertFalse(a.equals(d, annotations_ns=['dummy_ns'])) self.assertTrue(a.equals(e)) self.assertFalse(a.equals(e, annotations_ns=['dummy_ns']))
def __init__(self, name, dynamics_properties, synapse_propertiess=[], connection_property_sets=[]): self._name = validate_identifier(name) self._dynamics_properties = dynamics_properties self.add(*synapse_propertiess) self.add(*connection_property_sets) # Extract the AL objects for the definition synapses = (Synapse(s.name, s.dynamics_properties.component_class, s.port_connections) for s in synapse_propertiess) connection_parameter_sets = (ConnectionParameterSet( cp.port, [Parameter(p.name, p.units.dimension) for p in cp.properties]) for cp in connection_property_sets) self._definition = Definition( WithSynapses.wrap(dynamics_properties.component_class, synapses, connection_parameter_sets))
def test_add(self): # Copy templates a = self.a.clone() b = self.b.clone() # Add missing items a.add(Alias('A4', 'SV1^3 + SV2^-3')) a.add(StateVariable('SV3')) a.regime('R1').add(TimeDerivative('SV3', '-SV3/t + P3/t')) a.regime('R1').on_event('spikein').add(StateAssignment('SV1', 'P1')) a.regime('R2').add( OnCondition('SV3 < 0.001', target_regime_name='R2', state_assignments=[StateAssignment('SV3', 1)])) a.add(Parameter('P3')) a.add(AnalogSendPort('SV3')) a.bind() a.validate() self.assertEqual( b, a, "Did not transform 'a' into 'b':\n {}".format(b.find_mismatch(a)))
def test_read_annotations_and_annotate_xml(self): param_xml = E(Parameter.nineml_type, deepcopy(annot_xml), name="P1", dimension="dimensionless") dim_xml = E(Dimension.nineml_type, deepcopy(annot_xml), name='dimensionless') doc = Document() dimension = Dimension.unserialize(dim_xml, format='xml', version=DEFAULT_VERSION, document=doc) doc.add(dimension) parameter = Parameter.unserialize(param_xml, format='xml', version=DEFAULT_VERSION, document=doc) self.assertEqual( parameter.annotations, self.annot, "{}\n\nvs\n\n{}".format(parameter.annotations, self.annot)) self.assertEqual( dimension.annotations, self.annot, "{}\n\nvs\n\n{}".format(dimension.annotations, self.annot)) re_param_xml = parameter.serialize(format='xml', version=DEFAULT_VERSION, document=doc) re_dim_xml = dimension.serialize(format='xml', version=DEFAULT_VERSION, document=doc) self.assertTrue( xml_equal(param_xml, re_param_xml, annotations=True), "\n{}\n does not equal\n\n{}".format( etree.tostring(param_xml, pretty_print=True), etree.tostring(re_param_xml, pretty_print=True))) self.assertTrue( xml_equal(dim_xml, re_dim_xml, annotations=True), "\n{}\n does not equal\n\n{}".format( etree.tostring(dim_xml, pretty_print=True), etree.tostring(re_dim_xml, pretty_print=True)))
Property, Definition, Prototype, Initial, DynamicsProperties, ConnectionRuleProperties, RandomDistributionProperties, MultiDynamicsProperties, AnalogPortConnection, EventPortConnection, Network) from nineml.user.multi import (EventSendPortExposure, EventReceivePortExposure, AnalogSendPortExposure, AnalogReceivePortExposure, AnalogReducePortExposure) import sympy from nineml.user.projection import Connectivity from nineml.serialization import NINEML_V1_NS ranDistrA = RandomDistribution( name="ranDistrA", standard_library="http://www.uncertml.org/distributions/exponential", parameters=[Parameter('P1', dimension=un.dimensionless)]) ranDistrPropA = RandomDistributionProperties( name="ranDistrPropA", definition=ranDistrA, properties={'P1': 81.0 * un.unitless}) dynA = Dynamics(name='dynA', aliases=[ 'A1:=P1 * SV2', 'A2 := ARP1 + SV2', 'A3 := SV1', 'A4 := C2 * SV1' ], state_variables=[ StateVariable('SV1', dimension=un.voltage), StateVariable('SV2', dimension=un.current) ],
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 setUp(self): self.a = Dynamics( name='A', aliases=[ 'A1:=P1 / P2', 'A2 := ARP2 + P3', 'A3 := A4 * P4 * P5', 'A4:=P6 ** 2 + ADP1', 'A5:=SV1 * SV2 * P8', 'A6:=SV1 * P1 / P8', 'A7:=A1 / P8' ], regimes=[ Regime('dSV1/dt = -A1 / A2', 'dSV2/dt = -ADP1 / P7', 'dSV3/dt = -A1 * A3 / (A2 * C1)', transitions=[ OnCondition('SV1 > 10', target_regime_name='R2') ], aliases=[ Alias('A1', 'P1 / P2 * 2'), Alias('A5', 'SV1 * SV2 * P8 * 2') ], name='R1'), Regime('dSV1/dt = -A1 / A2', 'dSV3/dt = -A1 / A2 * A4', transitions=[ OnCondition('C2 > A6', state_assignments=[ StateAssignment('SV1', 'SV1 - A7') ], target_regime_name='R1') ], name='R2') ], analog_ports=[ AnalogReceivePort('ARP1', dimension=un.resistance), AnalogReceivePort('ARP2', dimension=un.charge), AnalogReducePort('ADP1', dimension=un.dimensionless), AnalogSendPort('A5', 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.dimensionless), Parameter('P7', dimension=un.time), Parameter('P8', dimension=un.current) ], constants=[ Constant('C1', value=10.0, units=un.unitless), Constant('C2', value=1.0, units=un.ohm) ]) self.ref_substituted_a = Dynamics( name='substituted_A', aliases=['A5:=SV1 * SV2 * P8'], regimes=[ Regime('dSV1/dt = -2 * (P1 / P2) / (ARP2 + P3)', 'dSV2/dt = -ADP1 / P7', ('dSV3/dt = -2 * (P1 / P2) * ((P6 ** 2 + ADP1) * P4 * ' 'P5) / ((ARP2 + P3) * C1)'), transitions=[ OnCondition('SV1 > 10', target_regime_name='R2') ], aliases=[Alias('A5', 'SV1 * SV2 * P8 * 2')], name='R1'), Regime('dSV1/dt = -(P1 / P2) / (ARP2 + P3)', 'dSV3/dt = -(P1 / P2) / (ARP2 + P3) * (P6 ** 2 + ADP1)', transitions=[ OnCondition('C2 > (SV1 * P1 / P8)', state_assignments=[ StateAssignment( 'SV1', 'SV1 - (P1 / P2) / P8') ], target_regime_name='R1') ], name='R2') ], analog_ports=[ AnalogReceivePort('ARP1', dimension=un.resistance), AnalogReceivePort('ARP2', dimension=un.charge), AnalogReducePort('ADP1', dimension=un.dimensionless), AnalogSendPort('A5', 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.dimensionless), Parameter('P7', dimension=un.time), Parameter('P8', dimension=un.current) ], constants=[ Constant('C1', value=10.0, units=un.unitless), Constant('C2', value=1.0, units=un.ohm) ])
do=[OutputEvent('ESP1')]), On('ERP1', do=[OutputEvent('ESP2')])], name='R1' ), Regime(name='R2', transitions=[ OnCondition('(SV1 > C1) & (SV2 < P4)', target_regime_name='R1')]) ], analog_ports=[AnalogReceivePort('ARP1', dimension=un.current), AnalogReceivePort('ARP2', dimension=(un.resistance * un.time)), AnalogSendPort('A1', dimension=un.voltage * un.current), AnalogSendPort('A2', dimension=un.current)], parameters=[Parameter('P1', dimension=un.voltage), Parameter('P2', dimension=un.time), Parameter('P3', dimension=un.voltage), Parameter('P4', dimension=un.current)], constants=[Constant('C1', value=-71.0, units=un.mV), Constant('C2', value=22.2, units=un.degC)]) ref.state_variable('SV2').annotations.set(('Z1', 'NS1'), 'Y1', 'X1', 2.0) A = Dynamics( name='dyn', aliases=['A1:=SV2', 'A2 := ARP1 + SV2', 'A3 := SV1', 'A4 := C2 * SV1'], state_variables=[ StateVariable('SV1', dimension=un.voltage), StateVariable('SV2', dimension=un.current)],
def _transform_full_component(self, trfrm, component_class, v, **kwargs): # ----------------------------------------------------------------- # Remove all analog send ports with 'current' dimension so they # don't get confused with the converted voltage time derivative # expression # ----------------------------------------------------------------- for port in list(trfrm.analog_send_ports): if port.dimension == un.current: trfrm.remove(port) # ----------------------------------------------------------------- # Insert membrane capacitance if not present # ----------------------------------------------------------------- # Get or guess the location of the membrane capacitance try: name = kwargs['membrane_capacitance'] try: orig_cm = component_class.parameter(name) except KeyError: raise Pype9BuildError( "Could not find specified membrane capacitance '{}'" .format(name)) cm = trfrm.parameter(orig_cm.name) except KeyError: # 'membrane_capacitance' was not specified candidate_cms = [ccm for ccm in component_class.parameters if ccm.dimension == un.capacitance] if len(candidate_cms) == 1: orig_cm = candidate_cms[0] cm = trfrm.parameter(orig_cm.name) logger.info("Guessing that '{}' is the membrane capacitance" .format(orig_cm)) elif len(candidate_cms) > 1: raise Pype9BuildError( "Could not guess the membrane capacitance, candidates:" " '{}'".format("', '".join(candidate_cms))) else: cm = Parameter("cm___pype9", dimension=un.capacitance) trfrm.add(cm) cm.annotations.set((BUILD_TRANS, PYPE9_NS), TRANSFORM_SRC, None) trfrm.annotations.set((BUILD_TRANS, PYPE9_NS), MEMBRANE_CAPACITANCE, cm.name) # ----------------------------------------------------------------- # Replace membrane voltage equation with membrane current # ----------------------------------------------------------------- # Determine the regimes in which each state variables has a time # derivative in has_td = defaultdict(list) # List which regimes need to be clamped to their last voltage # (as it has no time derivative) clamped_regimes = [] # The voltage clamp equation where v_clamp is the last voltage # value and g_clamp_ is a large conductance clamp_i = sympy.sympify('g_clamp___pype9 * (v - v_clamp___pype9)') memb_is = [] for regime in trfrm.regimes: # Add an appropriate membrane current try: # Convert the voltage time derivative into a membrane # current dvdt = regime.time_derivative(v.name) regime.remove(dvdt) i = -dvdt.rhs * cm memb_is.append(i) except KeyError: i = clamp_i clamped_regimes.append(regime) regime.add(Alias('i___pype9', i)) # Record state vars that have a time deriv. in this regime for var in regime.time_derivative_variables: if var != 'v': has_td[var].append(regime) # Pick the most popular membrane current to be the alias in # the global scope assert memb_is, "No regimes contain voltage time derivatives" memb_i = Alias('i___pype9', max(memb_is, key=memb_is.count)) # Add membrane current along with a analog send port trfrm.add(memb_i) i_port = AnalogSendPort('i___pype9', dimension=un.current) i_port.annotations.set((BUILD_TRANS, PYPE9_NS), ION_SPECIES, NONSPECIFIC_CURRENT) trfrm.add(i_port) # Remove membrane currents that match the membrane current in the # outer scope for regime in trfrm.regimes: if regime.alias('i___pype9') == memb_i: regime.remove(regime.alias('i___pype9')) # If there are clamped regimes add extra parameters and set the # voltage to clamp to in the regimes that trfrmition to them if clamped_regimes: trfrm.add(StateVariable('v_clamp___pype9', un.voltage)) trfrm.add(Constant('g_clamp___pype9', 1e8, un.uS)) for trans in trfrm.transitions: if trans.target_regime in clamped_regimes: # Assign v_clamp_ to the value try: v_clamp_rhs = trans.state_assignment('v').rhs except KeyError: v_clamp_rhs = 'v' trans.add(StateAssignment('v_clamp___pype9', v_clamp_rhs)) # ----------------------------------------------------------------- trfrm.annotations.set( (BUILD_TRANS, PYPE9_NS), NO_TIME_DERIVS, ','.join(['v'] + [sv for sv in trfrm.state_variable_names if sv not in has_td])) trfrm.annotations.set((BUILD_TRANS, PYPE9_NS), NUM_TIME_DERIVS, len(has_td)) # ----------------------------------------------------------------- # Remove the external input currents # ----------------------------------------------------------------- # Analog receive or reduce ports that are of dimension current and # are purely additive to the membrane current and nothing else # (actually subtractive as it is outward current) try: ext_is = [] for i_name in kwargs['external_currents']: try: ext_i = trfrm.analog_receive_port(i_name) except KeyError: try: ext_i = trfrm.analog_reduce_port(i_name) except KeyError: raise Pype9BuildError( "Did not find specified external current port " "'{}'".format(i_name)) if ext_i.dimension != un.current: raise Pype9BuildError( "Analog receive port matching specified external " "current '{}' does not have 'current' dimension " "({})".format(ext_i.name, ext_i.dimension)) ext_is.append(ext_i) except KeyError: ext_is = [] for port in chain(component_class.analog_receive_ports, component_class.analog_reduce_ports): # Check to see if the receive/reduce port has current dimension if port.dimension != un.current: continue # Check to see if the current appears in the membrane current # expression # FIXME: This test should check to to see if the port is # additive to the membrane current and substitute all # aliases. if port.name not in memb_i.rhs_symbol_names: continue # Get the number of expressions the receive port appears in # an expression if len([e for e in component_class.all_expressions if port.symbol in e.free_symbols]) > 1: continue # If all those conditions are met guess that port is a external # current that can be removed (ports that don't meet these # conditions will have to be specified separately) ext_is.append(port) if ext_is: logger.info("Guessing '{}' are external currents to be removed" .format(ext_is)) trfrm.annotations.set((BUILD_TRANS, PYPE9_NS), EXTERNAL_CURRENTS, ','.join(p.name for p in ext_is)) # Remove external input current ports (as NEURON handles them) for ext_i in ext_is: trfrm.remove(ext_i) for expr in chain(trfrm.aliases, trfrm.all_time_derivatives()): expr.subs(ext_i, 0) expr.simplify()
def setUp(self): liaf = Dynamics( name='liaf', parameters=[ Parameter(name='R', dimension=un.resistance), Parameter(name='Vreset', dimension=un.voltage), Parameter(name='tau', dimension=un.time), Parameter(name='tau_rp', dimension=un.time), Parameter(name='theta', dimension=un.voltage) ], analog_ports=[ AnalogReducePort(name='Isyn', dimension=un.current, operator='+'), AnalogSendPort(name='V', dimension=un.voltage), AnalogSendPort(name='t_rpend', dimension=un.time) ], event_ports=[EventSendPort(name='spikeOutput')], state_variables=[ StateVariable(name='V', dimension=un.voltage), StateVariable(name='t_rpend', dimension=un.time) ], regimes=[ Regime(name='refractoryRegime', transitions=[ OnCondition('t > t_rpend', target_regime_name='subthresholdRegime') ]), Regime( name='subthresholdRegime', time_derivatives=[TimeDerivative('V', '(Isyn*R - V)/tau')], transitions=[ OnCondition('V > theta', target_regime_name='refractoryRegime', state_assignments=[ StateAssignment('V', 'Vreset'), StateAssignment( 't_rpend', 't + tau_rp') ], output_events=[OutputEvent('spikeOutput')]) ]) ]) poisson = Dynamics( name='Poisson', parameters=[Parameter(name='rate', dimension=un.per_time)], event_ports=[EventSendPort(name='spikeOutput')], state_variables=[StateVariable(name='t_next', dimension=un.time)], regimes=[ Regime(name='default', transitions=[ OnCondition( 't > t_next', target_regime_name='default', state_assignments=[ StateAssignment( 't_next', 'one_ms*random.exponential(' 'rate*thousand_milliseconds) + t') ], output_events=[OutputEvent('spikeOutput')]) ]) ], constants=[ Constant(name='one_ms', units=un.ms, value=1.0), Constant(name='thousand_milliseconds', units=un.ms, value=1000.0) ]) static = Dynamics( name='StaticConnection', analog_ports=[AnalogSendPort(name='weight', dimension=un.current)], state_variables=[ StateVariable(name='weight', dimension=un.current) ], regimes=[ Regime(name='default', time_derivatives=[TimeDerivative('weight', 'zero')]) ], constants=[Constant(name='zero', units=un.A / un.s, value=0.0)]) psr = Dynamics( name='AlphaPSR', parameters=[Parameter(name='tau_syn', dimension=un.time)], event_ports=[EventReceivePort(name='spike')], analog_ports=[ AnalogReceivePort(name='weight', dimension=un.current), AnalogSendPort(name='A', dimension=un.current), AnalogSendPort(name='B', dimension=un.current), AnalogSendPort(name='Isyn', dimension=un.current) ], state_variables=[ StateVariable(name='A', dimension=un.current), StateVariable(name='B', dimension=un.current) ], regimes=[ Regime(name='default', time_derivatives=[ TimeDerivative('A', '(-A + B)/tau_syn'), TimeDerivative('B', '-B/tau_syn') ], transitions=[ OnEvent('spike', target_regime_name='default', state_assignments=[ StateAssignment('B', 'B + weight') ]) ]) ], aliases=['Isyn:=A']) one_to_one_class = ConnectionRule( 'OneToOneClass', standard_library=( "http://nineml.net/9ML/1.0/connectionrules/OneToOne")) self.one_to_one = ConnectionRuleProperties("OneToOne", one_to_one_class, {}) random_fan_in_class = ConnectionRule( name="RandomFanIn", parameters=[Parameter(name="number")], standard_library=( "http://nineml.net/9ML/1.0/connectionrules/RandomFanIn")) exc_random_fan_in = ConnectionRuleProperties( name="RandomFanInProps", definition=random_fan_in_class, properties={'number': 100}) inh_random_fan_in = ConnectionRuleProperties( name="RandomFanInProps", definition=random_fan_in_class, properties={'number': 200}) self.celltype = DynamicsProperties(name="liaf_props", definition=liaf, properties={ 'tau': self.tau, 'theta': self.theta, 'tau_rp': 2.0 * un.ms, 'Vreset': 10.0 * un.mV, 'R': 1.5 * un.Mohm }, initial_values={ "V": 0.0 * un.mV, "t_rpend": 0.0 * un.ms }) ext_stim = DynamicsProperties(name="stim", definition=poisson, properties={'rate': self.input_rate}, initial_values={"t_next": 0.5 * un.ms}) self.psr = DynamicsProperties(name="syn", definition=psr, properties={'tau_syn': self.tau_syn}, initial_values={ "A": 0.0 * un.nA, "B": 0.0 * un.nA }) exc = Population("Exc", self.order * 4, self.celltype) inh = Population("Inh", self.order, self.celltype) ext = Population("Ext", self.order * 5, ext_stim) exc_and_inh = Selection("All", Concatenate((exc, inh))) self.static_ext = DynamicsProperties( "ExternalPlasticity", static, {}, initial_values={"weight": self.Je * un.nA}) static_exc = DynamicsProperties( "ExcitatoryPlasticity", static, {}, initial_values={"weight": self.Je * un.nA}) static_inh = DynamicsProperties( "InhibitoryPlasticity", static, initial_values={"weight": self.Ji * un.nA}) ext_prj = Projection("External", pre=ext, post=exc_and_inh, response=self.psr, plasticity=self.static_ext, connection_rule_properties=self.one_to_one, delay=self.delay, port_connections=[ ('response', 'Isyn', 'post', 'Isyn'), ('plasticity', 'weight', 'response', 'weight') ]) exc_prj = Projection("Excitation", pre=exc, post=exc_and_inh, response=self.psr, plasticity=static_exc, connection_rule_properties=exc_random_fan_in, delay=self.delay, port_connections=[ ('response', 'Isyn', 'post', 'Isyn'), ('plasticity', 'weight', 'response', 'weight') ]) inh_prj = Projection("Inhibition", pre=inh, post=exc_and_inh, response=self.psr, plasticity=static_inh, connection_rule_properties=inh_random_fan_in, delay=self.delay, port_connections=[ ('response', 'Isyn', 'post', 'Isyn'), ('plasticity', 'weight', 'response', 'weight') ]) self.model = Network("brunel_network") self.model.add(ext) self.model.add(exc) self.model.add(inh) self.model.add(exc_and_inh) self.model.add(ext_prj) self.model.add(exc_prj) self.model.add(inh_prj)
], ) ], state_variables=[ StateVariable('V', un.voltage), StateVariable('tspike', un.time), ], analog_ports=[ AnalogSendPort("V", un.voltage), AnalogReducePort("ISyn", un.current, operator="+"), ], event_ports=[ EventSendPort('spikeoutput'), ], parameters=[ Parameter('cm', un.capacitance), Parameter('taurefrac', un.time), Parameter('gl', un.conductance), Parameter('vreset', un.voltage), Parameter('vrest', un.voltage), Parameter('vthresh', un.voltage) ]) coba = Dynamics(name="CobaSyn", aliases=[ "I:=g*(vrev-V)", ], regimes=[ Regime( name="cobadefaultregime", time_derivatives=[
def setUp(self): self.pre_dynamics = Dynamics( name='PreDynamics', state_variables=[StateVariable('SV1', dimension=un.voltage)], regimes=[ Regime('dSV1/dt = -SV1 / P1', transitions=[On('SV1 > P2', do=[OutputEvent('emit')])], name='R1'), ], parameters=[ Parameter('P1', dimension=un.time), Parameter('P2', dimension=un.voltage) ]) self.post_dynamics = Dynamics( name='PostDynamics', state_variables=[StateVariable('SV1', dimension=un.voltage)], regimes=[ Regime('dSV1/dt = -SV1 / P1 + ARP1 / P2', name='R1'), ], analog_ports=[AnalogReceivePort('ARP1', dimension=un.current)], parameters=[ Parameter('P1', dimension=un.time), Parameter('P2', dimension=un.capacitance) ]) self.response_dynamics = Dynamics( name='ResponseDynamics', state_variables=[StateVariable('SV1', dimension=un.current)], regimes=[ Regime('dSV1/dt = -SV1 / P1', transitions=[ On('receive', do=[StateAssignment('SV1', 'SV1 + P2')]) ], name='R1'), ], analog_ports=[AnalogSendPort('SV1', dimension=un.current)], parameters=[ Parameter('P1', dimension=un.time), Parameter('P2', dimension=un.current) ]) self.pre = Population(name="PrePopulation", size=1, cell=DynamicsProperties( name="PreDynamicsProps", definition=self.pre_dynamics, properties={ 'P1': 1 * un.ms, 'P2': -65 * un.mV })) self.post = Population(name="PostPopulation", size=1, cell=DynamicsProperties( name="PostDynamicsProps", definition=self.post_dynamics, properties={ 'P1': 1 * un.ms, 'P2': 1 * un.uF })) self.one_to_one = ConnectionRule( name="OneToOne", standard_library=(NINEML_NS + '/connectionrules/OneToOne')) self.projection = Projection( name="Projection", pre=self.pre, post=self.post, response=DynamicsProperties(name="ResponseProps", definition=self.response_dynamics, properties={ 'P1': 10 * un.ms, 'P2': 1 * un.nA }), connection_rule_properties=ConnectionRuleProperties( name="ConnectionRuleProps", definition=self.one_to_one), delay=1 * un.ms)