You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As we discussed, the next big feature to implement are synaptic connections. To start, deal with explicit synapses given with synapses.connect(i=..., j=...). To do this, you'll have to implement LEMSDevice.synapses_connect which will be called instead of the original Synapses.connect function (it takes the same arguments as Synapses.connect, but note that it starts like this:
i.e. you have "two self arguments", self corresponds to the LEMSDevice and synapses is the Synapses object.
When connecting synapses works in this way, the next step is to support synaptic connections defined by expressions/patterns (probabilistic connections, one-to-one connections, etc.). As discussed with Padraig, this is not something that we can do in the generated LEMS/NeuroML code, but instead Brian will generate the connections and then you'll include the generated connections in the XML file in the same way as if the user had called Synapses.connect(i=..., j=...) directly. IMO, the best way to implement it would be to have LEMSDevice.synapses_connect first call the original Synapses.connect with the given arguments and then pass the generated values for i and j to NeuroML. In the beginning, only support a single call to connect for each Synapses object (i.e. raise a NotImplementedError for a second call). Alternatively (actually that might be even easier and naturally supports multiple connect calls): do not overwrite Synapses.connect at all, simply check Synapses.i and Synapses.j for all Synapses objects in the network and create the corresponding synapses.
However, all of this will not work with the current design of LEMSDevice because the expressions for generating synapses refer to variables that are not actually stored anywhere. E.g. you could define spatial connectivity with something like this:
group=NeuronGroup(100, '''dv/dt = ... : volt x : meter y : meter''', threshold='v>v_th')
group.x='(x % 10) * 50*um'group.y='(x / 10) * 50*um'synapses=Synapses(group, group, ...)
synapses.connect('sqrt((x_pre - x_post)**2 + (y_pre - y_post)**2) < 100*umeter')
With the current approach, we'd generate <OnStart> assignments for the x and y values of group, but when we run Brian2's standard Synapses.connect function, it cannot actually refer to them.
The solution is, I think, to actually have LEMSDevice act like the standard runtime device except for the run. This means that it will actually assign and store values for x and y and it can create the synapses. Doing this should be straightforward:
Have LEMSDevice inherit from RuntimeDevice
Delete all the dummy functions that do nothing (e.g. LEMSDevice.add_array, LEMSDevice.get_value) -- their functionality will be inherited from RuntimeDevice
Also delete the DummyCodeObject and LEMSDevice.code_object
For the overwritten functions like variableview_set_with_expression_conditional, call the original implementation in addition to what LEMSDevice is doing currently. (Note that you cannot call variableview.set_with_expression_conditional, because this would call the overwritten function again. You have to take the quite ugly workaround of calling VariableView.original_function.set_with_expression_conditional(variableview, ...) ).
This way, everything up to the run call (including most importantly the synapse creation) will work just as in a normal run, but then the run will not be executed but instead we'll write out the XML file.
The text was updated successfully, but these errors were encountered:
As we discussed, the next big feature to implement are synaptic connections. To start, deal with explicit synapses given with
synapses.connect(i=..., j=...)
. To do this, you'll have to implementLEMSDevice.synapses_connect
which will be called instead of the originalSynapses.connect
function (it takes the same arguments asSynapses.connect
, but note that it starts like this:i.e. you have "two
self
arguments",self
corresponds to theLEMSDevice
andsynapses
is theSynapses
object.When connecting synapses works in this way, the next step is to support synaptic connections defined by expressions/patterns (probabilistic connections, one-to-one connections, etc.). As discussed with Padraig, this is not something that we can do in the generated LEMS/NeuroML code, but instead Brian will generate the connections and then you'll include the generated connections in the XML file in the same way as if the user had called
Synapses.connect(i=..., j=...)
directly. IMO, the best way to implement it would be to haveLEMSDevice.synapses_connect
first call the originalSynapses.connect
with the given arguments and then pass the generated values fori
andj
to NeuroML. In the beginning, only support a single call toconnect
for eachSynapses
object (i.e. raise aNotImplementedError
for a second call). Alternatively (actually that might be even easier and naturally supports multipleconnect calls
): do not overwriteSynapses.connect
at all, simply checkSynapses.i
andSynapses.j
for allSynapses
objects in the network and create the corresponding synapses.However, all of this will not work with the current design of
LEMSDevice
because the expressions for generating synapses refer to variables that are not actually stored anywhere. E.g. you could define spatial connectivity with something like this:With the current approach, we'd generate
<OnStart>
assignments for thex
andy
values ofgroup
, but when we run Brian2's standardSynapses.connect
function, it cannot actually refer to them.The solution is, I think, to actually have
LEMSDevice
act like the standard runtime device except for the run. This means that it will actually assign and store values forx
andy
and it can create the synapses. Doing this should be straightforward:LEMSDevice
inherit fromRuntimeDevice
LEMSDevice.add_array
,LEMSDevice.get_value
) -- their functionality will be inherited fromRuntimeDevice
DummyCodeObject
andLEMSDevice.code_object
variableview_set_with_expression_conditional
, call the original implementation in addition to whatLEMSDevice
is doing currently. (Note that you cannot callvariableview.set_with_expression_conditional
, because this would call the overwritten function again. You have to take the quite ugly workaround of callingVariableView.original_function.set_with_expression_conditional(variableview, ...)
).This way, everything up to the run call (including most importantly the synapse creation) will work just as in a normal run, but then the run will not be executed but instead we'll write out the XML file.
The text was updated successfully, but these errors were encountered: