diff --git a/coreneuron/CMakeLists.txt b/coreneuron/CMakeLists.txt index 810bc57f8..f65e7e7da 100644 --- a/coreneuron/CMakeLists.txt +++ b/coreneuron/CMakeLists.txt @@ -107,6 +107,7 @@ if(CORENRN_ENABLE_GPU) ${CMAKE_CURRENT_SOURCE_DIR}/utils/randoms/nrnran123.cpp ${CMAKE_CURRENT_SOURCE_DIR}/io/nrn_setup.cpp ${CMAKE_CURRENT_SOURCE_DIR}/io/setup_fornetcon.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/io/corenrn_data_return.cpp ${CMAKE_CURRENT_SOURCE_DIR}/io/global_vars.cpp) set_source_files_properties(${DIMPLIC_CODE_FILE} ${NMODL_INBUILT_MOD_OUTPUTS} PROPERTIES diff --git a/coreneuron/apps/main1.cpp b/coreneuron/apps/main1.cpp index 9075af336..9037b036c 100644 --- a/coreneuron/apps/main1.cpp +++ b/coreneuron/apps/main1.cpp @@ -62,6 +62,7 @@ THE POSSIBILITY OF SUCH DAMAGE. #include "coreneuron/network/multisend.hpp" #include "coreneuron/io/file_utils.hpp" #include "coreneuron/io/nrn2core_direct.h" +#include "coreneuron/io/core2nrn_data_return.hpp" extern "C" { const char* corenrn_version() { @@ -609,6 +610,8 @@ extern "C" int run_solve_core(int argc, char** argv) { (*nrn2core_all_weights_return_)(weights); } + core2nrn_data_return(); + { Instrumentor::phase p("checkpoint"); write_checkpoint(nrn_threads, nrn_nthread, corenrn_param.checkpointpath.c_str()); diff --git a/coreneuron/io/core2nrn_data_return.cpp b/coreneuron/io/core2nrn_data_return.cpp new file mode 100644 index 000000000..a380cf6cc --- /dev/null +++ b/coreneuron/io/core2nrn_data_return.cpp @@ -0,0 +1,174 @@ +/* +Copyright (c) 2020, Blue Brain Project +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "coreneuron/coreneuron.hpp" +#include "coreneuron/io/nrn2core_direct.h" +#include "coreneuron/sim/multicore.hpp" +#include "coreneuron/nrniv/nrniv_decl.h" +#include "coreneuron/io/core2nrn_data_return.hpp" + +/** @brief, Information from NEURON to help with copying data to NEURON. + * Info for copying voltage, i_membrane_, and mechanism data. + * See implementaton in + * nrn/src/nrniv/nrnbbcore_write.cpp:nrnthreads_type_return. + * Return is size of either the returned data pointer or the number + * of pointers in mdata. tid is the thread index. + */ +size_t (*nrn2core_type_return_)(int type, int tid, + double*& data, double**& mdata); + +namespace coreneuron { + +/** @brief permuted array copied to unpermuted array + * If permute is NULL then just a copy + */ +static void inverse_permute_copy(size_t n, double* permuted_src, double* dest, + int* permute) +{ + if (permute) { + for (size_t i = 0; i < n; ++i) { + dest[i] = permuted_src[permute[i]]; + } + }else{ + std::copy(permuted_src, permuted_src + n, dest); + } +} + +/** @brief SoA permuted mechanism data copied to unpermuted AoS data. + * dest is an array of n pointers to the beginning of each sz length array. + * src is a contiguous array of sz segments of size stride. The stride + * may be slightly greater than n for purposes of alignment. + * Each of the sz segments of src are permuted. + */ +static void soa2aos_inverse_permute_copy(size_t n, int sz, int stride, + double* src, double** dest, int* permute) +{ + // src is soa and permuted. dest is n pointers to sz doubles (aos). + for (size_t instance = 0; instance < n; ++instance) { + double* d = dest[instance]; + double* s = src + permute[instance]; + for (int i = 0; i < sz; ++i) { + d[i] = s[i*stride]; + } + } +} + +/** @brief SoA unpermuted mechanism data copied to unpermuted AoS data. + * dest is an array of n pointers to the beginning of each sz length array. + * src is a contiguous array of sz segments of size stride. The stride + * may be slightly greater than n for purposes of alignment. + * Each of the sz segments of src have the same order as the n pointers + * of dest. + */ +static void soa2aos_unpermuted_copy(size_t n, int sz, int stride, + double* src, double** dest) +{ + // src is soa and permuted. dest is n pointers to sz doubles (aos). + for (size_t instance = 0; instance < n; ++instance) { + double* d = dest[instance]; + double* s = src + instance; + for (int i = 0; i < sz; ++i) { + d[i] = s[i*stride]; + } + } +} + +/** @brief AoS mechanism data copied to AoS data. + * dest is an array of n pointers to the beginning of each sz length array. + * src is a contiguous array of n segments of size sz. + */ +static void aos2aos_copy(size_t n, int sz, double* src, double** dest) { + for (size_t instance = 0; instance < n; ++instance) { + double* d = dest[instance]; + double* s = src + (instance*sz); + std::copy(s, s + sz, d); + } +} + +/** @brief copy data back to NEURON. + * Copies t, voltage, i_membrane_ if it used, and mechanism param data. + */ +void core2nrn_data_return() { + if (!nrn2core_type_return_) { + return; + } + for (int tid = 0; tid < nrn_nthread; ++tid) { + size_t n = 0; + double* data = nullptr; + double** mdata = nullptr; + NrnThread& nt = nrn_threads[tid]; + + n = (*nrn2core_type_return_)(0, tid, data, mdata); // 0 means time + if (n) { // not the empty thread + data[0] = nt._t; + } + + if (nt.end) { // transfer voltage and possibly i_membrane_ + n = (*nrn2core_type_return_)(voltage, tid, data, mdata); + assert(n == size_t(nt.end) && data); + inverse_permute_copy(n, nt._actual_v, data, nt._permute); + + if (nt.nrn_fast_imem) { + n = (*nrn2core_type_return_)(i_membrane_, tid, data, mdata); + assert(n == size_t(nt.end) && data); + inverse_permute_copy(n, nt.nrn_fast_imem->nrn_sav_rhs, data, nt._permute); + } + } + + for (NrnThreadMembList* tml = nt.tml; tml; tml = tml->next) { + int mtype = tml->index; + Memb_list* ml = tml->ml; + n = (*nrn2core_type_return_)(mtype, tid, data, mdata); + assert(n == size_t(ml->nodecount) && mdata); + if (n == 0) { + continue; + } + // NEURON is AoS, CoreNEURON may be SoA and may be permuted. + // On the NEURON side, the data is actually contiguous because of + // cache_efficient, but that may not be the case for ARTIFICIAL_CELL. + // For initial implementation simplicity, use the mdata info which gives + // a double* for each param_size mech instance. + int* permute = ml->_permute; + double* cndat = ml->data; + int layout = corenrn.get_mech_data_layout()[mtype]; + int sz = corenrn.get_prop_param_size()[mtype]; + if (layout == 0) { /* SoA */ + int stride = ml->_nodecount_padded; + if (permute) { + soa2aos_inverse_permute_copy(n, sz, stride, cndat, mdata, permute); + } else { + soa2aos_unpermuted_copy(n, sz, stride, cndat, mdata); + } + } else { /* AoS */ + aos2aos_copy(n, sz, cndat, mdata); + } + } + } +} + +} // namespace coreneuron diff --git a/coreneuron/io/core2nrn_data_return.hpp b/coreneuron/io/core2nrn_data_return.hpp new file mode 100644 index 000000000..8f87d23f8 --- /dev/null +++ b/coreneuron/io/core2nrn_data_return.hpp @@ -0,0 +1,40 @@ +/* +Copyright (c) 2016, Blue Brain Project +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _H_CORENRNDATARETURN_ +#define _H_CORENRNDATARETURN_ + +namespace coreneuron { + +/** @brief Copies back to NEURON the voltage, i_membrane_, and mechanism data. + */ +extern void core2nrn_data_return(); + +} // namespace coreneuron +#endif // _H_CORENRNDATARETURN_ + diff --git a/coreneuron/io/nrn2core_direct.h b/coreneuron/io/nrn2core_direct.h index 0df66608f..3c4990a05 100644 --- a/coreneuron/io/nrn2core_direct.h +++ b/coreneuron/io/nrn2core_direct.h @@ -113,6 +113,9 @@ extern int (*nrn2core_all_spike_vectors_return_)(std::vector& spikevec, /* send all weights to NEURON */ extern void (*nrn2core_all_weights_return_)(std::vector& weights); +/* get data array pointer from NEURON to copy into. */ +extern size_t (*nrn2core_type_return_)(int type, int tid, double*& data, + double**& mdata); } // extern "C" #endif /* nrn2core_direct_h */ diff --git a/coreneuron/mechanism/mech/enginemech.cpp b/coreneuron/mechanism/mech/enginemech.cpp index 346f69cd7..b500116e8 100644 --- a/coreneuron/mechanism/mech/enginemech.cpp +++ b/coreneuron/mechanism/mech/enginemech.cpp @@ -95,8 +95,11 @@ int corenrn_embedded_run(int nthread, mk_mech_init(argc, argv); // initialize extra arguments built into special-core - coreneuron::modl_reg(); - + static bool modl_reg_called = false; + if (!modl_reg_called) { + coreneuron::modl_reg(); + modl_reg_called = true; + } // run simulation run_solve_core(argc, argv);