1 #include <../../nrnconf.h>
25 #include <unordered_map>
27 namespace fs = std::filesystem;
33 "Duke, Yale, and the BlueBrain Project -- Copyright 1984-2022\n\
34 See http://neuron.yale.edu/neuron/credits\n";
36 #if defined(WIN32) || defined(NRNMECH_DLL_STYLE)
42 #undef DLL_DEFAULT_FNAME
43 #define DLL_DEFAULT_FNAME "nrnmech.dll"
46 #if defined(NRNMECH_DLL_STYLE)
49 #ifndef DLL_DEFAULT_FNAME
50 #define DLL_DEFAULT_FNAME "libnrnmech.dylib"
54 void nrn_possible_mismatched_arch(
const char* libname) {
55 if (neuron::config::system_processor ==
"arm64") {
58 const char* we_are{
"arm64"};
60 const char* we_are{
"x86_64"};
64 auto const cmd_size = strlen(libname) + 100;
65 auto* cmd =
new char[cmd_size];
66 std::snprintf(cmd, cmd_size,
"lipo -archs %s 2> /dev/null", libname);
67 char libname_arch[20]{0};
68 FILE*
p = popen(cmd,
"r");
73 fgets(libname_arch, 18,
p);
74 if (strlen(libname_arch) == 0) {
79 if (strstr(libname_arch, we_are) ==
NULL) {
80 fprintf(stderr,
"libnrniv.dylib running as %s\n", we_are);
81 fprintf(stderr,
"but %s can only run as %s\n", libname, libname_arch);
88 #ifndef DLL_DEFAULT_FNAME
89 #define DLL_DEFAULT_FNAME "./libnrnmech.so"
98 if (hoc_lookup(name) != (Symbol*) 0) { \
99 IGNORE(fprintf(stderr, CHKmes, name)); \
103 static char CHKmes[] =
"The user defined name, %s, already exists\n";
122 {
"diam", {1e-9, 1e9}},
124 {
"rallbranch", {1., 1e9}},
126 {
"celsius", {-273., 1e6}},
127 {
"dt", {1e-9, 1e15}},
128 {
nullptr, {0., 0.}}};
233 auto abspath = fs::absolute(relpath);
237 nrn_possible_mismatched_arch(abspath.c_str());
240 }
catch (
const std::filesystem::filesystem_error& e) {
245 fmt::format(
"std::filesystem::absolute failed ({}) and dlopen failed with '{}'\n",
250 nrn_possible_mismatched_arch(relpath);
261 fprintf(stderr,
"loading membrane mechanisms from %s\n", cp1);
273 fprintf(stderr,
"dlsym modl_reg failed\n%s\n",
dlerror());
279 fprintf(stderr,
"dlopen failed - \n%s\n",
dlerror());
362 CHECK(
"i_membrane_");
388 #if defined(WIN32) || defined(NRNMECH_DLL_STYLE)
391 FILE* ff = fopen(DLL_DEFAULT_FNAME,
"r");
407 strncat(
buf,
"\\", 100);
415 for (cp1 = tmp.data(); *cp1; cp1 = cp2) {
416 for (cp2 = cp1; *cp2; ++cp2) {
431 s->type = OBJECTFUNC;
465 int nrnpointerindex);
477 static int mechtype = 2;
491 mech_symbol->
subtype = mechtype;
494 if (nrnpointerindex == -1) {
500 mech_symbol->
s_varn = nvars;
515 int nrnpointerindex) {
529 for (
j = 0,
k = 0, modltype =
nrnocCONST; modltype <= modltypemax; modltype++,
j++) {
530 for (; var_buffers[
j];
j++,
k++) {
532 std::string varname(var_buffers[
j]);
535 auto subscript = varname.find(
'[');
536 if (subscript != varname.npos) {
538 if (varname[subscript + 1] ==
'N') {
543 index = std::stoi(varname.substr(subscript + 1));
546 varname.erase(subscript);
548 if ((var_symbol =
hoc_lookup(varname.c_str()))) {
552 var_symbol->
subtype = modltype;
553 var_symbol->
u.
rng.type = mechtype;
556 var_symbol->
u.
rng.index = nrnpointerindex;
558 var_symbol->
u.
rng.index = pindx;
572 nrnpointerindex +=
index;
578 mech_symbol->
u.
ppsym[
k] = var_symbol;
588 for (
j = 0, nvars = 0, modltype =
nrnocCONST; modltype <= modltypemax; modltype++) {
672 memb_func[mechtype].set_initialize(initialize);
673 memb_func[mechtype].destructor =
nullptr;
674 memb_func[mechtype].vectorized = vectorized ? 1 : 0;
675 memb_func[mechtype].thread_size_ = vectorized ? (vectorized - 1) : 0;
676 memb_func[mechtype].thread_mem_init_ =
nullptr;
677 memb_func[mechtype].thread_cleanup_ =
nullptr;
678 memb_func[mechtype].thread_table_check_ =
nullptr;
682 memb_func[mechtype].dparam_semantics =
nullptr;
687 memb_func[mechtype].ode_matsol =
nullptr;
688 memb_func[mechtype].ode_synonym =
nullptr;
701 if (strcmp(m[0],
"0") == 0) {
702 }
else if (m[0][0] >
'9') {
704 "Mechanism %s needs to be re-translated.\n\
705 It's pre version 6.0 \"c\" code is incompatible with this neuron version.\n",
714 "Mechanism %s needs to be re-translated.\n\
715 It's version %s \"c\" code is incompatible with this neuron version.\n",
737 (*nrnpy_reg_mech_p_)(mechtype);
753 printf(
"%s reordered from %d to %d\n",
memb_func[mechtype].sym->name, mechtype, lastion);
769 static std::unordered_map<std::string, int> name_to_negint = {{
"area", -1},
775 {
"bbcorepointer", -7},
781 int dparam_semantics_to_int(std::string_view
name) {
782 if (
auto got = name_to_negint.find(std::string{name}); got != name_to_negint.end()) {
785 bool const i{
name[0] ==
'#'};
787 if (
s &&
s->type == MECHANISM) {
790 throw std::runtime_error(
"unknown dparam semantics: " + std::string{
name});
794 std::vector<int> indices_of_type(
795 const char* semantic_type,
796 std::vector<std::pair<const char*, const char*>>
const& dparam_info) {
797 std::vector<int> indices{};
798 int inttype = dparam_semantics_to_int(std::string{semantic_type});
799 for (
auto i = 0;
i < dparam_info.size(); ++
i) {
800 if (dparam_semantics_to_int(dparam_info[
i].second) == inttype) {
801 indices.push_back(
i);
807 static std::unordered_map<int, std::vector<int>> mech_random_indices{};
809 void update_mech_ppsym_for_modlrandom(
811 std::vector<std::pair<const char*, const char*>>
const& dparam_info) {
812 std::vector<int> indices = indices_of_type(
"random", dparam_info);
813 mech_random_indices[mechtype] = indices;
814 if (indices.empty()) {
818 int is_point =
memb_func[mechtype].is_point;
821 mechsym->
s_varn += int(indices.size());
825 for (
auto i: indices) {
826 auto&
p = dparam_info[
i];
831 std::string
s{
p.first};
837 ransym->u.rng.type = mechtype;
839 ransym->u.rng.index =
i;
840 mechsym->
u.
ppsym[
k++] = ransym;
852 std::vector<std::pair<std::string, int>>
const& param_info,
853 std::vector<std::pair<std::string, std::string>>
const& dparam_info) {
854 std::vector<std::pair<const char*, int>> params{};
855 std::vector<std::pair<const char*, const char*>> dparams{};
857 for (
auto&& [str,
i]: param_info) {
858 params.emplace_back(str.c_str(),
i);
860 for (
auto&& [str1, str2]: dparam_info) {
861 dparams.emplace_back(str1.c_str(), str2.c_str());
872 int float_variables = 0;
873 for (
const auto& [
i,
n]: param_info) {
874 float_variables +=
n;
877 return float_variables;
881 std::vector<std::pair<const char*, int>>
const& param_info,
882 std::vector<std::pair<const char*, const char*>>
const& dparam_info) {
885 if (dparam_info.empty()) {
886 memb_func[mechtype].dparam_semantics =
nullptr;
888 memb_func[mechtype].dparam_semantics.reset(
new int[dparam_info.size()]);
889 for (
auto i = 0;
i < dparam_info.size(); ++
i) {
891 memb_func[mechtype].dparam_semantics[
i] = dparam_semantics_to_int(
892 dparam_info[
i].second);
898 std::vector<container::Mechanism::Variable> param_info_new{};
901 std::back_inserter(param_info_new),
903 return {old.first, old.second};
915 memb_list[mechtype].set_storage_pointer(&mech_data);
916 update_mech_ppsym_for_modlrandom(mechtype, dparam_info);
959 for (
int i = 0; f[
i].
name; ++
i) {
985 return dparam_semantics_to_int(
name);
992 return mech_random_indices[
type];
1038 int nrnpointerindex,
1066 v = (
double*)
emalloc((
unsigned)(nrows*
sizeof(double)));
1097 if (mechtype &&
memb_func[mechtype].is_point) {
1114 if (mechtype &&
memb_func[mechtype].is_point) {
1145 printf(
"before-after processing type %d for %s not implemented\n",
1153 bam->
next =
nullptr;
1166 if (
s &&
s[
i]->extra) {
1168 x =
s[
i]->extra->tolerance;
1179 for (
i = 0; tol[
i].
name; ++
i) {
1192 auto*
const psym =
new Symbol* [
n] {};
1198 std::vector<neuron::container::data_handle<double>> pv(2 *
n);
1199 memb_func[mechtype].ode_map(
p, 0, pv.data(), pv.data() +
n,
nullptr, mechtype);
1201 for (
int i = 0;
i <
n; ++
i) {
1206 auto const num_params =
p->param_num_vars();
1207 for (
auto i_param = 0; i_param < num_params; ++i_param) {
1208 auto const array_dim =
p->param_array_dimension(i_param);
1209 for (
auto j = 0;
j < array_dim; ++
j, ++legacy_index) {
1210 if (h ==
p->param_handle(i_param,
j)) {
1211 return std::make_pair(
p, legacy_index);
1216 std::ostringstream oss;
1217 oss <<
"could not find " << h <<
" starting from " << *
p;
1218 throw std::runtime_error(oss.str());
1222 for (
int j = 0;
j < msym->s_varn; ++
j) {
1230 for (
int k = 1;
k < na; ++
k) {
1246 }
else if (
cons == 0) {
1268 hoc_warning(
"nrnunit_use_legacy() is deprecated as only modern units are supported.",
1269 "If you want to still use legacy unit you can use a version of nrn < 9.");
1271 int arg = (int)
chkarg(1, 0, 1);
1274 "'nrnunit_use_legacy(1)' have been called but legacy units are no more supported.",
void morph_alloc(Prop *p)
Symbol * hoc_table_lookup(const char *, Symlist *)
void hoc_symbol_tolerance(Symbol *, double)
void nrn_mk_prop_pools(int n)
DLFCN_EXPORT void * dlopen(const char *file, int mode)
DLFCN_EXPORT char * dlerror(void)
DLFCN_EXPORT int dlclose(void *handle)
DLFCN_NOINLINE DLFCN_EXPORT void * dlsym(void *handle, const char *name)
static HocParmLimits limits[]
double chkarg(int, double low, double high)
static void destruct(void *v)
static void * cons(Object *o)
void hoc_reg_nmodl_filename(int mechtype, const char *filename)
void hoc_reg_nmodl_text(int mechtype, const char *txt)
double hoc_call_func(Symbol *s, int narg)
Symbol * hoc_install(const char *, int, double, Symlist **)
const char * expand_env_var(const char *s)
void hoc_retpushx(double x)
void hoc_symbol_limits(Symbol *sym, float low, float high)
Symbol * hoc_lookup(const char *)
void state_discontinuity(int i, double *pd, double d)
const char * nrn_mech_dll
bool is_array(const Symbol &sym)
hoc_List * hoc_l_newlist()
static void call(Symbol *s, Node *nd, Prop *p)
int nrn_semantics_from_ion(int type, int i)
static int ode_count(int type)
char * hoc_symbol_units(Symbol *, const char *)
void(*)(Prop *, int, neuron::container::data_handle< double > *, neuron::container::data_handle< double > *, double *, int) nrn_ode_map_t
void(*)(Memb_list *, std::size_t, Datum *, Datum *, double *, NrnThread *, int, neuron::model_sorted_token const &) nrn_thread_table_check_t
int(* nrn_ode_count_t)(int)
void(*)(neuron::model_sorted_token const &, NrnThread *, Memb_list *, int) nrn_cur_t
nrn_cur_t nrn_ode_matsol_t
void(*)(Node *, Datum *, Datum *, NrnThread *, Memb_list *, std::size_t, neuron::model_sorted_token const &) nrn_bamech_t
void(*)(neuron::model_sorted_token const &, NrnThread &, Memb_list &, int) nrn_ode_synonym_t
#define BEFORE_AFTER_SIZE
#define BEFORE_BREAKPOINT
static double map(void *v)
void move(Item *q1, Item *q2, Item *q3)
void nrn_threads_create(int n)
double * makevector(size_t size)
static const char * mechanism[]
void hoc_execerror(const char *s1, const char *s2)
void hoc_register_var(DoubScal *ds, DoubVec *dv, VoidFunc *)
void * erealloc(void *ptr, size_t size)
void * ecalloc(size_t n, size_t size)
static void * emalloc(size_t size)
void modl_reg()
Mechanism registration function.
void hoc_warning(const char *s1, const char *s2)
handle_interface< non_owning_identifier< storage > > handle
Non-owning handle to a Mechanism instance.
static int count_prop_param_size(const std::vector< std::pair< const char *, int >> ¶m_info)
void register_data_fields(int mechtype, std::vector< std::pair< std::string, int >> const ¶m_info, std::vector< std::pair< std::string, std::string >> const &dparam_info)
static void register_data_fields(int mech_type, Fields const &... fields)
Type- and array-aware version of hoc_register_prop_size.
int get_field_count< double >(int mech_type)
int const * get_array_dims< double >(int mech_type)
double *const * get_data_ptrs< double >(int mech_type)
Model & model()
Access the global Model instance.
Prop * prop_alloc(Prop **, int, Node *)
data_handle< T > transform(data_handle< T > handle, Transform type)
void SectionRef_reg(void)
void(*)(double *, int *, int *, int *, Memb_list *, std::size_t, Datum *, Datum *, double *, NrnThread *) bbcore_write_t
static Node * node(Object *)
int const size_t const size_t n
void(* pnt_receive_t)(Point_process *, double *, double)
void(* pnt_receive_init_t)(Point_process *, double *, double)
void(* NrnWatchAllocateFunc_t)(Datum *)
void steer_point_process(void *v)
int nrn_noauto_dlopen_nrnmech
static const char * morph_mech[]
static struct @36 usrprop[]
void nrn_verify_ion_charge_defined()
const char ** nrn_nmodl_filename_
double _modl_get_dt_thread(NrnThread *nt)
void hoc_reg_ba(int mt, nrn_bamech_t f, int type)
void hoc_nrn_load_dll(void)
short * nrn_is_artificial_
short * nrn_artcell_qindex_
double nrn_call_mech_func(Symbol *s, int narg, Prop *p, int mechtype)
static HocParmLimits _hoc_parm_limits[]
void add_nrn_fornetcons(int type, int indx)
void nrnunit_use_legacy()
NrnWatchAllocateFunc_t * nrn_watch_allocate_
int * nrn_fornetcon_type_
int count_variables_in_mechanism(const char **m2, int modltypemax)
void * nrn_realpath_dlopen(const char *relpath, int flags)
void hoc_reg_bbcore_read(int mechtype, bbcore_write_t f)
void _cvode_abstol(Symbol **s, double *tol, int i)
std::vector< Memb_list > memb_list
void _modl_set_dt_thread(double newdt, NrnThread *nt)
void hoc_register_limits(int mechtype, HocParmLimits *limits)
std::vector< Memb_func > memb_func
pnt_receive_init_t * pnt_receive_init
static HocParmUnits _hoc_parm_units[]
int * nrn_fornetcon_index_
void hoc_register_npy_direct(int mechtype, NPyDirectMechFunc *f)
Support mechanism FUNCTION/PROCEDURE python syntax seg.mech.f()
void register_mech(const char **m, Pvmp alloc, nrn_cur_t cur, nrn_jacob_t jacob, nrn_state_t stat, nrn_init_t initialize, int nrnpointerindex, int vectorized)
void hoc_register_synonym(int i, nrn_ode_synonym_t syn)
static std::vector< double > morph_parm_default
Point_process ** point_process
int mswin_load_dll(const char *cp1)
int nrn_netrec_state_adjust
cTemplate ** nrn_pnt_template_
int nrn_load_dll_recover_error()
int nrn_dparam_semantics_to_int(const char *name)
static int memb_func_size_
std::unordered_map< int, NPyDirectMechFuncs > nrn_mech2funcs_map
void class2oc_base(const char *, ctor_f *cons, dtor_f *destruct, Member_func *, Member_ret_obj_func *, Member_ret_str_func *)
int point_register_mech(const char **m, Pvmp alloc, nrn_cur_t cur, nrn_jacob_t jacob, nrn_state_t stat, nrn_init_t initialize, int nrnpointerindex, int vectorized, void *(*constructor)(Object *), void(*destructor)(void *), Member_func *fmember)
int * nrn_prop_param_size_
int state_discon_allowed_
void hoc_register_cvode(int i, nrn_ode_count_t cnt, nrn_ode_map_t map, nrn_ode_spec_t spec, nrn_ode_matsol_t matsol)
void hoc_reg_bbcore_write(int mechtype, bbcore_write_t f)
int nrn_is_artificial(int pnttype)
int point_reg_helper(Symbol *s2)
void initialize_memb_func(int mechtype, nrn_cur_t cur, nrn_jacob_t jacob, Pvmp alloc, nrn_state_t stat, nrn_init_t initialize, int vectorized)
int nrn_has_net_event_cnt_
void add_nrn_artcell(int mechtype, int qi)
void _nrn_thread_table_reg(int i, nrn_thread_table_check_t f)
int * nrn_dparam_ptr_start_
void hoc_register_parm_default(int mechtype, const std::vector< double > *pd)
void _modl_set_dt(double newdt)
std::vector< int > & nrn_mech_random_indices(int type)
dparam indices with random semantics for mechtype
void nrn_load_name_check(const char *name)
void hoc_register_tolerance(int mechtype, HocStateTolerance *tol, Symbol ***stol)
int * nrn_prop_dparam_size_
void hoc_register_prop_size(int mechtype, int psize, int dpsize)
Legacy way of registering mechanism data/pdata size.
bbcore_write_t * nrn_bbcore_write_
void nrn_writes_conc(int mechtype, int unused)
std::unordered_map< int, void(*)(Prop *)> nrn_mech_inst_destruct
double hoc_default_dll_loaded_
void register_destructor(Pvmp d)
Symlist * nrn_load_dll_called_
int * nrn_dparam_ptr_end_
void reallocate_mech_data(int mechtype)
pnt_receive_t * pnt_receive
const char ** nrn_nmodl_text_
void hoc_reg_watch_allocate(int type, NrnWatchAllocateFunc_t waf)
void(* nrnpy_reg_mech_p_)(int)
bbcore_write_t * nrn_bbcore_read_
void register_mech_vars(const char **var_buffers, int modltypemax, Symbol *mech_symbol, int mechtype, int nrnpointerindex)
static char nmodl_version_[]
void check_mech_version(const char **m)
void hoc_register_units(int mechtype, HocParmUnits *units)
void nrn_register_mech_common(const char **m, Pvmp alloc, nrn_cur_t cur, nrn_jacob_t jacob, nrn_state_t stat, nrn_init_t initialize, int nrnpointerindex, int vectorized)
void add_nrn_has_net_event(int mechtype)
void hoc_register_dparam_semantics(int mechtype, int ix, const char *name)
Legacy way of registering pdata semantics.
void _nrn_setdata_reg(int i, void(*call)(Prop *))
void _nrn_thread_reg(int i, int cons, void(*f)(Datum *))
HOC interpreter function declarations (included by hocdec.h)
static void * constructor(Object *ho)
static void destructor(void *v)
void SectionList_reg(void)
Symlist * hoc_built_in_symlist
Represent main neuron object computed by single thread.
A point process is computed just like regular mechanisms.
struct Symbol::@45::@46 rng
void delete_mechanism(int type)
Destroy the structure holding the data of a particular mechanism.
container::Mechanism::storage & add_mechanism(int type, Args &&... args)
Create a structure to hold the data of a new Mechanism.
container::Mechanism::storage & mechanism_data(int type)
Get the structure holding the data of a particular Mechanism.
Catch-all for floating point per-instance variables in the MOD file.
Non-template stable handle to a generic value.
int const * get_array_dims() const
Get a pointer to an array holding the array dimensions of the fields associated with this tag.
constexpr Tag const & get_tag() const
Get the instance of the given tag type.
Tag::type *const * get_data_ptrs() const
Get a pointer to a range of pointers that always point to the start of the contiguous storage.
int Fprintf(FILE *stream, const char *fmt, Args... args)