Skip to content

Commit

Permalink
Callbacks for reading mapping information from memory (#2555)
Browse files Browse the repository at this point in the history
* Implement necessary changes for in-memory transfer for `gid_3.dat` i.e. report related information
* no need to send ReportEvent back to nrn, skip them
* add new test from ringtests
  • Loading branch information
WeinaJi authored Mar 13, 2024
1 parent e3e8625 commit 17be061
Show file tree
Hide file tree
Showing 13 changed files with 292 additions and 55 deletions.
4 changes: 4 additions & 0 deletions src/coreneuron/io/core2nrn_data_return.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,10 @@ static bool core2nrn_tqueue_item(TQItem* q, SelfEventWeightMap& sewm, NrnThread&
// nothing to transfer
break;
}
case ReportEventType: {
// no need to transfer ReportEvent
break;
}
default: {
// In particular, InputPreSyn does not appear in tqueue as it
// immediately fans out to NetCon.
Expand Down
15 changes: 15 additions & 0 deletions src/coreneuron/io/nrn2core_direct.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include <iostream>
#include <vector>
#include <cstdint>

extern "C" {
// The callbacks into nrn/src/nrniv/nrnbbcore_write.cpp to get
Expand Down Expand Up @@ -96,6 +97,20 @@ extern int (*nrn2core_get_dat2_vecplay_inst_)(int tid,

extern void (*nrn2core_part2_clean_)();

extern void (*nrn2core_get_dat3_cell_count_)(int& cell_count);
extern void (
*nrn2core_get_dat3_cellmapping_)(int i, int& gid, int& nsec, int& nseg, int& n_seclist);
extern void (*nrn2core_get_dat3_secmapping_)(int i_c,
int i_sec,
std::string& sclname,
int& nsec,
int& nseg,
size_t& total_lfp_factors,
int& n_electrodes,
std::vector<int>& data_sec,
std::vector<int>& data_seg,
std::vector<double>& data_lfp);

/* what variables to send back to NEURON on each time step */
extern void (*nrn2core_get_trajectory_requests_)(int tid,
int& bsize,
Expand Down
13 changes: 5 additions & 8 deletions src/coreneuron/io/nrn_filehandler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,13 @@ class FileHandler {
mapinfo->name = std::string(name);

if (nseg) {
std::vector<int> sec, seg;
std::vector<double> lfp_factors;

sec.reserve(nseg);
seg.reserve(nseg);
lfp_factors.reserve(total_lfp_factors);
auto sec = read_vector<int>(nseg);
auto seg = read_vector<int>(nseg);

read_array<int>(&sec[0], nseg);
read_array<int>(&seg[0], nseg);
std::vector<double> lfp_factors;
if (total_lfp_factors > 0) {
// ASan reports container overflow on read_array with vec.reserve, resize does work
lfp_factors.resize(nseg);
read_array<double>(&lfp_factors[0], total_lfp_factors);
}

Expand Down
38 changes: 9 additions & 29 deletions src/coreneuron/io/nrn_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "coreneuron/utils/nrnoc_aux.hpp"
#include "coreneuron/io/phase1.hpp"
#include "coreneuron/io/phase2.hpp"
#include "coreneuron/io/phase3.hpp"
#include "coreneuron/io/mech_report.h"
#include "coreneuron/io/reports/nrnreport.hpp"

Expand Down Expand Up @@ -516,7 +517,7 @@ void nrn_setup(const char* filesdat,
}

if (is_mapping_needed)
coreneuron::phase_wrapper<coreneuron::phase::three>(userParams);
coreneuron::phase_wrapper<coreneuron::phase::three>(userParams, !corenrn_file_mode);

*mindelay = set_mindelay(*mindelay);

Expand Down Expand Up @@ -928,37 +929,16 @@ void read_phase2(NrnThread& nt, UserParams& userParams) {

/** read mapping information for neurons */
void read_phase3(NrnThread& nt, UserParams& userParams) {
/** restore checkpoint state (before restoring queue items */
auto& F = userParams.file_reader[nt.id];
F.restore_checkpoint();

/** mapping information for all neurons in single NrnThread */
NrnThreadMappingInfo* ntmapping = new NrnThreadMappingInfo();

int count = 0;

F.read_mapping_cell_count(&count);

/** number of cells in mapping file should equal to cells in NrnThread */
nrn_assert(count == nt.ncell);

/** for every neuron */
for (int i = 0; i < nt.ncell; i++) {
int gid, nsec, nseg, nseclist;

// read counts
F.read_mapping_count(&gid, &nsec, &nseg, &nseclist);

CellMapping* cmap = new CellMapping(gid);

// read section-segment mapping for every section list
for (int j = 0; j < nseclist; j++) {
SecMapping* smap = new SecMapping();
F.read_mapping_info(smap, ntmapping, cmap);
cmap->add_sec_map(smap);
}

ntmapping->add_cell_mapping(cmap);
Phase3 p3;
if (corenrn_embedded && !corenrn_file_mode) {
p3.read_direct(ntmapping);
} else {
auto& F = userParams.file_reader[nt.id];
F.restore_checkpoint();
p3.read_file(F, ntmapping);
}

// make number #cells match with mapping size
Expand Down
101 changes: 101 additions & 0 deletions src/coreneuron/io/phase3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
# =============================================================================
# Copyright (c) 2016 - 2024 Blue Brain Project/EPFL
#
# See top-level LICENSE file for details.
# =============================================================================
*/
#include <algorithm>

#include "coreneuron/io/phase3.hpp"
// Where nrn2core_get_dat3_secmapping_ is declared with extern "C" to avoid symbol name mangling
// caused by dual ABI for std::string
#include "coreneuron/io/nrn2core_direct.h"

void (*nrn2core_get_dat3_cell_count_)(int& cell_count);
void (*nrn2core_get_dat3_cellmapping_)(int i, int& gid, int& nsec, int& nseg, int& n_seclist);
void (*nrn2core_get_dat3_secmapping_)(int i_c,
int i_sec,
std::string& sclname,
int& nsec,
int& nseg,
size_t& total_lfp_factors,
int& n_electrodes,
std::vector<int>& data_sec,
std::vector<int>& data_seg,
std::vector<double>& data_lfp);

namespace coreneuron {
void Phase3::read_file(FileHandler& F, NrnThreadMappingInfo* ntmapping) {
int count = 0;
F.read_mapping_cell_count(&count);
/** for every neuron */
for (int i = 0; i < count; i++) {
int gid, nsec, nseg, nseclist;
// read counts
F.read_mapping_count(&gid, &nsec, &nseg, &nseclist);
CellMapping* cmap = new CellMapping(gid);
// read section-segment mapping for every section list
for (int j = 0; j < nseclist; j++) {
SecMapping* smap = new SecMapping();
F.read_mapping_info(smap, ntmapping, cmap);
cmap->add_sec_map(smap);
}
ntmapping->add_cell_mapping(cmap);
}
}

void Phase3::read_direct(NrnThreadMappingInfo* ntmapping) {
int count;
nrn2core_get_dat3_cell_count_(count);
/** for every neuron */
for (int i = 0; i < count; i++) {
int gid;
int t_sec;
int t_seg;
int nseclist;
nrn2core_get_dat3_cellmapping_(i, gid, t_sec, t_seg, nseclist);
auto cmap = new CellMapping(gid);
for (int j = 0; j < nseclist; j++) {
std::string sclname;
int n_sec;
int n_seg;
int n_electrodes;
size_t total_lfp_factors;
std::vector<int> data_sec;
std::vector<int> data_seg;
std::vector<double> data_lfp;
nrn2core_get_dat3_secmapping_(i,
j,
sclname,
n_sec,
n_seg,
total_lfp_factors,
n_electrodes,
data_sec,
data_seg,
data_lfp);
auto smap = new SecMapping();
smap->name = sclname;
for (int i_seg = 0; i_seg < n_seg; i_seg++) {
smap->add_segment(data_sec[i_seg], data_seg[i_seg]);
ntmapping->add_segment_id(data_seg[i_seg]);
int factor_offset = i_seg * n_electrodes;
if (total_lfp_factors > 0) {
// Abort if the factors contains a NaN
nrn_assert(count_if(data_lfp.begin(), data_lfp.end(), [](double d) {
return std::isnan(d);
}) == 0);
std::vector<double> segment_factors(data_lfp.begin() + factor_offset,
data_lfp.begin() + factor_offset +
n_electrodes);
cmap->add_segment_lfp_factor(data_seg[i], segment_factors);
}
}
cmap->add_sec_map(smap);
}
ntmapping->add_cell_mapping(cmap);
}
}

} // namespace coreneuron
21 changes: 21 additions & 0 deletions src/coreneuron/io/phase3.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
# =============================================================================
# Copyright (c) 2016 - 2024 Blue Brain Project/EPFL
#
# See top-level LICENSE file for details.
# =============================================================================
*/

#pragma once

#include "coreneuron/io/nrn_filehandler.hpp"

namespace coreneuron {
struct NrnThreadMappingInfo;

class Phase3 {
public:
void read_file(FileHandler& F, NrnThreadMappingInfo* ntmapping);
void read_direct(NrnThreadMappingInfo* ntmapping);
};
} // namespace coreneuron
3 changes: 3 additions & 0 deletions src/coreneuron/io/reports/report_event.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ class ReportEvent: public DiscreteEvent {
bool require_checkpoint() override;
void summation_alu(NrnThread* nt);
void lfp_calc(NrnThread* nt);
int type() const override {
return ReportEventType;
}

private:
double dt;
Expand Down
1 change: 1 addition & 0 deletions src/coreneuron/network/netcon.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class NetCvode;
#define PreSynType 4
#define NetParEventType 7
#define InputPreSynType 20
#define ReportEventType 8

struct DiscreteEvent {
DiscreteEvent() = default;
Expand Down
36 changes: 36 additions & 0 deletions src/nrniv/nrncore_write/callbacks/nrncore_callbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ extern TQueue* net_cvode_instance_event_queue(NrnThread*);
#include "vrecitem.h" // for nrnbbcore_vecplay_write

#include "nrnwrap_dlfcn.h"
#include "nrnsection_mapping.h"

extern bbcore_write_t* nrn_bbcore_write_;
extern bbcore_write_t* nrn_bbcore_read_;
Expand All @@ -26,6 +27,7 @@ extern bool corenrn_direct;
extern int* bbcore_dparam_size;
extern double nrn_ion_charge(Symbol*);
extern CellGroup* cellgroups_;
extern NrnMappingInfo mapinfo;
extern NetCvode* net_cvode_instance;
extern char* pnt_map;
extern void* nrn_interthread_enqueue(NrnThread*);
Expand Down Expand Up @@ -219,6 +221,40 @@ int nrnthread_dat1(int tid,
return 1;
}

void nrnthread_dat3_cell_count(int& cell_count) {
cell_count = mapinfo.size();
}

void nrnthread_dat3_cellmapping(int i, int& gid, int& nsec, int& nseg, int& n_seclist) {
CellMapping* c = mapinfo.mapping[i];
gid = c->gid;
nsec = c->num_sections();
nseg = c->num_segments();
n_seclist = c->size();
}

void nrnthread_dat3_secmapping(int i_c,
int i_sec,
std::string& sclname,
int& nsec,
int& nseg,
size_t& total_lfp_factors,
int& n_electrodes,
std::vector<int>& data_sec,
std::vector<int>& data_seg,
std::vector<double>& data_lfp) {
CellMapping* c = mapinfo.mapping[i_c];
SecMapping* s = c->secmapping[i_sec];
sclname = s->name;
nsec = s->nsec;
nseg = s->size();
total_lfp_factors = s->seglfp_factors.size();
n_electrodes = s->num_electrodes;
data_sec = s->sections;
data_seg = s->segments;
data_lfp = s->seglfp_factors;
}

// sizes and total data count
int nrnthread_dat2_1(int tid,
int& ncell,
Expand Down
15 changes: 15 additions & 0 deletions src/nrniv/nrncore_write/callbacks/nrncore_callbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,18 @@ int nrnthread_dat2_vecplay_inst(int tid,
int& last_index,
int& discon_index,
int& ubound_index);
void nrnthread_dat3_cell_count(int& cell_count);
void nrnthread_dat3_cellmapping(int i, int& gid, int& nsec, int& nseg, int& n_seclist);
void nrnthread_dat3_secmapping(int i_c,
int i_sec,
std::string& sclname,
int& nsec,
int& nseg,
size_t& total_lfp_factors,
int& n_electrodes,
std::vector<int>& data_sec,
std::vector<int>& data_seg,
std::vector<double>& data_lfp);

int* datum2int(int type,
Memb_list* ml,
Expand Down Expand Up @@ -215,6 +227,9 @@ static core2nrn_callback_t cnbs[] = {
{"nrn2core_get_dat2_vecplay_", (CNB) nrnthread_dat2_vecplay},
{"nrn2core_get_dat2_vecplay_inst_", (CNB) nrnthread_dat2_vecplay_inst},
{"nrn2core_part2_clean_", (CNB) part2_clean},
{"nrn2core_get_dat3_cell_count_", (CNB) nrnthread_dat3_cell_count},
{"nrn2core_get_dat3_cellmapping_", (CNB) nrnthread_dat3_cellmapping},
{"nrn2core_get_dat3_secmapping_", (CNB) nrnthread_dat3_secmapping},

{"nrn2core_get_trajectory_requests_", (CNB) nrnthread_get_trajectory_requests},
{"nrn2core_trajectory_values_", (CNB) nrnthread_trajectory_values},
Expand Down
Loading

0 comments on commit 17be061

Please sign in to comment.