-
Brent Huisman authoredUnverified5447e2a8
Simulations
From recipe to simulation
To build a simulation the following concepts are needed:
- an :class:`arbor.recipe` that describes the cells and connections in the model;
- an :class:`arbor.context` used to execute the simulation.
The workflow to build a simulation is to first generate an :class:`arbor.domain_decomposition` based on the :class:`arbor.recipe` and :class:`arbor.context` describing the distribution of the model over the local and distributed hardware resources (see :ref:`pydomdec`). Then, the simulation is build using this :class:`arbor.domain_decomposition`.
import arbor
# Get a communication context (with 4 threads, no GPU)
context = arbor.context(threads=4, gpu_id=None)
# Initialise a recipe of user defined type my_recipe with 100 cells.
n_cells = 100
recipe = my_recipe(n_cells)
# Get a description of the partition of the model over the cores.
decomp = arbor.partition_load_balance(recipe, context)
# Instatitate the simulation.
sim = arbor.simulation(recipe, decomp, context)
# Run the simulation for 2000 ms with time stepping of 0.025 ms
tSim = 2000
dt = 0.025
sim.run(tSim, dt)
The executable form of a model. A simulation is constructed from a recipe, and then used to update and monitor the model state.
Simulations take the following inputs:
The constructor takes
- an :class:`arbor.recipe` that describes the model;
- an :class:`arbor.domain_decomposition` that describes how the cells in the model are assigned to hardware resources;
- an :class:`arbor.context` which is used to execute the simulation.
Simulations provide an interface for executing and interacting with the model:
- Specify what data (spikes, probe results) to record.
- Advance the model state by running the simulation up to some time point.
- Retrieve recorded data.
- Reset simulator state back to initial conditions.
Constructor:
Updating Model State:
Recording spike data:
Sampling probes:
Types:
Enumeration for event time binning policy.
Enumeration for spike recording policy.
Enumeration for deteriming sampling policy.
Recording spikes
By default, spikes are not recorded. Recording is enabled with the :py:func:`simulation.record` method, which takes a single argument instructing the simulation object to record no spikes, all locally generated spikes, or all spikes generated by any MPI rank.
Spikes recorded during a simulation are returned as a NumPy structured datatype with two fields,
source
and time
. The source
field itself is a structured datatype with two fields,
gid
and index
, identifying the spike detector that generated the spike.
import arbor
# Instatitate the simulation.
sim = arbor.simulation(recipe, decomp, context)
# Direct the simulation to record all spikes.
sim.record(arbor.spike_recording.all)
# Run the simulation for 2000 ms with time stepping of 0.025 ms
tSim = 2000
dt = 0.025
sim.run(tSim, dt)
# Print the spikes and according spike time
for s in sim.spikes():
print(s)
>>> ((0,0), 2.15168) >>> ((1,0), 14.5235) >>> ((2,0), 26.9051) >>> ((3,0), 39.4083) >>> ((4,0), 51.9081) >>> ((5,0), 64.2902) >>> ((6,0), 76.7706) >>> ((7,0), 89.1529) >>> ((8,0), 101.641) >>> ((9,0), 114.125)
Recording samples
Definitions
- probe
-
A measurement that can be perfomed on a cell. Each cell kind will have its own sorts of probe; Cable cells (:attr:`arbor.cable_probe`) allow the monitoring of membrane voltage, total membrane current, mechanism state, and a number of other quantities, measured either over the whole cell, or at specific sites (see :ref:`pycablecell-probes`).
Probes are described by probe addresses, and the collection of probe addresses for a given cell is provided by the :class:`recipe` object. One address may correspond to more than one probe: as an example, a request for membrane voltage on a cable cell at sites specified by a location expression will generate one probe for each site in that location expression.
- probe id
- A designator for one or more probes as specified by a recipe. The probe id is a :class:`cell_member` refering to a specific cell by gid, and the index into the list of probe addresses returned by the recipe for that gid.
- metadata
- Each probe has associated metadata describing, for example, the location on a cell where the measurement is being taken, or other such identifying information. Metadata for the probes associated with a probe id can be retrieved from the simulation object, and is also provided along with any recorded samples.
- sample
- A record of data corresponding to the value at a specific probe at a specific time.
- schedule
- An object representing a series of monotonically increasing points in time, used for determining sample times (see :ref:`pyrecipe`).
Procedure
There are three parts to the process of recording cell data over a simulation.
Describing what to measure.
The recipe object must provide a method :py:func:`recipe.get_probes` that returns a list of probe addresses for the cell with a given
gid
. The kth element of the list corresponds to the probe id(gid, k)
.Each probe address is an opaue object describing what to measure and where, and each cell kind will have its own set of functions for generating valid address specifications. Possible cable cell probes are described in the cable cell documentation: :ref:`pycablecell-probes`.
Instructing the simulator to record data.
Recording is set up with the method :py:func:`simulation.sample` as described above. It returns a handle that is used to retrieve the recorded data after simulation.
Retrieve recorded data.
The method :py:func:`simulation.samples` takes a handle and returns the recorded data as a list, with one entry for each probe associated with the probe id that was used in step 2 above. Each entry will be a tuple
(data, meta)
wheremeta
is the metadata associated with the probe, anddata
contains all the data sampled on that probe over the course of the simulation.The contents of
data
will depend upon the specifics of the probe, but note:
- The object type and structure of
data
is fully determined by the metadata.- All currently implemented probes return data that is a NumPy array, with one row per sample, first column being sample time, and the remaining columns containing the corresponding data.
import arbor
# [... define recipe, decomposition, context ... ]
# Initialize simulation:
sim = arbor.simulation(recipe, decomp, context)
# Sample probe id (0, 0) (first probe id on cell 0) every 0.1 ms with exact sample timing:
handle = sim.sample((0, 0), arbor.regular_schedule(0.1), arbor.sampling_policy.exact)
# Run simulation and retrieve sample data from the first probe associated with the handle.
sim.run(tfinal=3, dt=0.1)
data, meta = sim.samples(handle)[0]
print(data)
>>> [[ 0. -50. ] >>> [ 0.1 -55.14412111] >>> [ 0.2 -59.17057625] >>> [ 0.3 -62.58417912] >>> [ 0.4 -65.47040168] >>> [ 0.5 -67.80222861] >>> [ 0.6 -15.18191623] >>> [ 0.7 27.21110919] >>> [ 0.8 48.74665099] >>> [ 0.9 48.3515727 ] >>> [ 1. 41.08435987] >>> [ 1.1 33.53571111] >>> [ 1.2 26.55165892] >>> [ 1.3 20.16421752] >>> [ 1.4 14.37227532] >>> [ 1.5 9.16209063] >>> [ 1.6 4.50159342] >>> [ 1.7 0.34809083] >>> [ 1.8 -3.3436289 ] >>> [ 1.9 -6.61665687] >>> [ 2. -9.51020525] >>> [ 2.1 -12.05947812] >>> [ 2.2 -14.29623969] >>> [ 2.3 -16.24953688] >>> [ 2.4 -17.94631322] >>> [ 2.5 -19.41182385] >>> [ 2.6 -52.19519009] >>> [ 2.7 -62.53349949] >>> [ 2.8 -69.22068995] >>> [ 2.9 -73.41691825]]