From 975fb7c635adb8e1754a18f507dc0cb1d8b6971b Mon Sep 17 00:00:00 2001 From: Jorge Blanco Alonso <41900536+jorblancoa@users.noreply.github.com> Date: Tue, 13 Feb 2024 11:06:20 +0100 Subject: [PATCH] [BBPBGLIB-1127] Remove SpikeWriter.mod and out.dat (#123) ## Context After the deprecation of BlueConfig files, out.dat is not generated anymore. Remove the SpikeWriter mod file and the code that was handling the old out.dat spike file. ## Review * [x] PR description is complete * [x] Coding style (imports, function length, New functions, classes or files) are good * [ ] Unit/Scientific test added * [ ] Updated Readme, in-code, developer documentation --- core/mod/SpikeWriter.mod | 142 -------------------------------- core/mod/coreneuron_modlist.txt | 1 - examples/test_neurodamus.py | 3 +- neurodamus/core/_neurodamus.py | 2 +- neurodamus/node.py | 35 -------- neurodamus/replay.py | 2 +- 6 files changed, 3 insertions(+), 182 deletions(-) delete mode 100644 core/mod/SpikeWriter.mod diff --git a/core/mod/SpikeWriter.mod b/core/mod/SpikeWriter.mod deleted file mode 100644 index 694d3e5b..00000000 --- a/core/mod/SpikeWriter.mod +++ /dev/null @@ -1,142 +0,0 @@ -COMMENT -/** - * @file SpikeWriter.mod - * @brief Interface to write spikes in parallel using MPI-IO - */ -ENDCOMMENT - -NEURON { - ARTIFICIAL_CELL SpikeWriter -} - -VERBATIM -#ifndef CORENEURON_BUILD -#include - -#ifndef DISABLE_MPI -#include -#endif - -#ifndef NRN_VERSION_GTEQ_8_2_0 -extern double* vector_vec(); -extern int vector_capacity(); -extern void* vector_arg(); -#endif - -extern int nrnmpi_myid; -#endif // CORENEURON_BUILD -ENDVERBATIM - -: write_spikes to file in parallel -PROCEDURE write() { - - VERBATIM -#ifndef CORENEURON_BUILD - double *time = NULL, *gid = NULL; - int num_spikes = 0; - char *filePath = NULL; - - // first vector is time of spikes - if (ifarg(1)) { - IvocVect *v = vector_arg(1); - time = vector_vec(v); - num_spikes = vector_capacity(v); - } - - // second vector is associated gids - if (ifarg(2)) { - IvocVect *v = vector_arg(2); - gid = vector_vec(v); - } - - // third argument is file path - if(ifarg(3)) { - filePath = hoc_gargstr(3); - } else { -#ifndef DISABLE_MPI - if(nrnmpi_myid == 0) { - fprintf(stderr, " Error : No spike file path provided, can't write spikes! \n"); - MPI_Abort(MPI_COMM_WORLD, 1); - } -#else - fprintf(stderr, " Error : No spike file path provided, can't write spikes! \n"); - exit(-1); -#endif - } - - // rank 0 write extra string at the begining as "/scatter" - unsigned num_entries = nrnmpi_myid == 0 ? (num_spikes + 1) : num_spikes; - - // each spike record in the file is max 48 chars - const int spike_record_length = 48; - - // amount of data for recording spikes + zero termination - unsigned num_bytes = (sizeof(char) * num_entries * spike_record_length) + 1; - - char *spike_data = (char *) malloc(num_bytes); - - if(spike_data == NULL) { - fprintf(stderr, "Error : Memory allocation failed for spike buffer I/O!\n"); -#ifndef DISABLE_MPI - MPI_Abort(MPI_COMM_WORLD, 1); -#else - exit(-1); -#endif - } - - strcpy(spike_data, ""); - - if(nrnmpi_myid == 0) { - strcat(spike_data, "/scatter\n"); - } - - // populate buffer with all entries - int i; - for(i = 0; i < num_spikes; i++) { - char str[spike_record_length]; - int nstr = snprintf(str, spike_record_length, "%.3f\t%d\n", time[i], (int)gid[i]); - if (nstr >= spike_record_length) { - fprintf(stderr, "Error : Record written is larger than spike record buffer\n"); - free(spike_data); -#ifndef DISABLE_MPI - MPI_Abort(MPI_COMM_WORLD, 1); -#else - exit(-1); -#endif - } - strcat(spike_data, str); - } - - // calculate offset into global file. note that we don't write - // num_bytes but only "populated" characters - unsigned long num_chars = strlen(spike_data); - -#ifndef DISABLE_MPI - unsigned long offset = 0; - - MPI_Exscan(&num_chars, &offset, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - - if (nrnmpi_myid == 0) { - offset = 0; - } - - // write to file using parallel mpi i/o Remove it first in case it exists. - // Must delete because MPI_File_open does not have a Truncate mode - MPI_File fh; - MPI_Status status; - MPI_File_delete(filePath, MPI_INFO_NULL); - MPI_File_open(MPI_COMM_WORLD, filePath, MPI_MODE_CREATE | MPI_MODE_WRONLY, MPI_INFO_NULL, &fh); - MPI_File_write_at_all(fh, offset, spike_data, num_chars, MPI_BYTE, &status); - - MPI_File_close(&fh); -#else - FILE *spike_file = fopen(filePath, "w"); - fprintf(spike_file, spike_data); - fclose(spike_file); -#endif - - free(spike_data); -#endif // CORENEURON_BUILD - ENDVERBATIM -} - diff --git a/core/mod/coreneuron_modlist.txt b/core/mod/coreneuron_modlist.txt index 2835660c..e55bb284 100644 --- a/core/mod/coreneuron_modlist.txt +++ b/core/mod/coreneuron_modlist.txt @@ -5,5 +5,4 @@ lookupTableV2.mod netstim_inhpoisson.mod SonataReportHelper.mod SonataReports.mod -SpikeWriter.mod VecStim.mod diff --git a/examples/test_neurodamus.py b/examples/test_neurodamus.py index bfdfec07..5201fb44 100644 --- a/examples/test_neurodamus.py +++ b/examples/test_neurodamus.py @@ -57,8 +57,7 @@ def test_node_run(trace=False): logging.info("Run") node.run_all() - logging.info("Simulation finished. Gather spikes then clean up.") - node.spike2file("out.dat") + logging.info("Simulation finished.") node.cleanup() diff --git a/neurodamus/core/_neurodamus.py b/neurodamus/core/_neurodamus.py index 15946273..0679a824 100644 --- a/neurodamus/core/_neurodamus.py +++ b/neurodamus/core/_neurodamus.py @@ -106,7 +106,7 @@ def check_load_lib(mech, env_lib_path): # which might not bring the model (support for split neurodamus) in which case # we should load only the model libs pointed by BGLIBPY_MOD_LIBRARY_PATH. - if not check_load_lib("SpikeWriter", "NRNMECH_LIB_PATH"): + if not check_load_lib("SonataReport", "NRNMECH_LIB_PATH"): logging.error("Could not load neurodamus core mechs from NRNMECH_LIB_PATH") sys.exit(1) if not check_load_lib("ProbAMPANMDA_EMS", "BGLIBPY_MOD_LIBRARY_PATH"): diff --git a/neurodamus/node.py b/neurodamus/node.py index bce37642..b57485e2 100644 --- a/neurodamus/node.py +++ b/neurodamus/node.py @@ -12,7 +12,6 @@ from os import path as ospath from collections import namedtuple, defaultdict from contextlib import contextmanager -from shutil import copyfileobj, move from .core import MPI, mpi_no_errors, return_neuron_timings, run_only_rank0 from .core import NeurodamusCore as Nd @@ -1335,15 +1334,11 @@ def run_all(self): timings = None if SimConfig.use_neuron: timings = self._run_neuron() - if not SimConfig.is_sonata_config: - self.spike2file("out.dat") self.sonata_spikes() if SimConfig.use_coreneuron: print_mem_usage() self.clear_model(avoid_clearing_queues=False) self._run_coreneuron() - if not SimConfig.is_sonata_config: - self.adapt_spikes("out.dat") return timings # - @@ -1487,36 +1482,6 @@ def clear_model(self, avoid_creating_objs=False, avoid_clearing_queues=True): # output # ------------------------------------------------------------------------- - @run_only_rank0 - def adapt_spikes(self, outfile): - """Prepend /scatter to spikes file after coreneuron sim finishes. - """ - output_root = SimConfig.output_root - outfile = ospath.join(output_root, outfile) - tmpfile = ospath.join(output_root, 'tmp.out') - with open(outfile, 'r') as f_src: - with open(tmpfile, 'w') as f_dest: - f_dest.write("/scatter\n") - copyfileobj(f_src, f_dest) - move(tmpfile, outfile) - - @mpi_no_errors - def spike2file(self, outfile): - """ Write the spike events that occured on each node into a single output file. - Nodes will write in order, one after the other. - """ - logging.info("Writing spikes to %s", outfile) - output_root = SimConfig.output_root - outfile = ospath.join(output_root, outfile) - spikevec = Nd.Vector() - idvec = Nd.Vector() - # merge spike_vecs and id_vecs for SpikeWriter - for spikes, ids in self._spike_vecs: - spikevec.append(spikes) - idvec.append(ids) - spikewriter = Nd.SpikeWriter() - spikewriter.write(spikevec, idvec, outfile) - def sonata_spikes(self): """ Write the spike events that occured on each node into a single output SONATA file. """ diff --git a/neurodamus/replay.py b/neurodamus/replay.py index 53aa955e..60a0b157 100644 --- a/neurodamus/replay.py +++ b/neurodamus/replay.py @@ -14,7 +14,7 @@ class SpikeManager: """ Holds and manages gid spike time information, specially for Replay. A SynapseReplay stim can be used for a single gid that has all the synapses instantiated. - Given an out.dat file from a previous run, this object uses a NetStim object to retrigger + Given a spikes file from a previous run, this object uses a NetStim object to retrigger the synapses at the appropriate time as though the presynaptic cells were present and active. Internally the spikes are stored in a :py:class:`neurodamus.utils.multimap.GroupedMultiMap`