This article is one of a series of tutorials designed to provide the new user with insight into how to create models using the GUI. Advanced users may find the Reference section more helpful. Note that the screenshots are from the Mac build of the GUI, and will have a different visual appearance on other platforms.
Fig1: Tab selector
The component editor tab is selected using the tab bar on the left side of the GUI window. The Fig 1 shows the tab bar with the Component editor tab selected. You should now select this tab.
Once the tab is selected, the component editor is laid out as in Fig
The colours highlight the following sections:
Tab selector: This panel is used to change between the different tabs of the GUI. Each tab focuses on a different aspect of model creation.
The current tab is highlighted with a grey background.
Clicking on the divider to the right of this panel will hide and show the panel.
Fig 2: Overview of the component editor tab
Properties panel: This panel is used to edit the properties of the component elements.
Toolbar: The toolbar gives context-sensitive buttons for interacting with the current component that is being edited. Note: Hover the mouse over the buttons for a tooltip description.
As an example we will create a Leaky Integrate and Fire (LIF) neuron with a conductance-based single exponential decaying synapse using the component editor tab. The LIF is a simple neuron model that provides a great example for demonstrating the tools. Before getting started building the model we first have a look at the equations that govern the LIF and synaptic model behaviour and show how these should be broken down for implementation.
The equation for the membrane voltage dynamics is:
where v is the membrane potential, tau is the membrane time constant, I_off and I_syn are the offset and synaptic currents acting on the membrane, C_m is the membrane capacitance and v_rest is the resting membrane potential.
When the voltage crosses a threshold it is reset to a fixed value and the neuron enters a fixed refractory period in which there are no dynamics for the membrane.
The equation for the synaptic current is:
where g_syn is the instantaneous synaptic conductance and E_syn is the synaptic reversal potential.
The instantaneous conductance is modelled as follows:
where tau is the synaptic decay constant, s denotes the index in the set of action potential reaching the synapse, and g-bar is the maximal synaptic conductance. The delta function applies an instantaneous rise of g-max to the synaptic conductance each time an action potential acts on the synapse. This equation is more commonly expressed as the solution:
We have tried with the GUI to spare the user as much concern for the implementation of the model as possible to allow them to focus on the model itself, however in mapping these equations to SpineML components we must spare a little bit of thought to implementation.
Fig3: Diagram of a projection between two populations of neuron_body (blue circles) showing weight_update (green triangles and postsynapse (red squares)
SpineML has three types of neural components: weight_update, post_synapse, and neuron_body. Together the weight_update and postsynapse components form synapses, however the equations that are placed in each need consideration. Weight_updates are calculated for every connection, while postsynapses are calculated for every target neuron.
The diagram in Fig 3 shows this a bit better - there is a projection between the top population of blue neuron_body components and the bottom blue neuron_body components. Every source neuron_body is connected to every adjacent destination neuron_body. There are seven green weight_updates, but only three red postsynapses - one for each destination neuron_body.
So what does this mean for implementation? Everything that must be done on a per connection basis must be put in the weight_update component, and everything else should go in the postsynapse - as they are fewer in number so will apply less computational overhead. For large densely connected populations unnecessary computation in the weight_update can be quite costly to performance.
For this model this involves breaking the model down as follows:
neuron_body:
postsynapse:
and
weight_update:
where each weight_update i applies each input action potential s for that connection (redefined from earlier), and then the contributions for each weight_update i are summed in the postsynapse. This is possible as exponential decays are linearly separable, so can be composed into a single decay without changing the result.
Sorry about the slight added complexity, but we couldn’t think of a method that would preserve the flexibility and performance we desired and not require this step.
Now that we have the equations that describe the neuron and synapse and have broken them into the correct components, we can begin building!
Add a new component using the ‘New component’ button at the top of the component selection panel.
First we shall create a SpineML component for the neuron_body. To do that we must add elements to the component and set their properties to create the behaviour we require.
Fig 4: Component properties panel
First we configure the properties of the component as a whole. The properties panel should look as shown to the right (Fig 4). If it does not then make sure the cursor icon is selected in the toolbox and click on the background of the visualisation pane. The properties should be set as follows:
Now we add Regimes. These contain sets of differential equations that describe the behaviour of the component in one state.
Regimes: These contain the differential equations that describe the dynamics of the component. Regimes can be switched between using Conditionals (see later). {: .info-popout }
There should now be a new Regime named ‘New_Regime_1’ in the visualisation pane which is selected (note the red outline). In the Properties panel there are the properties that can be set for this Regime, which is just the name. Set the name to ‘Integrating’ - note that the visualisation updates to reflect the changes as you type.
The Add Regime button is no longer on the toolbox as we have the Regime selected, so click on the visualisation pane to deselect the Regime and bring it back. Add another Regime and name it ‘Refractory’.
Click on the background of the visualisation pane to return to the Component Properties and set the ‘Initial Regime’ to ‘Integrating’.
We now need to add a differential equation element (called a Time Derivatives), which will contain the differential equation for the neuron membrane potential, to the Integrating Regime:
Fig 5: Time derivative properties panel
Select the new Time Derivative element by clicking on it. Note the dotted outline denoting selection of a sub-element. The context sensitive Properties panel now shows the properties of the Time Derivative. The drop down box ‘Variable’ is empty and there are no options to select. We need to add a State Variable for voltage, which will show up here.
To add the voltage State Variable:
State Variables and Parameters: There are two types of Properties of a component - Parameters and State Variables. Parameters represent numbers that are static during the simulation of a model, while State Variables can change, thus they represent the current state of the system. {: .info-popout }
Fig 6: Right: the toolbar buttons for adding Parameters, State Variables and Aliases. Left: The Params, Vars & Alias box
Now we are in a position to finish the Time Derivative we added earlier:
Now we add the equation for the membrane potential dynamics. This must be in the form of C-style code (for details see here: section A.1.16 MathInline ). As an example here is the membrane potential equation:
(I_off+I_syn)/C_m+(v_rest-v)/tau_m
where the tau_m has been moved across to the other side of the equation.
Note that there are several names that we use here that represent values that are fixed for the duration of the simulation (I_off, C_m, v_rest, tau_m), or inputs into the component (I_syn), but we have not defined them. Consequently the text background is red - showing that there is an error in the text string. To solve this we must add Parameters for the fixed values, and an Analog Input Port for I_syn.
Your component should now look as below:
We now must add the Parameters for the membrane potential equation
To add a Parameter:
Select the red box titled ‘Params, Vars & Alias’ as in [[#Add a State Variable | adding a State Variable]]. |
Click to add four Parameters, and name these Parameters ‘I_off’, ‘C_m’, ‘v_rest’ and ‘tau_m’.
The Parameters can be re-ordered by selecting one and using the up and down buttons on the toolbar.
Set the Dimensions of the Parameters to physiological units (current = nA, capacitance = pF, voltage = mV, time = ms).
Ports: There are three types of Port which carry different types of data between components - Analog Ports carry continuous variable data every timestep of the simulation; Event Ports are analogous to action potential spikes, and trigger discrete events in components; Impulse Ports are event ports that, along with the discrete event, carry a value which can be set by the source component. {: .info-popout }
Ports describe the communications of the component with other components. We need to add an Analog Input Port for the incoming current from the synapses, I_syn.
To add an Analog Port:
The Port is currently configured as an output, or Send port by the ‘Analog Mode’ drop-down box. We want to reconfigure it so that it is an input Port. there are two types of input port: Receive Ports take input from a single source, and connecting multiple sources is not possible; Reduce Ports take input from multiple sources and combine them using a Reduce Operator. Since our neuron may receive currents from multiple synapses, we require a Reduce Port. To configure the Port see Fig 7:
Fig 7: Reduce Port properties panel
The Properties panel should now look as the image to the right.
Now select the Time Derivative, note that the background to the text is white. If this is not the case then recheck the Parameters and Port for errors.
We now have a component with membrane dynamics and current input, but we are still lacking any way for the component to communicate to the outside world, and to enter the refractory period. First we consider communication.
The IAF neuron_body needs two outputs. One is an Event Port to transmit spikes, and the other an Analog Port to send voltage for use in a conductance-based synapse.
To add and configure the Analog Port (Fig 8):
This Port will now transmit the value of the voltage State Variable.
Fig 9: Properties for the Event Port
To add and configure the Event Port (Fig 9):
This Port will send Events when triggered, but we still need to add a mechanism to trigger this Port.
In order to move between Regimes, or perform actions within the component that depend upon conditions being met, we use Transitions.
There are three types of Transition:
For this component we only require OnCondition Transitions. The remaining two Transition types will be described when creating the weight_update component.
All Transition types can contain State Assignments which can update State Variables by assignment - i.e.:
sv1 = sv1+(var1-sv2*exp(var2))
They can also contain EventOut and ImpulseOut which trigger Events and Impulses to be transmitted on set Ports.
The three types of Transition are added using the three toolbox buttons below the cursor arrow button (C: OnCondition; E: OnEvent; I: OnImpulse). Clicking these buttons exits the selection mode (denoted by the cursor arrow) and enters a creation mode for the respective Transition. To add an OnCondition Transition (see Fig 10):
Fig 10: The new OnCondition
Selecting the OnCondition brings three new buttons to the context sensitive toolbar: add State Assignment (=), add EventOut (e^), and add ImpulseOut (I^).
We now need to configure this OnCondition to activate when the neuron reaches a set threshold, then reset the voltage to zero and note the time of the spike (which will be used to return to the ‘Integrating’ Regime after the refractory time period).
We now need to apply some of the lessons learned so far to set up the OnCondition, as we need new Parameters for the threshold and reset voltages, a new State Variable to store the spike time, and a new Parameter for the refractory time period:
These can then be used to configure the OnCondition:
v > v_thresh
Your component should now look similar to that is Fig 11.
Fig 11: Overview of the component at this stage
Fig 12: State Assignment Properties
We need two State Assignments in this OnCondition. These will reset the voltage to v_reset and log the spike time in t_spike.
Fig 13: ‘t_spike’ State Assignment Properties
We now configure the second State Assignment with ‘Variable’ set to ‘t_spike’. We wish to store the current simulation time, so we use the reserved variable t to do so, setting ‘Maths’ to ‘t’, as shown to the right (Fig 13).
The final thing that the component must do when the voltage threshold is crossed is emit an action potential, or spike. To do this we add an EventOut to the OnCondition.
While in the ‘Refractory’ Regime there are no Time Derivative and the system does not update. We therefore need to add a means of returning to the ‘Integrating’ Regime after the refractory time period has elapsed to allow the component to function again. We do this using another OnCondition Transition.
t > t_spike+t_refrac
Now when t has progressed past t_spike by t_refrac (i.e. the current time is the spike time + the refractory time period) the component will transition back into the ‘Integrating’ Regime.
The component is now complete. However in order to use it in models we must first validate and store the model. To do this:
or
To save the model to a file use the ‘Save component’ and ‘Save component as…’ items in the ‘File’ menu. The component will be stored as a SpineML xml file. The model does not have to be stored to be saved, but will be validated before saving.
If there are any validation problems with the model these will be reported and the model will not be stored or saved! Only correctly formed models can be stored or saved
Fig 14: The finished component
We will now quickly run through the steps to test this neuron - note that no explanation will be given here as these are subjects for the remaining tutorials.
You should see regular spiking.
Note: if you play with the parameter and run the experiment again the plot will update with the new results!
It is worth noting that this weight_update component contains no Time Derivatives or Analog Ports. This means that everything in the component acts in response to Events or Impulses - it is Event Driven. By making the weight_update Event Driven the simulation can calculate synapses much faster. You should always aim to make your weight_updates Event Driven for this reason. That said, if it is necessary to add Time Derivatives or Analog Ports then this is possible, however you models will take a significant performance hit for doing so. {: .info-popout }
The synapse weight_update component is simple, but introduces several new component elements - OnEvent Transitions, Impulse Ports and ImpulseOut elements. This section of the tutorial assumes that you have read the previous section.
This component takes a spike from a neuron_body and sends on an Impulse of the connection weight to the postsynapse. It converts an Event into an Event with a value (an Impulse) with the value being the weight of the connection.
Fig 15: Event Port properties
We first add the input to the component, which is an Event Port (this will be connected to the Event Send Port of the neuron_body):
Currently this event port cannot affect the component behaviour, and requires an OnEvent to trigger when an event is received. First, however, it is useful to add the output port for the component - an Impulse Port.
Fig 16: Impulse Port properties
Now we add an Impulse port that will be the output of the component:
This configures the Impulse port to send the value ‘g’ when it is triggered - note that g is a Parameter and thus will not change during the simulation as this synapse cannot learn. To implement a learning synapse g would be a State Variable.
We must now connect the input to the output, which we do using a type of Transition we have not previously used - an OnEvent. The OnEvent is triggered when an Event arrives on the specified Event Port, and can then execute a set of State assignments, EventOuts and ImpulseOuts. We will use the OnEvent to trigger an ImpulseOut and pass on the weight to the postsynapse component.
Fig 17: OnEvent properties
This will be triggered every time the neuron_body connected to the Port ‘spike’ sends an Event.
Now we need to get the OnEvent to send an Impulse.
Fig 18: ImpulseOut Properties
Now every time the component receives an Event on Port ‘spike’ it will send an Impulse on Port ‘g’. This completes the component! Now validate and store the component and save to hard drive if you wish. Fig 19 shows the finished component.
Fig 19: Complete weight_update component
The final component in this tutorial is the exponential decaying postsynapse. This mainly uses the techniques described in the previous sections, so detail will only be provided for the new elements - the Alias and the OnImpulse.
Fig 20: Postsynapse component after Initial setup
dg/dt = -g/tau_syn
The component should now look like shown to the right (Fig 20).
Note: we have added an input Port g_in, which is not the same name as the output Port g of the weight_update. This is not an issue as the Network Editor will allow differently named Ports to be joined as long as the type and dimensions (if Analog) are consistent, or if Analog one of the Analog Ports has no dimensionality.
Note2: The ‘v’ Port that we have added will need to be connected to the postsynapsic neuron body, this will be covered in the Network Editor tutorial.
Now we will investigate adding an Alias.
Aliases are used for two purposes. One is to reduce the length of mathematical expressions by allowing the use of variables which represent a value derived in a separate equation:
dv/dt = I_sum/C_m - v; I_sum = I_off + I_syn + I_noise
Here I_sum is an Alias used to simplify the differential equation.
The second use of Aliases is to derive values for Analog or Impulse Port output. An Analog or Impulse Port may wish to transmit a value derived from the Inputs, Parameters, State Variables and other Aliases of the component. In this case the output I_syn uses the voltage from the neuron_body and the reversal potential (E) to transform the conductance of the synapse into a current.
Fig 21: Alias Properties
To add the Alias for I_syn:
g*(E-v)
Now the final step in creating this component is to take input from the Impulse Port. To do so we need to use an OnImpulse Transition, the remaining Transition type that we have not used so far.
Fig 22: State Assignment Properties
To add an OnImpulse:
g+g_in
The component is now finished! validate and store and then save to hard drive if you wish. See Fig 23 for the finished component.
Fig 23: Finished postsynapse component
I hope this tutorial has introduced you to how to create components in the GUI. Finished versions of the components described here can be found below, and the second tutorial will instruct you how to combine components into networks consisting of neural populations connected by projections. This will also allow you to build networks to test out the components you have just created!
Note to selves: ADD FINISHED COMPONENTS HERE