===================
User layer tutorial
===================

To start an interactive Python session, type `python` (or `ipython`, if you have that installed) in a terminal window.
(This might be different on Windows?)::

    $ python
    
Now we can import the user layer module::

    >>> import nineml.user_layer as nineml
    
Let's start by creating a spiking node::

    >>> exc_celltype = nineml.SpikingNodeType(
    ...                     name="Excitatory neuron type",
    ...                     definition="IaF_tau.xml",
    ...                     )
    
The file "IaF_tau.xml" does not have to exist. Normally, you would give a full
URL here. Also note that we did not set any of the parameters/properties of the
node. So let's try again::

    >>> parameters = {"membraneCapacitance": (1.0, "nF"),
    ...               "membraneTimeConstant": (20.0, "ms"),
    ...               "refractoryTime": (5.0, "ms"),
    ...               "threshold": (-50.0, "mV"),
    ...               "restingPotential": (-65.0, "mV"),
    ...               "resetPotential": (-70.0, "mV")}
    >>> exc_celltype = nineml.SpikingNodeType(
    ...                     name="Excitatory neuron type",
    ...                     definition="http://svn.incf.org/svn/nineml/trunk/catalog/neurons/IaF_tau.xml",
    ...                     parameters=parameters
    ...                     )
    
In the current version, there is no checking that the parameters supplied have the correct names.
This feature will be added soon. It is now easy to get information about the node::

    >>> exc_celltype
    SpikingNodeType(name="Excitatory neuron type", definition="http://svn.incf.org/svn/nineml/trunk/catalog/neurons/IaF_tau.xml")
    >>> exc_celltype.name
    'Excitatory neuron type'
    >>> exc_celltype.definition.url
    'http://svn.incf.org/svn/nineml/trunk/catalog/neurons/IaF_tau.xml'
    >>> exc_celltype.parameters                                                 #doctest: +NORMALIZE_WHITESPACE
    ParameterSet({'membraneCapacitance': Parameter(name=membraneCapacitance, value=1.0, unit=nF),
    'refractoryTime': Parameter(name=refractoryTime, value=5.0, unit=ms), 'threshold':
    Parameter(name=threshold, value=-50.0, unit=mV), 'restingPotential':
    Parameter(name=restingPotential, value=-65.0, unit=mV), 'membraneTimeConstant':
    Parameter(name=membraneTimeConstant, value=20.0, unit=ms), 'resetPotential':
    Parameter(name=resetPotential, value=-70.0, unit=mV)})

To see what XML will be generated for this node::

    >>> from lxml import etree
    >>> print etree.tostring(exc_celltype.to_xml(), pretty_print=True)          #doctest: +NORMALIZE_WHITESPACE
    <node name="Excitatory neuron type">
      <definition>
        <url>http://svn.incf.org/svn/nineml/trunk/catalog/neurons/IaF_tau.xml</url>
      </definition>
      <properties>
        <membraneCapacitance>
          <value>1.0</value>
          <unit>nF</unit>
        </membraneCapacitance>
        <membraneTimeConstant>
          <value>20.0</value>
          <unit>ms</unit>
        </membraneTimeConstant>
        <refractoryTime>
          <value>5.0</value>
          <unit>ms</unit>
        </refractoryTime>
        <threshold>
          <value>-50.0</value>
          <unit>mV</unit>
        </threshold>
        <restingPotential>
          <value>-65.0</value>
          <unit>mV</unit>
        </restingPotential>
        <resetPotential>
          <value>-70.0</value>
          <unit>mV</unit>
        </resetPotential>
      </properties>
    </node>
    
Suppose that the inhibitory neurons will use the same model, but with some
randomness in their membrane time constants::

    >>> tau_distr = nineml.RandomDistribution(
    ...                 name="normal(20.0,3.0)",                
    ...                 definition="http://svn.incf.org/svn/nineml/trunk/catalog/randomdistributions/normal_distribution.xml",
    ...                 parameters={'standardDeviation': (3.0, "dimensionless"),
    ...                             'mean': (20.0, "dimensionless")})
    >>> inh_celltype = nineml.SpikingNodeType(
    ...                 name="Inhibitory neuron type",
    ...                 reference=exc_celltype.name,
    ...                 parameters={'membraneTimeConstant': (tau_distr, "ms")})
    
Now we have specified that `inh_celltype` should use the same definition and
parameters as `exc_celltype`, except for the membrane time constant. For now,
`inh_celltype` is unresolved: we haven't matched the reference to the actual object::

    >>> inh_celltype.reference
    'Excitatory neuron type'
    >>> inh_celltype
    SpikingNodeType(name="Inhibitory neuron type", UNRESOLVED)
    
Normally, you don't need to worry about resolving components -- it is done
automatically when you build a full model -- but we will do it manually for
illustration purposes::

    >>> inh_celltype.resolve(exc_celltype)
    >>> inh_celltype          
    SpikingNodeType(name="Inhibitory neuron type", definition="http://svn.incf.org/svn/nineml/trunk/catalog/neurons/IaF_tau.xml")
    >>> inh_celltype.parameters                                                 #doctest: +NORMALIZE_WHITESPACE
    ParameterSet({'membraneCapacitance': Parameter(name=membraneCapacitance, value=1.0, unit=nF),
    'refractoryTime': Parameter(name=refractoryTime, value=5.0, unit=ms),
    'threshold': Parameter(name=threshold, value=-50.0, unit=mV),
    'restingPotential': Parameter(name=restingPotential, value=-65.0, unit=mV),
    'membraneTimeConstant': Parameter(name=membraneTimeConstant,
    value=RandomDistribution(name="normal(20.0,3.0)",
    definition="http://svn.incf.org/svn/nineml/trunk/catalog/randomdistributions/normal_distribution.xml"), unit=ms),
    'resetPotential': Parameter(name=resetPotential, value=-70.0, unit=mV)})
    
OK, we've got some prototypes for the neuron models, now let's create some populations of neurons::

    >>> grid2D = nineml.Structure(
    ...                 name="2D grid",
    ...                 definition="http://svn.incf.org/svn/nineml/trunk/catalog/networkstructures/2Dgrid.xml",
    ...                 parameters={'fillOrder': ("sequential", None),
    ...                             'aspectRatioXY': (1.0, "dimensionless"),
    ...                             'dx': (10.0, u"µm"), 'dy': (10.0, u"µm"),
    ...                             'x0': (0.0, u"µm"), 'y0': (0.0, u"µm")})
    >>> exc_cells = nineml.Population(
    ...                 name="Excitatory cells",
    ...                 number=100,
    ...                 prototype=exc_celltype,
    ...                 positions=nineml.PositionList(structure=grid2D))

(If your terminal won't let you type "µm" (Alt-m), "um" works just as well). Here
we have specified that the excitatory cells should be laid out on a square grid.
The actual positions won't be calculated until the model is simulated. We can
also specify the cell positions explicitly as a list of (x,y,z) coordinates::

    >>> positions = [(10.0*x,0.0,0.0) for x in range(25)]
    >>> inh_cells = nineml.Population(
    ...                 name="Inhibitory cells",
    ...                 number=25,
    ...                 prototype=inh_celltype,
    ...                 positions=nineml.PositionList(positions=positions))
    
A population cannot exist by itself: we have to add it to a `Group`::

    >>> network = nineml.Group("Network")
    >>> network.add(exc_cells, inh_cells)
    
To create a network, we need to create some more components: for the post-synaptic
response, for the connection type (management of weights, delays, etc.) and the
connectivity rule::

    >>> connection_rule = nineml.ConnectionRule(
    ...                 name="random connections",
    ...                 definition="http://svn.incf.org/svn/nineml/trunk/catalog/connectionrules/fixed_probability.xml",
    ...                 parameters={'p_connect': (0.1, "dimensionless")})
    >>> exc_psr = nineml.SynapseType(
    ...                 name="Excitatory post-synaptic response",
    ...                 definition="http://svn.incf.org/svn/nineml/trunk/catalog/postsynapticresponses/exp_g.xml",
    ...                 parameters={'decayTimeConstant': (5.0, "ms"), 'reversalPotential': (0.0, "mV"), 'unitAmplitude': (0.1, "nS")})
    >>> inh_psr = nineml.SynapseType(
    ...                 name="Inhibitory post-synaptic response",
    ...                 reference=exc_psr.name,
    ...                 parameters={'reversalPotential': (-70.0, "mV")})
    >>> connection_type = nineml.ConnectionType(
    ...                 name="Static connections",
    ...                 definition="http://svn.incf.org/svn/nineml/trunk/catalog/connectiontypes/static_connection.xml",
    ...                 parameters={'delay': (0.3, "ms")})
    
And now we can create our Projections::

    >>> exc2all = nineml.Projection(
    ...                 name="Excitatory connections",
    ...                 source=exc_cells,
    ...                 target=network,
    ...                 rule=connection_rule,
    ...                 synaptic_response=exc_psr,
    ...                 connection_type=connection_type)
    >>> inh2all = nineml.Projection(
    ...                 name="Inhibitory connections",
    ...                 source=inh_cells,
    ...                 target=network,
    ...                 rule=connection_rule,
    ...                 synaptic_response=inh_psr,
    ...                 connection_type=connection_type)
    
and add them to our Group::

    >>> network.add(exc2all, inh2all)
    
Finally, we create a container for the entire model and add the group to it::

    >>> model = nineml.Model("User-layer tutorial model")
    >>> model.add_group(network)

And now we can export it as XML::

    >>> #model.write("user_layer_tutorial_model.xml")
    >>> import sys
    >>> model.write(sys.stdout)                                                 #doctest: +REPORT_UDIFF
    <?xml version='1.0' encoding='UTF-8'?>
    <nineml xmlns="http://nineml.org/9ML/0.1" name="User-layer tutorial model">
      <node name="Inhibitory post-synaptic response">
        <definition>
          <url>http://svn.incf.org/svn/nineml/trunk/catalog/postsynapticresponses/exp_g.xml</url>
        </definition>
        <properties>
          <decayTimeConstant>
            <value>5.0</value>
            <unit>ms</unit>
          </decayTimeConstant>
          <unitAmplitude>
            <value>0.1</value>
            <unit>nS</unit>
          </unitAmplitude>
          <reversalPotential>
            <value>-70.0</value>
            <unit>mV</unit>
          </reversalPotential>
        </properties>
      </node>
      <node name="Excitatory post-synaptic response">
        <definition>
          <url>http://svn.incf.org/svn/nineml/trunk/catalog/postsynapticresponses/exp_g.xml</url>
        </definition>
        <properties>
          <decayTimeConstant>
            <value>5.0</value>
            <unit>ms</unit>
          </decayTimeConstant>
          <unitAmplitude>
            <value>0.1</value>
            <unit>nS</unit>
          </unitAmplitude>
          <reversalPotential>
            <value>0.0</value>
            <unit>mV</unit>
          </reversalPotential>
        </properties>
      </node>
      <node name="Inhibitory neuron type">
        <definition>
          <url>http://svn.incf.org/svn/nineml/trunk/catalog/neurons/IaF_tau.xml</url>
        </definition>
        <properties>
          <membraneCapacitance>
            <value>1.0</value>
            <unit>nF</unit>
          </membraneCapacitance>
          <membraneTimeConstant>
            <value>
              <reference>normal(20.0,3.0)</reference>
            </value>
            <unit>ms</unit>
          </membraneTimeConstant>
          <refractoryTime>
            <value>5.0</value>
            <unit>ms</unit>
          </refractoryTime>
          <threshold>
            <value>-50.0</value>
            <unit>mV</unit>
          </threshold>
          <restingPotential>
            <value>-65.0</value>
            <unit>mV</unit>
          </restingPotential>
          <resetPotential>
            <value>-70.0</value>
            <unit>mV</unit>
          </resetPotential>
        </properties>
      </node>
      <node name="normal(20.0,3.0)">
        <definition>
          <url>http://svn.incf.org/svn/nineml/trunk/catalog/randomdistributions/normal_distribution.xml</url>
        </definition>
        <properties>
          <standardDeviation>
            <value>3.0</value>
            <unit>dimensionless</unit>
          </standardDeviation>
          <mean>
            <value>20.0</value>
            <unit>dimensionless</unit>
          </mean>
        </properties>
      </node>
      <node name="Excitatory neuron type">
        <definition>
          <url>http://svn.incf.org/svn/nineml/trunk/catalog/neurons/IaF_tau.xml</url>
        </definition>
        <properties>
          <membraneCapacitance>
            <value>1.0</value>
            <unit>nF</unit>
          </membraneCapacitance>
          <membraneTimeConstant>
            <value>20.0</value>
            <unit>ms</unit>
          </membraneTimeConstant>
          <refractoryTime>
            <value>5.0</value>
            <unit>ms</unit>
          </refractoryTime>
          <threshold>
            <value>-50.0</value>
            <unit>mV</unit>
          </threshold>
          <restingPotential>
            <value>-65.0</value>
            <unit>mV</unit>
          </restingPotential>
          <resetPotential>
            <value>-70.0</value>
            <unit>mV</unit>
          </resetPotential>
        </properties>
      </node>
      <node name="Static connections">
        <definition>
          <url>http://svn.incf.org/svn/nineml/trunk/catalog/connectiontypes/static_connection.xml</url>
        </definition>
        <properties>
          <delay>
            <value>0.3</value>
            <unit>ms</unit>
          </delay>
        </properties>
      </node>
      <node name="random connections">
        <definition>
          <url>http://svn.incf.org/svn/nineml/trunk/catalog/connectionrules/fixed_probability.xml</url>
        </definition>
        <properties>
          <p_connect>
            <value>0.1</value>
            <unit>dimensionless</unit>
          </p_connect>
        </properties>
      </node>
      <node name="2D grid">
        <definition>
          <url>http://svn.incf.org/svn/nineml/trunk/catalog/networkstructures/2Dgrid.xml</url>
        </definition>
        <properties>
          <fillOrder>
            <value>sequential</value>
          </fillOrder>
          <aspectRatioXY>
            <value>1.0</value>
            <unit>dimensionless</unit>
          </aspectRatioXY>
          <dx>
            <value>10.0</value>
            <unit>µm</unit>
          </dx>
          <dy>
            <value>10.0</value>
            <unit>µm</unit>
          </dy>
          <y0>
            <value>0.0</value>
            <unit>µm</unit>
          </y0>
          <x0>
            <value>0.0</value>
            <unit>µm</unit>
          </x0>
        </properties>
      </node>
      <group name="Network">
        <population name="Inhibitory cells">
          <number>25</number>
          <prototype>Inhibitory neuron type</prototype>
          <positions>
            <position y="0.0" x="0.0" z="0.0" unit="um"/>
            <position y="0.0" x="10.0" z="0.0" unit="um"/>
            <position y="0.0" x="20.0" z="0.0" unit="um"/>
            <position y="0.0" x="30.0" z="0.0" unit="um"/>
            <position y="0.0" x="40.0" z="0.0" unit="um"/>
            <position y="0.0" x="50.0" z="0.0" unit="um"/>
            <position y="0.0" x="60.0" z="0.0" unit="um"/>
            <position y="0.0" x="70.0" z="0.0" unit="um"/>
            <position y="0.0" x="80.0" z="0.0" unit="um"/>
            <position y="0.0" x="90.0" z="0.0" unit="um"/>
            <position y="0.0" x="100.0" z="0.0" unit="um"/>
            <position y="0.0" x="110.0" z="0.0" unit="um"/>
            <position y="0.0" x="120.0" z="0.0" unit="um"/>
            <position y="0.0" x="130.0" z="0.0" unit="um"/>
            <position y="0.0" x="140.0" z="0.0" unit="um"/>
            <position y="0.0" x="150.0" z="0.0" unit="um"/>
            <position y="0.0" x="160.0" z="0.0" unit="um"/>
            <position y="0.0" x="170.0" z="0.0" unit="um"/>
            <position y="0.0" x="180.0" z="0.0" unit="um"/>
            <position y="0.0" x="190.0" z="0.0" unit="um"/>
            <position y="0.0" x="200.0" z="0.0" unit="um"/>
            <position y="0.0" x="210.0" z="0.0" unit="um"/>
            <position y="0.0" x="220.0" z="0.0" unit="um"/>
            <position y="0.0" x="230.0" z="0.0" unit="um"/>
            <position y="0.0" x="240.0" z="0.0" unit="um"/>
          </positions>
        </population>
        <population name="Excitatory cells">
          <number>100</number>
          <prototype>Excitatory neuron type</prototype>
          <positions>
            <structure>2D grid</structure>
          </positions>
        </population>
        <projection name="Inhibitory connections">
          <source>Inhibitory cells</source>
          <target>Network</target>
          <rule>random connections</rule>
          <response>Inhibitory post-synaptic response</response>
          <synapse>Static connections</synapse>
        </projection>
        <projection name="Excitatory connections">
          <source>Excitatory cells</source>
          <target>Network</target>
          <rule>random connections</rule>
          <response>Excitatory post-synaptic response</response>
          <synapse>Static connections</synapse>
        </projection>
      </group>
    </nineml>

To ensure that our model is consistent, run::

    >>> model.check()
    
This exports the model to XML, reads it back in, and checks that the model is
unchanged.