Arbor, "noise" sources", stochastic differential equations: desire for benchmarking and validation - help required #1986
-
Dear All, dear Developers, together with my colleagues, I committed (by a grant with the EU/ERA-NET, called Arbor-IO) to investigate and validate SDEs and "noise sources" of Arbor. While I am waiting for the next Arbor release, where the "noise sources" will be available, I need some input and help. May I ask you to clarify whether, upon a change in dt, the variance of the Wiener process (i.e. the term premultiplying the gauss-distributed pseudorandom number on the right hand side of each SDE, scales with the square root of dt ? I would like to publish a short and concise document, to be anyway submitted to EIC-EU Project Officer and Reviewers, including a
The piece of information on the scaling with 'dt' and 'sqrt(dt)' are key to us at this point. If it does not scale like 'sqrt(dt)' then we won't be able to match control simulations. Thank you in advance |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 5 replies
-
Dear Michele, SDE support is still unreleased, but the scaling is indeed with the square root of the However, we do not have built-in support for random current sources, so a workaround Looking forward to hearing about your progress. Best regards |
Beta Was this translation helpful? Give feedback.
-
Hi Michele, from my reading of the code and documentation, I assume an implmentation like below would be a feasible option
and give you a random-walk-like current. It could also be possible to use See also #1987. |
Beta Was this translation helpful? Give feedback.
-
Made together with @boeschf and @thorstenhater, here is a multicore demo that simulates OU current noise and outputs numpy arrays with the voltage values. There current version runs on boeschf SDE branch as it's not merged into arbor master yet. To build from source:
Then update the install path in the import sys
import importlib.util
import os.path
##### IF INSTALLED USING PIP:
#ARBOR_LOCATION = 'default'
ARBOR_BUILD_CATALOGUE = 'arbor-build-catalogue'
#### IF INSTALLED FROM SOURCE:
ARBOR_REPOSITORY = '/home/llandsmeer/tmp/a-e/arbor'
ARBOR_LOCATION = os.path.join(ARBOR_REPOSITORY,
'build/prefix/lib/python3.10/site-packages/arbor/__init__.py')
ARBOR_BUILD_CATALOGUE = os.path.join(ARBOR_REPOSITORY,
'build/prefix/bin/arbor-build-catalogue')
if ARBOR_LOCATION != 'default':
spec = importlib.util.spec_from_file_location('arbor', ARBOR_LOCATION)
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module
spec.loader.exec_module(module)
# END INSTALLATION OPTIONS
import numpy as np
import re
import subprocess
import tempfile
import arbor
import matplotlib.pyplot as plt
mechanism_source = '''
NEURON {
SUFFIX noise
NONSPECIFIC_CURRENT i
RANGE mu, theta, sigma
}
PARAMETER {
mu = 0
theta = 1
sigma = 1
}
STATE { x }
INITIAL { x=0 }
WHITE_NOISE { W }
DERIVATIVE dX {
x' = (mu - x)*theta + sigma*W
}
BREAKPOINT {
SOLVE dX METHOD stochastic
i = x
}
'''
def build_noise_catalogue():
with tempfile.TemporaryDirectory() as tmpdir:
with open(os.path.join(tmpdir, 'noise.mod'), 'w') as f:
print(mechanism_source, file=f)
out = subprocess.getoutput(f'{ARBOR_BUILD_CATALOGUE} noise {tmpdir}')
m = re.search('[^ ]*\.so', out)
if m is None:
print(out)
exit(1)
return arbor.load_catalogue(m.group(0))
def make_cable_cell(gid):
tree = arbor.segment_tree()
soma = tree.append(arbor.mnpos, arbor.mpoint(-12, 0, 0, 6), arbor.mpoint(0, 0, 0, 6), tag=1)
labels = arbor.label_dict(dict(soma="(tag 1)", root= "(root)"))
decor = arbor.decor()
decor.paint('"soma"', arbor.density("noise"))
return arbor.cable_cell(tree, labels, decor)
class Recipe(arbor.recipe):
def __init__(self, ncells=100):
arbor.recipe.__init__(self)
self.ncells = ncells
self.props = arbor.neuron_cable_properties()
self.props.catalogue.extend(build_noise_catalogue(), '')
def num_cells(self): return self.ncells
def cell_description(self, gid): return make_cable_cell(gid)
def cell_kind(self, gid): return arbor.cell_kind.cable
def connections_on(self, gid): return []
def event_generators(self, gid): return []
def probes(self, gid): return [arbor.cable_probe_membrane_voltage('"root"')]
def global_properties(self, kind): return self.props
# (11) Instantiate recipe
recipe = Recipe(ncells=10)
ctx = arbor.context('avail_threads')
sim = arbor.simulation(recipe, ctx)
handles = [sim.sample((gid, 0), arbor.regular_schedule(1)) for gid in range(recipe.num_cells())]
sim.run(100)
times = np.array(sim.samples(handles[0])[0][0][:,0])
results = np.array([sim.samples(handles[gid])[0][0][:, 1] for gid in range(recipe.num_cells())])
plt.plot(times,results.T)
plt.show() |
Beta Was this translation helpful? Give feedback.
-
Hi @mgiugliano, we had a breaking change to our APIs at some point between September and now. Just swap def make_cable_cell(gid):
tree = arbor.segment_tree()
soma = tree.append(arbor.mnpos, arbor.mpoint(-12, 0, 0, 6), arbor.mpoint(0, 0, 0, 6), tag=1)
labels = arbor.label_dict(dict(soma="(tag 1)", root= "(root)"))
decor = arbor.decor()
decor.paint('"soma"', arbor.density("noise"))
return arbor.cable_cell(tree, decor, labels) |
Beta Was this translation helpful? Give feedback.
-
For posterity, here is Google Colab notebook that runs the demo too. https://colab.research.google.com/drive/1MQpfdrpxzTqGvRp-tc8QCpk2BKNEOR-b?usp=sharing |
Beta Was this translation helpful? Give feedback.
Hi @mgiugliano,
we had a breaking change to our APIs at some point between September and now. Just swap
the arguments to the cable cell constructor as mentioned in the error: