1 #include <../../nrnconf.h>
8 #include <../nrnoc/section.h>
9 #include <../nrnoc/nrn_ansi.h>
10 #include <../nrnoc/multicore.h>
19 #include <nanobind/nanobind.h>
21 namespace nb = nanobind;
23 static void ode_solve(
double,
double*,
double*);
139 static inline void*
allocopy(
void* src,
size_t size) {
140 void* dst = malloc(size);
141 memcpy(dst, src, size);
188 memcpy(
_curr_indices, curr_index,
sizeof(
int) * num_currents);
190 _curr_scales = (
double*) malloc(
sizeof(
double) * num_currents);
191 memcpy(
_curr_scales, curr_scale,
sizeof(
double) * num_currents);
194 for (
int i = 0;
i < num_currents;
i++)
208 for (
i = 0;
i < conc_count;
i++)
219 int i = 0,
j,
k,
n, grid_id;
235 if (grid_id == grids[
i])
236 n = grid_counts[
i++];
267 if (grid_id == grids[
i]) {
269 if (grid_counts[
i] > 0) {
271 grid_counts[
i] *
sizeof(
long));
273 grid_counts[
i] *
sizeof(
double));
277 offset += grid_counts[
i++];
281 if (grid_id == grids[
i]) {
283 if (grid_counts[
i] > 0) {
286 grid_counts[
i] *
sizeof(
double));
290 offset += grid_counts[
i++];
320 for (
size_t i = 0;
i <
n;
i++) {
322 if (PyFloat_Check(source[
i])) {
323 states[
j] +=
dt * PyFloat_AsDouble(source[
i]) / scale[
i];
324 }
else if (PyCallable_Check(source[
i])) {
335 auto result = nb::steal(PyObject_CallObject(source[
i],
nullptr));
336 if (PyFloat_Check(
result.ptr())) {
338 }
else if (PyLong_Check(
result.ptr())) {
343 PyErr_SetString(PyExc_Exception,
344 "node._include_flux callback did not return a number.\n");
348 PyErr_SetString(PyExc_Exception,
"node._include_flux unrecognised source term.\n");
362 double* nonzero_values,
363 double* c_diagonal) {
367 unsigned int* parent_count;
388 _rxd_a = (
double*) calloc(nrow,
sizeof(
double));
389 _rxd_b = (
double*) calloc(nrow,
sizeof(
double));
390 _rxd_c = (
double*) calloc(nrow,
sizeof(
double));
391 _rxd_d = (
double*) calloc(nrow,
sizeof(
double));
392 _rxd_p = (
long*) malloc(nrow *
sizeof(
long));
393 parent_count = (
unsigned int*) calloc(nrow,
sizeof(
unsigned int));
395 for (idx = 0; idx < nrow; idx++)
398 for (idx = 0; idx < nnonzero; idx++) {
401 val = nonzero_values[idx];
413 for (idx = 0; idx < nrow; idx++) {
432 for (
j = 0,
k = 0;
k < ps;
j++) {
454 for (side = 0; side < 2; side++) {
464 static void mul(
int nnonzero,
467 const double* nonzero_values,
473 for (
k = 0;
k < nnonzero;
k++) {
518 double* d = (
double*) malloc(
sizeof(
double) *
n);
529 for (
i = 0;
i <
n;
i++) {
530 *myd++ = *myc++ +
dt * (*mydbase++);
534 for (
i =
n - 1;
i > 0; --
i) {
538 p =
dt * a[
i] / d[
i];
539 d[pin] -=
dt *
p * b[
i];
544 for (
i = 0;
i <
n; ++
i) {
560 double *full_b, *full_y;
564 full_b = (
double*) calloc(
sizeof(
double),
num_states);
565 full_y = (
double*) calloc(
sizeof(
double),
num_states);
570 full_b[
i] = b[
i -
j];
571 full_y[
i] = y[
i -
j];
588 b[
i -
j] = full_b[
i];
641 int i,
j,
k,
id, side, count;
642 int* induced_currents_ecs_idx;
643 int* induced_currents_grid_id;
645 double* current_scales;
675 for (
i = 0,
k = 0;
i < num_currents;
i++) {
681 for (
j = 0;
j < num_species[
i];
j++,
k++) {
687 for (side = 0; side < 2; side++) {
691 for (side = 0; side < 2; side++) {
711 if (induced_currents_grid_id[
k] ==
id) {
717 ecs_indices = (
int*) malloc(count *
sizeof(
int));
720 if (induced_currents_grid_id[
k] ==
id) {
721 ecs_indices[
i] = induced_currents_ecs_idx[
k];
722 ecs_ptrs[
i++] = ptrs[
k];
729 if (induced_currents_grid_id[
k] ==
id)
739 free(induced_currents_ecs_idx);
740 free(induced_currents_grid_id);
744 int i,
j,
k, idx, side;
762 for (side = 0; side < 2; side++) {
841 printf(
"Unknown rxd_nonvint_block call: %d\n", method);
868 int i,
j,
k, idx, ecs_id, ecs_index, ecs_offset;
869 unsigned char counted;
884 react->
vptrs = (
double**) malloc(nseg *
sizeof(
double*));
885 for (
i = 0;
i < nseg;
i++)
886 react->
vptrs[
i] =
static_cast<double*
>(vptrs[
i]->
u.
px_);
890 react->
state_idx = (
int***) malloc(nseg *
sizeof(
int**));
891 for (
i = 0, idx = 0;
i < nseg;
i++) {
892 react->
state_idx[
i] = (
int**) malloc((nspecies + nparam) *
sizeof(
int*));
893 for (
j = 0;
j < nspecies + nparam;
j++) {
894 react->
state_idx[
i][
j] = (
int*) malloc(nregions *
sizeof(
int));
895 for (
k = 0;
k < nregions;
k++, idx++) {
900 if (
i == 0 &&
j < nspecies)
907 react->
mc_multiplier = (
double**) malloc(nmult *
sizeof(
double*));
908 for (
i = 0;
i < nmult;
i++) {
909 react->
mc_multiplier[
i] = (
double*) malloc(nseg *
sizeof(
double));
910 memcpy(react->
mc_multiplier[
i], (mult +
i * nseg), nseg *
sizeof(
double));
916 react->
ecs_state = (
double***) malloc(nseg *
sizeof(
double**));
917 react->
ecs_index = (
int**) malloc(nseg *
sizeof(
int*));
919 for (
i = 0;
i < nseg;
i++) {
920 react->
ecs_state[
i] = (
double**) malloc((necs + necsparam) *
sizeof(
double*));
921 react->
ecs_index[
i] = (
int*) malloc((necs + necsparam) *
sizeof(int));
923 for (
j = 0;
j < necs + necsparam;
j++) {
927 if (ecs_id == ecs_ids[
j]) {
936 for (
i = 0, counted =
FALSE;
i < nseg;
i++) {
938 ecs_index = ecsidx[
i * (necs + necsparam) +
j];
940 if (ecs_index >= 0) {
943 if (
j < necs && !counted) {
973 react->
flux = (
double**) malloc(react->
icsN *
sizeof(
double*));
974 for (
i = 0;
i < react->
icsN;
i++)
1042 for (
i = 0;
i < react->
icsN;
i++)
1043 free(react->
flux[
i]);
1066 react = react->
next;
1084 if (list->
id ==
id) {
1097 list->
indices = (
int*) malloc(
sizeof(
int) * len);
1098 memcpy(list->
indices, idx,
sizeof(
int) * len);
1108 if (list->
id ==
id) {
1151 std::lock_guard<std::mutex> _{
q->task_mutex};
1162 std::lock_guard<std::mutex> _{
q->waiting_mutex};
1168 q->task_cond.notify_one();
1177 std::unique_lock<std::mutex>
lock{
q->task_mutex};
1180 q->task_cond.wait(
lock,
1181 [
q, thread_index] {
return q->first ||
q->exit[thread_index]; });
1182 if (
q->exit[thread_index]) {
1186 q->first = job->next;
1189 job->result = job->task(job->args);
1194 auto const new_length = [
q] {
1195 std::lock_guard<std::mutex> _{
q->waiting_mutex};
1196 return --(
q->length);
1200 if (new_length == 0) {
1203 q->waiting_cond.notify_one();
1215 std::size_t
const new_num =
n - 1;
1218 if (new_num < old_num) {
1225 for (
auto k = new_num;
k < old_num; ++
k) {
1231 for (
auto k = new_num;
k < old_num; ++
k) {
1240 }
else if (new_num > old_num) {
1245 for (
auto k = old_num;
k < new_num; ++
k) {
1259 std::unique_lock<std::mutex>
lock{
q->waiting_mutex};
1260 q->waiting_cond.wait(
lock, [
q] {
return q->length == 0; });
1340 const unsigned char calculate_rhs = p2 ==
NULL ? 0 : 1;
1377 if (!calculate_rhs) {
1399 const double* states3d = orig_states3d;
1400 double* ydot3d = orig_ydot3d;
1407 ydot3d += grid_size;
1408 states3d += grid_size;
1441 for (
i = 0;
i < react->
icsN;
i++)
1444 for (segment = 0; segment < react->
num_segments; segment++) {
1486 v = *(react->
vptrs[segment]);
1507 if (rates !=
NULL) {
1527 double* cvode_states,
1530 int i,
j,
k, idx, jac_i, jac_j, jac_idx;
1534 double dx = FLT_EPSILON;
1536 auto b = std::make_unique<IvocVect>(N);
1537 auto x = std::make_unique<IvocVect>(N);
1545 for (segment = 0; segment < react->
num_segments; segment++) {
1547 v = *(react->
vptrs[segment]);
1575 if (cvode_states !=
NULL) {
1615 b->elem(idx) = bval[react->
state_idx[segment][
i][
j]];
1634 for (jac_i = 0, jac_idx = 0; jac_i < react->
num_species; jac_i++) {
1635 for (jac_j = 0; jac_j < react->
num_regions; jac_j++) {
1641 jacobian(jac_idx, idx) = (idx == jac_idx) -
dt * pd;
1669 b->elem(idx) = cvode_b[react->
ecs_index[segment][
i]];
1688 for (jac_i = 0, jac_idx = 0; jac_i < react->
num_species; jac_i++) {
1689 for (jac_j = 0; jac_j < react->
num_regions; jac_j++) {
1704 jacobian(jac_idx, idx) = (idx == jac_idx) -
dt * pd;
1716 jacobian.solv(b.get(), x.get(),
false);
1724 bval[idx] = x->elem(jac_idx++);
1740 states[idx] += x->elem(jac_idx++);
double * set_rxd_currents(int, int *, PyHocObject **)
void initialize_multicompartment_reaction()
int add_multicompartment_reaction(int, int *, int)
double * all_reaction_states
double * local_induced_currents
virtual void variable_step_hybrid_connections(const double *cvode_states_3d, double *const ydot_3d, const double *cvode_states_1d, double *const ydot_1d)=0
PyObject ** node_flux_src
static double jacobian(void *v)
Grid_node * Parallel_grids[100]
void(double **, double **, double **, double *, double *, double *, double *, double **, double) ReactionRate
static int ode_count(int type)
std::vector< std::thread > Threads
int const size_t const size_t n
NRN_EXPORT void rxd_set_no_diffusion()
NRN_EXPORT void setup_solver(double *my_states, int my_num_states, long *zvi, int num_zvi)
std::vector< neuron::container::data_handle< double > > _curr_ptrs
int prev_structure_change_cnt
NRN_EXPORT void rxd_include_node_flux3D(int grid_count, int *grid_counts, int *grids, long *index, double *scales, PyObject **sources)
NRN_EXPORT int get_num_threads(void)
NRN_EXPORT void rxd_setup_curr_ptrs(int num_currents, int *curr_index, double *curr_scale, PyHocObject **curr_ptrs)
static void free_zvi_child()
void TaskQueue_exe_tasks(std::size_t thread_index, TaskQueue *q)
void get_all_reaction_rates(double *states, double *rates, double *ydot)
NRN_EXPORT void set_num_threads(const int n)
NRN_EXPORT void remove_species_atolscale(int id)
NRN_EXPORT void set_initialize(fptr *initialize_fn)
double * _rxd_induced_currents_scale
NRN_EXPORT void set_setup_matrices(fptr *setup_matrices)
unsigned char _membrane_flux
long * _rxd_euler_nonzero_j
SpeciesIndexList * species_indices
unsigned int * _rxd_zvi_child_count
NRN_EXPORT void set_setup(fptr *setup_fn)
NRN_EXPORT void species_atolscale(int id, double scale, int len, int *idx)
void apply_node_flux(int n, long *index, double *scale, PyObject **source, double dt, double *states)
long * _rxd_euler_nonzero_i
double * _rxd_euler_nonzero_values
static void add_currents(double *result)
ECS_Grid_node ** _rxd_induced_currents_grid
void do_ics_reactions(double *states, double *b, double *cvode_states, double *cvode_b)
static void nrn_tree_solve(double *a, double *b, double *c, double *dbase, double *rhs, long *pindex, long n, double dt)
void _ode_reinit(double *y)
static void ode_abs_tol(double *p1)
static void * allocopy(void *src, size_t size)
NRN_EXPORT void clear_rates()
int * _memb_species_count
static void transfer_to_legacy()
NRN_EXPORT void rxd_setup_conc_ptrs(int conc_count, int *conc_index, PyHocObject **conc_ptrs)
long * _rxd_zero_volume_indices
NRN_EXPORT void set_setup_units(fptr *setup_units)
int *** _memb_cur_mapped_ecs
void _rhs_variable_step(const double *p1, double *p2)
NRN_EXPORT void rxd_include_node_flux1D(int n, long *index, double *scales, PyObject **sources)
NRN_EXPORT void free_curr_ptrs()
double * _rxd_induced_currents
void get_reaction_rates(ICSReactions *react, double *states, double *rates, double *ydot)
NRN_EXPORT void rxd_set_euler_matrix(int nrow, int nnonzero, long *nonzero_i, long *nonzero_j, double *nonzero_values, double *c_diagonal)
double * _node_flux_scale
static void ode_solve(double, double *, double *)
void TaskQueue_add_task(TaskQueue *q, void *(*task)(void *), void *args, void *result)
NRN_EXPORT void setup_currents(int num_currents, int num_fluxes, int *num_species, int *node_idxs, double *scales, PyHocObject **ptrs, int *mapped, int *mapped_ecs)
static void apply_node_flux1D(double dt, double *states)
static void mul(int nnonzero, long *nonzero_i, long *nonzero_j, const double *nonzero_values, const double *v, double *result)
ICSReactions * _reactions
std::vector< std::vector< neuron::container::data_handle< double > > > _memb_cur_ptrs
PyObject ** _node_flux_src
static void _currents(double *rhs)
void solve_reaction(ICSReactions *react, double *states, double *bval, double *cvode_states, double *cvode_b)
unsigned char initialized
NRN_EXPORT void register_rate(int nspecies, int nparam, int nregions, int nseg, int *sidx, int necs, int necsparam, int *ecs_ids, int *ecsidx, int nmult, double *mult, PyHocObject **vptrs, ReactionRate *f)
NRN_EXPORT void free_conc_ptrs()
void TaskQueue_sync(TaskQueue *q)
std::vector< neuron::container::data_handle< double > > _conc_ptrs
PyTypeObject * hocobject_type
static void free_currents()
NRN_EXPORT int rxd_nonvint_block(int method, int size, double *p1, double *p2, int)
void _rhs_variable_step_ecs(const double *, double *)
void ecs_atolscale(double *)
void _ecs_ode_reinit(double *)
void set_num_threads_3D(int n)
void ics_ode_solve(double, double *, const double *)
void _fadvance_fixed_step_3D(void)
double ** result_array_dx
struct ICSReactions * next
double * ecs_states_for_reaction
double ** states_for_reaction_dx
double ** params_for_reaction
ECS_Grid_node ** ecs_grid
double ** states_for_reaction
double * ecs_states_for_reaction_dx
double * ecs_params_for_reaction
Represent main neuron object computed by single thread.
neuron::container::data_handle< double > px_
struct SpeciesIndexList * next
std::condition_variable task_cond