Skip to content
This repository was archived by the owner on Mar 20, 2023. It is now read-only.

Commit f776393

Browse files
nrnhinespramodk
authored andcommitted
Bi-directional in-memory transfer between NEURON and CoreNEURON (#182)
- Direct transfer mode disable error checking for real cell with no gid. - All the fixed_record items become trajectory requests for direct mode CoreNEURON In particular, any Vector.record specified in NEURON will be recorded during a direct mode CoreNEURON run (presently limited to voltage and non artificial cell mechanism data). - Direct mode transfer allows CoreNEURON to record entire Vector trajectory. - An Graph line expression may depend on several range variables. So the number of PlayRecord items in NEURON may not be the same as the number of trajectories to record in CoreNEURON. - NEURON determines if trajectory direct transfer is per step or buffered. - NEURON trajectory requests have to be received prior to finitialize. - Special mtype for tvec trajectory - Trajectory transfer scatters to NEURON variables in per step mode. Instead of sending back array of values from CoreNEURON.
1 parent 2829bb8 commit f776393

File tree

13 files changed

+264
-17
lines changed

13 files changed

+264
-17
lines changed

coreneuron/nrniv/global_vars.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ void set_globals(const char* path, bool cli_global_seed, int cli_global_seed_val
8282
double val;
8383
int n;
8484

85-
fscanf(f, "%s\n", line);
85+
nrn_assert(fscanf(f, "%s\n", line) == 1);
8686
check_bbcore_write_version(line);
8787

8888
for (;;) {

coreneuron/nrniv/main1.cpp

Lines changed: 76 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ const char* corenrn_version() {
6464
return coreneuron::bbcore_write_version;
6565
}
6666

67+
void (*nrn2core_part2_clean_)();
68+
6769
#ifdef ISPC_INTEROP
6870
// cf. utils/ispc_globals.c
6971
extern double ispc_celsius;
@@ -358,6 +360,58 @@ void handle_forward_skip(double forwardskip, int prcellgid) {
358360
const char* nrn_version(int) {
359361
return "version id unimplemented";
360362
}
363+
364+
// bsize = 0 then per step transfer
365+
// bsize > 1 then full trajectory save into arrays.
366+
void get_nrn_trajectory_requests(int bsize) {
367+
if (nrn2core_get_trajectory_requests_) {
368+
for (int tid=0; tid < nrn_nthread; ++tid) {
369+
NrnThread& nt = nrn_threads[tid];
370+
int n_pr;
371+
int n_trajec;
372+
int* types;
373+
int* indices;
374+
void** vpr;
375+
double** varrays;
376+
double** pvars;
377+
378+
// bsize is passed by reference, the return value will determine if
379+
// per step return or entire trajectory return.
380+
(*nrn2core_get_trajectory_requests_)(tid, bsize, n_pr, vpr, n_trajec, types, indices, pvars, varrays);
381+
delete_trajectory_requests(nt);
382+
if (n_trajec) {
383+
TrajectoryRequests* tr = new TrajectoryRequests;
384+
nt.trajec_requests = tr;
385+
tr->bsize = bsize;
386+
tr->n_pr = n_pr;
387+
tr->n_trajec = n_trajec;
388+
tr->vsize = 0;
389+
tr->vpr = vpr;
390+
tr->gather = new double*[n_trajec];
391+
tr->varrays = varrays;
392+
tr->scatter = pvars;
393+
for (int i=0; i < n_trajec; ++i) {
394+
tr->gather[i] = stdindex2ptr(types[i], indices[i], nt);
395+
}
396+
delete [] types;
397+
delete [] indices;
398+
}
399+
}
400+
}
401+
}
402+
403+
static void trajectory_return() {
404+
if (nrn2core_trajectory_return_) {
405+
for (int tid=0; tid < nrn_nthread; ++tid) {
406+
NrnThread& nt = nrn_threads[tid];
407+
TrajectoryRequests* tr = nt.trajec_requests;
408+
if (tr && tr->varrays) {
409+
(*nrn2core_trajectory_return_)(tid, tr->n_pr, tr->vsize, tr->vpr, nt._t);
410+
}
411+
}
412+
}
413+
}
414+
361415
} // namespace coreneuron
362416

363417
/// The following high-level functions are marked as "extern C"
@@ -423,15 +477,6 @@ extern "C" int run_solve_core(int argc, char** argv) {
423477
// clang-format on
424478
{
425479
double v = nrnopt_get_dbl("--voltage");
426-
427-
// TODO : if some ranks are empty then restore will go in deadlock
428-
// phase (as some ranks won't have restored anything and hence return
429-
// false in checkpoint_initialize
430-
if (!checkpoint_initialize()) {
431-
nrn_finitialize(v != 1000., v);
432-
}
433-
434-
report_mem_usage("After nrn_finitialize");
435480
double dt = nrnopt_get_dbl("--dt");
436481
double delay = nrnopt_get_dbl("--mindelay");
437482
double tstop = nrnopt_get_dbl("--tstop");
@@ -442,6 +487,24 @@ extern "C" int run_solve_core(int argc, char** argv) {
442487
abort();
443488
}
444489

490+
// In direct mode there are likely trajectory record requests
491+
// to allow processing in NEURON after simulation by CoreNEURON
492+
if (corenrn_embedded) {
493+
// arg is vector size required but NEURON can instead
494+
// specify that returns will be on a per time step basis.
495+
get_nrn_trajectory_requests(int(tstop/dt) + 2);
496+
(*nrn2core_part2_clean_)();
497+
}
498+
499+
// TODO : if some ranks are empty then restore will go in deadlock
500+
// phase (as some ranks won't have restored anything and hence return
501+
// false in checkpoint_initialize
502+
if (!checkpoint_initialize()) {
503+
nrn_finitialize(v != 1000., v);
504+
}
505+
506+
report_mem_usage("After nrn_finitialize");
507+
445508
// register all reports into reportinglib
446509
double min_report_dt = INT_MAX;
447510
int report_buffer_size = nrnopt_get_int("--report-buffer-size");
@@ -473,6 +536,10 @@ extern "C" int run_solve_core(int argc, char** argv) {
473536
BBS_netpar_solve(nrnopt_get_dbl("--tstop"));
474537
Instrumentor::phase_end("simulation");
475538
Instrumentor::stop_profile();
539+
// direct mode and full trajectory gathering on CoreNEURON, send back.
540+
if (corenrn_embedded) {
541+
trajectory_return();
542+
}
476543
// Report global cell statistics
477544
report_cell_stats();
478545

coreneuron/nrniv/mk_mech.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,14 @@ void mk_mech(const char* datpath) {
118118

119119
// we are embedded in NEURON, get info as stringstream from nrnbbcore_write.cpp
120120
static void mk_mech() {
121+
static bool done = false;
122+
if (done) { return; }
121123
nrn_need_byteswap = 0;
122124
std::stringstream ss;
123125
nrn_assert(nrn2core_mkmech_info_);
124126
(*nrn2core_mkmech_info_)(ss);
125127
mk_mech(ss);
128+
done = true;
126129
}
127130

128131
static void mk_mech(std::istream& s) {

coreneuron/nrniv/nrn2core_direct.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,33 @@ extern int (*nrn2core_get_dat2_vecplay_inst_)(int tid,
8787
int& sz,
8888
double*& yvec,
8989
double*& tvec);
90+
91+
extern void (*nrn2core_part2_clean_)();
92+
93+
/* what variables to send back to NEURON on each time step */
94+
extern void (*nrn2core_get_trajectory_requests_)(int tid,
95+
int& bsize,
96+
int& n_pr,
97+
void**& vpr,
98+
int& n_trajec,
99+
int*& types,
100+
int*& indices,
101+
double**& pvars,
102+
double**& varrays);
103+
104+
/* send values to NEURON on each time step */
105+
extern void (*nrn2core_trajectory_values_)(int tid,
106+
int n_pr,
107+
void** vpr,
108+
double t);
109+
110+
/* Filled the Vector data arrays and send back the sizes at end of run */
111+
extern void (*nrn2core_trajectory_return_)(int tid,
112+
int n_pr,
113+
int vecsz,
114+
void** vpr,
115+
double t);
116+
90117
}
91118

92119
#endif /* nrn2core_direct_h */

coreneuron/nrniv/nrn_setup.cpp

Lines changed: 82 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,28 @@ int (*nrn2core_get_dat2_vecplay_inst_)(int tid,
128128
double*& yvec,
129129
double*& tvec);
130130

131+
void (*nrn2core_get_trajectory_requests_)(int tid,
132+
int& bsize,
133+
int& n_pr,
134+
void**& vpr,
135+
int& n_trajec,
136+
int*& types,
137+
int*& indices,
138+
double**& pvars,
139+
double**& varrays);
140+
141+
void (*nrn2core_trajectory_values_)(int tid,
142+
int n_pr,
143+
void** vpr,
144+
double t);
145+
146+
void (*nrn2core_trajectory_return_)(int tid,
147+
int n_pr,
148+
int vecsz,
149+
void** vpr,
150+
double t);
151+
152+
131153
// file format defined in cooperation with nrncore/src/nrniv/nrnbbcore_write.cpp
132154
// single integers are ascii one per line. arrays are binary int or double
133155
// Note that regardless of the gid contents of a group, since all gids are
@@ -312,7 +334,7 @@ void nrn_read_filesdat(int& ngrp, int*& grp, int multiple, int*& imult, const ch
312334
}
313335

314336
char version[256];
315-
fscanf(fp, "%s\n", version);
337+
nrn_assert(fscanf(fp, "%s\n", version) == 1);
316338
check_bbcore_write_version(version);
317339

318340
int iNumFiles = 0;
@@ -350,8 +372,8 @@ void nrn_read_filesdat(int& ngrp, int*& grp, int multiple, int*& imult, const ch
350372
if ((iNum + 1) % iNumFiles == 0) {
351373
// re-read file for each multiple (skipping the two header lines)
352374
rewind(fp);
353-
fscanf(fp, "%*s\n");
354-
fscanf(fp, "%*d\n");
375+
nrn_assert(fscanf(fp, "%*s\n") == 0);
376+
nrn_assert(fscanf(fp, "%*d\n") == 0);
355377
}
356378
}
357379

@@ -681,7 +703,9 @@ void nrn_setup(const char* filesdat,
681703
maxgid = 0x7fffffff / nrn_setup_multiple;
682704
nrn_read_filesdat(ngroup, gidgroups, nrn_setup_multiple, imult, filesdat);
683705

684-
MUTCONSTRUCT(1)
706+
if (!MUTCONSTRUCTED) {
707+
MUTCONSTRUCT(1)
708+
}
685709
// temporary bug work around. If any process has multiple threads, no
686710
// process can have a single thread. So, for now, if one thread, make two.
687711
// Fortunately, empty threads work fine.
@@ -795,7 +819,12 @@ void nrn_setup(const char* filesdat,
795819
delete[] file_reader;
796820

797821
model_size();
798-
delete[] gidgroups;
822+
delete [] gidgroups;
823+
delete [] imult;
824+
if (nrnthread_chkpnt) {
825+
delete [] nrnthread_chkpnt;
826+
nrnthread_chkpnt = NULL;
827+
}
799828

800829
if (nrnmpi_myid == 0) {
801830
printf(" Setup Done : %.2lf seconds \n", nrn_wtime() - time);
@@ -900,6 +929,34 @@ int nrn_i_layout(int icnt, int cnt, int isz, int sz, int layout) {
900929
return 0;
901930
}
902931

932+
// take into account alignment, layout, permutation
933+
// only voltage or mechanism data index allowed. (mtype 0 means time)
934+
double* stdindex2ptr(int mtype, int index, NrnThread& nt) {
935+
if (mtype == -5) { // voltage
936+
int v0 = nt._actual_v - nt._data;
937+
int ix = index; // relative to _actual_v
938+
nrn_assert((ix >= 0) && (ix < nt.end));
939+
if (nt._permute) {
940+
node_permute(&ix, 1, nt._permute);
941+
}
942+
return nt._data + (v0 + ix); // relative to nt._data
943+
}else if (mtype > 0 && mtype < n_memb_func) { //
944+
Memb_list* ml = nt._ml_list[mtype];
945+
nrn_assert(ml);
946+
int ix = nrn_param_layout(index, mtype, ml);
947+
if (ml->_permute) {
948+
ix = nrn_index_permute(ix, mtype, ml);
949+
}
950+
return ml->data + ix;
951+
}else if (mtype == 0) { // time
952+
return &nt._t;
953+
}else{
954+
printf("stdindex2ptr does not handle mtype=%d\n", mtype);
955+
nrn_assert(0);
956+
}
957+
return NULL;
958+
}
959+
903960
// from i to (icnt, isz)
904961
void nrn_inverse_i_layout(int i, int& icnt, int cnt, int& isz, int sz, int layout) {
905962
if (layout == 1) {
@@ -948,6 +1005,7 @@ inline void mech_layout(FileHandler& F, T* data, int cnt, int sz, int layout) {
9481005
* things up first. */
9491006

9501007
void nrn_cleanup(bool clean_ion_global_map) {
1008+
clear_event_queue(); // delete left-over TQItem
9511009
gid2in.clear();
9521010
gid2out.clear();
9531011

@@ -967,6 +1025,7 @@ void nrn_cleanup(bool clean_ion_global_map) {
9671025
for (int it = 0; it < nrn_nthread; ++it) {
9681026
NrnThread* nt = nrn_threads + it;
9691027
NrnThreadMembList* next_tml = NULL;
1028+
delete_trajectory_requests(*nt);
9701029
for (NrnThreadMembList* tml = nt->tml; tml; tml = next_tml) {
9711030
Memb_list* ml = tml->ml;
9721031

@@ -1114,9 +1173,24 @@ void nrn_cleanup(bool clean_ion_global_map) {
11141173

11151174
if (pnttype2presyn) {
11161175
free(pnttype2presyn);
1176+
pnttype2presyn = NULL;
11171177
}
11181178
}
11191179

1180+
void delete_trajectory_requests(NrnThread& nt) {
1181+
if (nt.trajec_requests) {
1182+
TrajectoryRequests* tr = nt.trajec_requests;
1183+
if (tr->n_trajec) {
1184+
delete [] tr->vpr;
1185+
if (tr->scatter) {delete [] tr->scatter;}
1186+
if (tr->varrays) {delete [] tr->varrays;}
1187+
delete [] tr->gather;
1188+
}
1189+
delete nt.trajec_requests;
1190+
nt.trajec_requests = NULL;
1191+
}
1192+
}
1193+
11201194
void read_phase2(FileHandler& F, int imult, NrnThread& nt) {
11211195
bool direct = corenrn_embedded ? true : false;
11221196
if (!direct) {
@@ -1178,7 +1252,9 @@ void read_phase2(FileHandler& F, int imult, NrnThread& nt) {
11781252
ntc.n_outputgids = n_outputgid;
11791253
ntc.nmech = nmech;
11801254
#endif
1181-
nrn_assert(n_outputgid > 0); // avoid n_outputgid unused warning
1255+
if (!direct) {
1256+
nrn_assert(n_outputgid > 0); // avoid n_outputgid unused warning
1257+
}
11821258

11831259
/// Checkpoint in coreneuron is defined for both phase 1 and phase 2 since they are written
11841260
/// together

coreneuron/nrniv/nrniv_decl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ extern void nrn_setup(const char* filesdat,
5555
bool is_mapping_needed,
5656
int byte_swap,
5757
bool run_setup_cleanup = true);
58+
extern double* stdindex2ptr(int mtype, int index, NrnThread&);
59+
extern void delete_trajectory_requests(NrnThread&);
5860
extern int nrn_setup_multiple;
5961
extern int nrn_setup_extracon;
6062
extern void nrn_cleanup(bool clean_ion_global_map = true);

coreneuron/nrniv/output_spikes.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ static MUTDEC
5757
} catch (const std::length_error& le) {
5858
std::cerr << "Lenght error" << le.what() << std::endl;
5959
}
60-
MUTCONSTRUCT(1);
60+
if (!MUTCONSTRUCTED) {
61+
MUTCONSTRUCT(1);
62+
}
6163
}
6264

6365
void spikevec_lock() {

coreneuron/nrniv/tqueue.ipp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ TQueue<C>::~TQueue() {
7878
}
7979
delete binq_;
8080

81+
if (least_) {
82+
delete least_;
83+
least_ = NULL;
84+
}
85+
8186
/// Clear the splay tree
8287
while ((q = spdeq(&sptree_->root)) != NULL) {
8388
delete q;

0 commit comments

Comments
 (0)