Skip to content

Commit

Permalink
Replay with NetCons in CoreNEURON as in NEURON (#173)
Browse files Browse the repository at this point in the history
## Context
Currently Neurodamus uses different spike replay processes for NEURON
and CoreNEURON:

- For NEURON, it creates NetCons between a Vectim and the post synaptic
object

- For CoreNeuron, it writes the spikes into a .dat file and passes it to
CoreNEURON via "–pattern" CLI h

For the feature of running CoreNEURON in memory, we need to unify the
synapse replay for both simulators. This PR makes CoreNEURON to replay
as NEURON, using NetCons and VecStim. NetCons should be transferable
between Neuron and CoreNEURON.

## Scope
- In `node.py`, remove `_coreneuron_replay_append` for writing out
replay data file. Call the same replay function for CoreNEURON.
- In `connection_manager.py`, no `attach_src` for coreneuron virtual
source. `replay_mode` from ReplayMode.NONE -> ReplayMode.AS_REQUIRED for
coreneuron
- In `neuromodulation_manager.py`, similar changes

## Testing
Current tests

## Review
* [x] PR description is complete
* [x] Coding style (imports, function length, New functions, classes or
files) are good
* [x] Unit/Scientific test added
* [ ] Updated Readme, in-code, developer documentation
  • Loading branch information
WeinaJi authored Jun 26, 2024
1 parent 66ad0e5 commit 98fef41
Show file tree
Hide file tree
Showing 3 changed files with 6 additions and 34 deletions.
6 changes: 2 additions & 4 deletions neurodamus/connection_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1081,8 +1081,7 @@ def finalize(self, base_seed=0, sim_corenrn=False, *, _conn_type="synapses", **c
n_created_conns = 0

for popid, pop in self._populations.items():
attach_src = (pop.src_id == 0 or not pop.virtual_source # real populations
or pop.virtual_source and bool(sim_corenrn)) # Req'd for replay
attach_src = pop.src_id == 0 or not pop.virtual_source # real populations
conn_params["attach_src_cell"] = attach_src
logging.info(" * Connections among %s -> %s, attach src: %s",
pop.src_name or "(base)", pop.dst_name or "(base)", attach_src)
Expand Down Expand Up @@ -1234,8 +1233,7 @@ def __init__(self, circuit_conf, target_manager, cell_manager, src_cell_manager=
def finalize(self, base_seed=0, sim_corenrn=False, **kwargs):
"""Create the actual synapses and netcons. See super() docstring
"""
# CoreNeuron will handle replays automatically with its own PatternStim
kwargs.setdefault("replay_mode", ReplayMode.NONE if sim_corenrn else ReplayMode.AS_REQUIRED)
kwargs.setdefault("replay_mode", ReplayMode.AS_REQUIRED)
super().finalize(base_seed, sim_corenrn, **kwargs)

def _finalize_conns(self, tgid, conns, base_seed, sim_corenrn, **kw):
Expand Down
14 changes: 3 additions & 11 deletions neurodamus/neuromodulation_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from .connection_manager import SynapseRuleManager
from .connection import Connection, NetConType, ReplayMode
from .core.configuration import GlobalConfig, SimConfig
from .core.configuration import GlobalConfig
from .io.sonata_config import ConnectionTypes
from .io.synapse_reader import SynapseParameters, SonataReader
from .utils.logging import log_all
Expand Down Expand Up @@ -35,7 +35,7 @@ def __init__(self,
def finalize(self, cell, base_seed=0, *,
skip_disabled=False,
replay_mode=ReplayMode.AS_REQUIRED,
base_manager=None, attach_src_cell=True, **_kwargs):
base_manager=None, **_kwargs):
""" Override the finalize process from the base class.
NeuroModulatory events do not create synapses but link to existing cell synapses.
A neuromodulatory connection from projections with match to the closest cell synapse.
Expand All @@ -60,16 +60,8 @@ def finalize(self, cell, base_seed=0, *,
if syn_obj is None:
logging.warning("No cell synapse associated to the neuromodulatory event")
return 0
nc = None
# For coreneuron, create NetCon attached to the (virtual) source gid for replay
# For neuron, create NetCon with source from replay stim
if SimConfig.use_coreneuron:
nc = self._pc.gid_connect(self.sgid, syn_obj)
nc.delay = syn_params.delay
self._netcons.append(nc)
elif self._replay is not None:
if self._replay is not None:
nc = self._replay.create_on(self, sec, syn_obj, syn_params)
if nc:
nc.weight[0] = int(self.weight_factor > 0) # weight is binary 1/0, default 1
nc.weight[1] = self.neuromod_strength or syn_params.neuromod_strength
nc.weight[2] = self.neuromod_dtc or syn_params.neuromod_dtc
Expand Down
20 changes: 1 addition & 19 deletions neurodamus/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -774,25 +774,7 @@ def _enable_replay(self, source, target, stim_conf, tshift=.0, delay=.0,

logging.info("=> Population pathway %s -> %s. Source offset: %d",
src_pop_str, dst_pop_str, src_pop_offset)
if SimConfig.use_coreneuron:
self._coreneuron_replay_append(spike_manager, src_pop_offset)
else:
conn_manager.replay(spike_manager, source, target, delay)

def _coreneuron_replay_append(self, spike_manager, gid_offset=None):
"""Write replay spikes in single file for CoreNeuron"""
# To be loaded as PatternStim, requires final gids (with offset)
# Initialize file if non-existing
if not self._core_replay_file:
self._core_replay_file = ospath.join(SimConfig.output_root, 'pattern.dat')
if MPI.rank == 0:
log_verbose("Creating pattern.dat file for CoreNEURON. Gid offset: %d", gid_offset)
spike_manager.dump_ascii(self._core_replay_file, gid_offset)
else:
if MPI.rank == 0:
log_verbose("Appending to pattern.dat. Gid offset: %d", gid_offset)
with open(self._core_replay_file, "a") as f:
spike_manager.dump_ascii(f, gid_offset)
conn_manager.replay(spike_manager, source, target, delay)

# -
@mpi_no_errors
Expand Down

0 comments on commit 98fef41

Please sign in to comment.