1 #include <../../nrnconf.h>
7 #include <../nrnoc/section.h>
8 #include <../nrnoc/nrn_ansi.h>
9 #include <../nrnoc/multicore.h>
13 static void ode_solve(
double,
double*,
double*);
127 static inline void*
allocopy(
void* src,
size_t size) {
128 void* dst = malloc(size);
129 memcpy(dst, src, size);
182 memcpy(
_curr_indices, curr_index,
sizeof(
int) * num_currents);
184 _curr_scales = (
double*) malloc(
sizeof(
double) * num_currents);
185 memcpy(
_curr_scales, curr_scale,
sizeof(
double) * num_currents);
187 _curr_ptrs = (
double**) malloc(
sizeof(
double*) * num_currents);
188 for (
i = 0;
i < num_currents;
i++)
200 _conc_ptrs = (
double**) malloc(
sizeof(
double*) * conc_count);
201 for (
i = 0;
i < conc_count;
i++)
210 PyObject** sources) {
212 int i = 0,
j,
k,
n, grid_id;
216 if (
g->node_flux_count > 0) {
217 g->node_flux_count = 0;
218 free(
g->node_flux_scale);
219 free(
g->node_flux_idx);
220 free(
g->node_flux_src);
228 if (grid_id == grids[
i])
229 n = grid_counts[
i++];
234 nrnmpi_int_allgather_inplace(
g->proc_num_fluxes, 1);
236 g->proc_flux_offsets[0] = 0;
238 g->proc_flux_offsets[
j] =
g->proc_flux_offsets[
j - 1] +
g->proc_num_fluxes[
j - 1];
239 g->node_flux_count =
g->proc_flux_offsets[
j - 1] +
g->proc_num_fluxes[
j - 1];
242 g->node_flux_idx = (
long*) malloc(
g->node_flux_count *
sizeof(
long));
243 g->node_flux_scale = (
double*) malloc(
g->node_flux_count *
sizeof(
double));
244 g->node_flux_src = (PyObject**)
allocopy(&sources[offset],
n *
sizeof(PyObject*));
248 g->node_flux_idx[
k] =
index[offset +
j];
249 g->node_flux_scale[
k] = scales[offset +
j];
251 nrnmpi_long_allgatherv_inplace(
g->node_flux_idx,
253 g->proc_flux_offsets);
254 nrnmpi_dbl_allgatherv_inplace(
g->node_flux_scale,
256 g->proc_flux_offsets);
260 if (grid_id == grids[
i]) {
261 g->node_flux_count = grid_counts[
i];
262 if (grid_counts[
i] > 0) {
264 grid_counts[
i] *
sizeof(
long));
265 g->node_flux_scale = (
double*)
allocopy(&scales[offset],
266 grid_counts[
i] *
sizeof(
double));
267 g->node_flux_src = (PyObject**)
allocopy(&sources[offset],
268 grid_counts[
i] *
sizeof(PyObject*));
270 offset += grid_counts[
i++];
274 if (grid_id == grids[
i]) {
275 g->node_flux_count = grid_counts[
i];
276 if (grid_counts[
i] > 0) {
277 g->node_flux_idx = (
long*)
allocopy(&
index[offset], grid_counts[
i] *
sizeof(
long));
278 g->node_flux_scale = (
double*)
allocopy(&scales[offset],
279 grid_counts[
i] *
sizeof(
double));
280 g->node_flux_src = (PyObject**)
allocopy(&sources[offset],
281 grid_counts[
i] *
sizeof(PyObject*));
283 offset += grid_counts[
i++];
310 for (
size_t i = 0;
i <
n;
i++) {
312 if (PyFloat_Check(source[
i])) {
313 states[
j] +=
dt * PyFloat_AsDouble(source[
i]) / scale[
i];
314 }
else if (PyCallable_Check(source[
i])) {
325 auto result = PyObject_CallObject(source[
i],
nullptr);
326 if (PyFloat_Check(
result)) {
328 }
else if (PyLong_Check(
result)) {
335 PyErr_SetString(PyExc_Exception,
336 "node._include_flux callback did not return a number.\n");
340 PyErr_SetString(PyExc_Exception,
"node._include_flux unrecognised source term.\n");
354 double* nonzero_values,
355 double* c_diagonal) {
359 unsigned int* parent_count;
380 _rxd_a = (
double*) calloc(nrow,
sizeof(
double));
381 _rxd_b = (
double*) calloc(nrow,
sizeof(
double));
382 _rxd_c = (
double*) calloc(nrow,
sizeof(
double));
383 _rxd_d = (
double*) calloc(nrow,
sizeof(
double));
384 _rxd_p = (
long*) malloc(nrow *
sizeof(
long));
385 parent_count = (
unsigned int*) calloc(nrow,
sizeof(
unsigned int));
387 for (idx = 0; idx < nrow; idx++)
390 for (idx = 0; idx < nnonzero; idx++) {
393 val = nonzero_values[idx];
405 for (idx = 0; idx < nrow; idx++) {
424 for (
j = 0,
k = 0;
k < ps;
j++) {
446 for (side = 0; side < 2; side++) {
456 static void mul(
int nnonzero,
459 const double* nonzero_values,
465 for (
k = 0;
k < nnonzero;
k++) {
511 double* d = (
double*) malloc(
sizeof(
double) *
n);
522 for (
i = 0;
i <
n;
i++) {
523 *myd++ = *myc++ +
dt * (*mydbase++);
527 for (
i =
n - 1;
i > 0; --
i) {
531 p =
dt * a[
i] / d[
i];
532 d[pin] -=
dt *
p * b[
i];
537 for (
i = 0;
i <
n; ++
i) {
553 double *full_b, *full_y;
557 full_b = (
double*) calloc(
sizeof(
double),
num_states);
558 full_y = (
double*) calloc(
sizeof(
double),
num_states);
563 full_b[
i] = b[
i -
j];
564 full_y[
i] = y[
i -
j];
581 b[
i -
j] = full_b[
i];
635 int i,
j,
k,
id, side, count;
636 int* induced_currents_ecs_idx;
637 int* induced_currents_grid_id;
639 double* current_scales;
661 _memb_cur_ptrs = (
double***) malloc(
sizeof(
double**) * num_currents);
670 for (
i = 0,
k = 0;
i < num_currents;
i++) {
677 for (
j = 0;
j < num_species[
i];
j++,
k++) {
683 for (side = 0; side < 2; side++) {
687 for (side = 0; side < 2; side++) {
707 if (induced_currents_grid_id[
k] ==
id) {
713 ecs_indices = (
int*) malloc(count *
sizeof(
int));
716 if (induced_currents_grid_id[
k] ==
id) {
717 ecs_indices[
i] = induced_currents_ecs_idx[
k];
718 ecs_ptrs[
i++] = ptrs[
k];
725 if (induced_currents_grid_id[
k] ==
id)
735 free(induced_currents_ecs_idx);
736 free(induced_currents_grid_id);
740 int i,
j,
k, idx, side;
758 for (side = 0; side < 2; side++) {
795 g->initialize_multicompartment_reaction();
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++)
890 react->
state_idx = (
int***) malloc(nseg *
sizeof(
double**));
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) {
1013 if (list->
id ==
id) {
1026 list->
indices = (
int*) malloc(
sizeof(
int) * len);
1027 memcpy(list->
indices, idx,
sizeof(
int) * len);
1037 if (list->
id ==
id) {
1049 extern "C" void setup_solver(
double* my_states,
int my_num_states,
long* zvi,
int num_zvi) {
1072 Threads = (pthread_t*) malloc(
sizeof(pthread_t) * (
n - 1));
1082 for (
i = 0;
i <
n - 1;
i++)
1096 pthread_mutex_lock(
q->task_mutex);
1097 if (
q->first ==
NULL)
1107 pthread_mutex_lock(
q->waiting_mutex);
1109 pthread_mutex_unlock(
q->waiting_mutex);
1110 pthread_mutex_unlock(
q->task_mutex);
1113 pthread_cond_signal(
q->task_cond);
1131 pthread_mutex_lock(
q->task_mutex);
1132 while (
q->first ==
NULL)
1135 pthread_cond_wait(
q->task_cond,
q->task_mutex);
1139 q->first = job->
next;
1140 pthread_mutex_unlock(
q->task_mutex);
1147 pthread_mutex_lock(
q->waiting_mutex);
1148 if (--(
q->length) == 0)
1150 pthread_cond_broadcast(
q->waiting_cond);
1152 pthread_mutex_unlock(
q->waiting_mutex);
1167 for (
k = old_num - 1;
k >=
n;
k--) {
1173 }
else if (
n > old_num) {
1178 for (
k = old_num - 1;
k <
n;
k++) {
1189 pthread_mutex_lock(
q->waiting_mutex);
1190 while (
q->length > 0)
1191 pthread_cond_wait(
q->waiting_cond,
q->waiting_mutex);
1192 pthread_mutex_unlock(
q->waiting_mutex);
1272 const unsigned char calculate_rhs = p2 ==
NULL ? 0 : 1;
1309 if (!calculate_rhs) {
1331 const double* states3d = orig_states3d;
1332 double* ydot3d = orig_ydot3d;
1339 ydot3d += grid_size;
1340 states3d += grid_size;
1368 double** states_for_reaction = (
double**) malloc(react->
num_species *
sizeof(
double*));
1369 double** params_for_reaction = (
double**) malloc(react->
num_params *
sizeof(
double*));
1370 double** result_array = (
double**) malloc(react->
num_species *
sizeof(
double*));
1371 double* mc_mult =
NULL;
1374 mc_mult = (
double*) malloc(react->
num_mult *
sizeof(
double));
1376 double* ecs_states_for_reaction =
NULL;
1377 double* ecs_params_for_reaction =
NULL;
1378 double* ecs_result =
NULL;
1379 int* ecsindex =
NULL;
1382 ecs_states_for_reaction = (
double*) malloc(react->
num_ecs_species *
sizeof(
double));
1383 ecs_result = (
double*) malloc(react->
num_ecs_species *
sizeof(
double));
1386 ecs_params_for_reaction = (
double*) calloc(react->
num_ecs_params,
sizeof(
double));
1389 flux = (
double**) malloc(react->
icsN *
sizeof(
double*));
1390 for (
i = 0;
i < react->
icsN;
i++)
1395 states_for_reaction[
i] = (
double*) calloc(react->
num_regions,
sizeof(
double));
1396 result_array[
i] = (
double*) malloc(react->
num_regions *
sizeof(
double));
1399 params_for_reaction[
i] = (
double*) calloc(react->
num_regions,
sizeof(
double));
1410 states_for_reaction[
i][
j] = NAN;
1420 params_for_reaction[
k][
j] = NAN;
1427 ecs_states_for_reaction[
i] = *(react->
ecs_state[segment][
i]);
1429 ecs_states_for_reaction[
i] = NAN;
1434 ecs_params_for_reaction[
k] = *(react->
ecs_state[segment][
i]);
1436 ecs_params_for_reaction[
k] = NAN;
1446 v = *(react->
vptrs[segment]);
1449 react->
reaction(states_for_reaction,
1450 params_for_reaction,
1453 ecs_states_for_reaction,
1454 ecs_params_for_reaction,
1467 if (rates !=
NULL) {
1468 rates[idx] += result_array[
i][
j];
1485 for (
i = 0;
i < react->
icsN;
i++)
1490 free(ecs_states_for_reaction);
1494 free(states_for_reaction[
i]);
1495 free(result_array[
i]);
1497 free(states_for_reaction);
1500 free(params_for_reaction[
i]);
1502 free(params_for_reaction);
1504 free(ecs_params_for_reaction);
1511 double* cvode_states,
1514 int i,
j,
k, idx, jac_i, jac_j, jac_idx;
1518 double dx = FLT_EPSILON;
1524 double** states_for_reaction = (
double**) malloc(react->
num_species *
sizeof(
double*));
1525 double** states_for_reaction_dx = (
double**) malloc(react->
num_species *
sizeof(
double*));
1526 double** params_for_reaction = (
double**) malloc(react->
num_params *
sizeof(
double*));
1527 double** result_array = (
double**) malloc(react->
num_species *
sizeof(
double*));
1528 double** result_array_dx = (
double**) malloc(react->
num_species *
sizeof(
double*));
1529 double* mc_mult =
NULL;
1531 mc_mult = (
double*) malloc(react->
num_mult *
sizeof(
double));
1533 double* ecs_states_for_reaction =
NULL;
1534 double* ecs_states_for_reaction_dx =
NULL;
1535 double* ecs_params_for_reaction =
NULL;
1536 double* ecs_result =
NULL;
1537 double* ecs_result_dx =
NULL;
1539 int* ecsindex =
NULL;
1545 ecs_states_for_reaction = (
double*) malloc(react->
num_ecs_species *
sizeof(
double));
1546 ecs_states_for_reaction_dx = (
double*) malloc(react->
num_ecs_species *
sizeof(
double));
1547 ecs_result = (
double*) malloc(react->
num_ecs_species *
sizeof(
double));
1548 ecs_result_dx = (
double*) malloc(react->
num_ecs_species *
sizeof(
double));
1552 ecs_params_for_reaction = (
double*) malloc(react->
num_ecs_params *
sizeof(
double));
1556 states_for_reaction[
i] = (
double*) malloc(react->
num_regions *
sizeof(
double));
1557 states_for_reaction_dx[
i] = (
double*) malloc(react->
num_regions *
sizeof(
double));
1558 result_array[
i] = (
double*) malloc(react->
num_regions *
sizeof(
double));
1559 result_array_dx[
i] = (
double*) malloc(react->
num_regions *
sizeof(
double));
1562 params_for_reaction[
i] = (
double*) malloc(react->
num_regions *
sizeof(
double));
1564 for (segment = 0; segment < react->
num_segments; segment++) {
1566 v = *(react->
vptrs[segment]);
1572 states_for_reaction_dx[
i][
j] = states_for_reaction[
i][
j];
1575 states_for_reaction_dx[
i][
j] = states_for_reaction[
i][
j];
1594 if (cvode_states !=
NULL) {
1595 ecs_states_for_reaction[
i] = cvode_states[react->
ecs_index[segment][
i]];
1597 ecs_states_for_reaction[
i] = *(react->
ecs_state[segment][
i]);
1599 ecs_states_for_reaction_dx[
i] = ecs_states_for_reaction[
i];
1604 ecs_params_for_reaction[
k] = *(react->
ecs_state[segment][
i]);
1617 react->
reaction(states_for_reaction,
1618 params_for_reaction,
1621 ecs_states_for_reaction,
1622 ecs_params_for_reaction,
1638 states_for_reaction_dx[
i][
j] += dx;
1643 react->
reaction(states_for_reaction_dx,
1644 params_for_reaction,
1647 ecs_states_for_reaction,
1648 ecs_params_for_reaction,
1653 for (jac_i = 0, jac_idx = 0; jac_i < react->
num_species; jac_i++) {
1654 for (jac_j = 0; jac_j < react->
num_regions; jac_j++) {
1657 pd = (result_array_dx[jac_i][jac_j] - result_array[jac_i][jac_j]) /
1662 result_array_dx[jac_i][jac_j] = 0;
1668 pd = (ecs_result_dx[jac_i] - ecs_result[jac_i]) / dx;
1672 ecs_result_dx[jac_i] = 0;
1675 states_for_reaction_dx[
i][
j] -= dx;
1691 ecs_states_for_reaction_dx[
i] += dx;
1696 react->
reaction(states_for_reaction,
1697 params_for_reaction,
1700 ecs_states_for_reaction_dx,
1701 ecs_params_for_reaction,
1706 for (jac_i = 0, jac_idx = 0; jac_i < react->
num_species; jac_i++) {
1707 for (jac_j = 0; jac_j < react->
num_regions; jac_j++) {
1710 pd = (result_array_dx[jac_i][jac_j] - result_array[jac_i][jac_j]) / dx;
1719 pd = (ecs_result_dx[jac_i] - ecs_result[jac_i]) / dx;
1726 ecs_states_for_reaction_dx[
i] -= dx;
1773 free(states_for_reaction[
i]);
1774 free(states_for_reaction_dx[
i]);
1775 free(result_array[
i]);
1776 free(result_array_dx[
i]);
1779 free(params_for_reaction[
i]);
1782 free(states_for_reaction_dx);
1783 free(states_for_reaction);
1784 free(params_for_reaction);
1786 free(result_array_dx);
1788 free(ecs_states_for_reaction);
1789 free(ecs_states_for_reaction_dx);
1791 free(ecs_result_dx);
1794 free(ecs_params_for_reaction);
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
static double jacobian(void *v)
Grid_node * Parallel_grids[100]
void(* ReactionRate)(double **, double **, double **, double *, double *, double *, double *, double **, double)
static double v_get(void *v)
void flux(Item *qREACTION, Item *qdir, Item *qlast)
static int ode_count(int type)
MAT * LUfactor(MAT *A, PERM *pivot)
VEC * LUsolve(MAT *A, PERM *pivot, VEC *b, VEC *x)
#define m_set_val(A, i, j, val)
#define v_set_val(x, i, val)
int const size_t const size_t n
static philox4x32_key_t k
void rxd_include_node_flux1D(int n, long *index, double *scales, PyObject **sources)
int prev_structure_change_cnt
static void free_zvi_child()
void species_atolscale(int id, double scale, int len, int *idx)
void get_all_reaction_rates(double *states, double *rates, double *ydot)
double * _rxd_induced_currents_scale
unsigned char _membrane_flux
long * _rxd_euler_nonzero_j
SpeciesIndexList * species_indices
void set_initialize(const fptr initialize_fn)
void set_setup_units(fptr setup_units)
unsigned int * _rxd_zvi_child_count
void set_num_threads(const int n)
void rxd_setup_conc_ptrs(int conc_count, int *conc_index, PyHocObject **conc_ptrs)
void * TaskQueue_exe_tasks(void *dat)
void set_setup_matrices(fptr setup_matrices)
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 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)
void do_ics_reactions(double *states, double *b, double *cvode_states, double *cvode_b)
void start_threads(const int n)
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)
int * _memb_species_count
static void transfer_to_legacy()
long * _rxd_zero_volume_indices
void remove_species_atolscale(int id)
int *** _memb_cur_mapped_ecs
void _rhs_variable_step(const double *p1, double *p2)
double * _rxd_induced_currents
void rxd_set_no_diffusion()
void get_reaction_rates(ICSReactions *react, double *states, double *rates, double *ydot)
double * _node_flux_scale
static void ode_solve(double, double *, double *)
void TaskQueue_add_task(TaskQueue *q, void *(*task)(void *), void *args, void *result)
void rxd_setup_curr_ptrs(int num_currents, int *curr_index, double *curr_scale, PyHocObject **curr_ptrs)
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
PyObject ** _node_flux_src
int get_num_threads(void)
static void _currents(double *rhs)
void solve_reaction(ICSReactions *react, double *states, double *bval, double *cvode_states, double *cvode_b)
double *** _memb_cur_ptrs
unsigned char initialized
void rxd_include_node_flux3D(int grid_count, int *grid_counts, int *grids, long *index, double *scales, PyObject **sources)
void set_setup(const fptr setup_fn)
void TaskQueue_sync(TaskQueue *q)
PyTypeObject * hocobject_type
void rxd_set_euler_matrix(int nrow, int nnonzero, long *nonzero_i, long *nonzero_j, double *nonzero_values, double *c_diagonal)
int prev_nrnunit_use_legacy
void setup_solver(double *my_states, int my_num_states, long *zvi, int num_zvi)
void setup_currents(int num_currents, int num_fluxes, int *num_species, int *node_idxs, double *scales, PyHocObject **ptrs, int *mapped, int *mapped_ecs)
int rxd_nonvint_block(int method, int size, double *p1, double *p2, int)
static void free_currents()
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)
struct ICSReactions * next
ECS_Grid_node ** ecs_grid
Represent main neuron object computed by single thread.
struct SpeciesIndexList * next
pthread_mutex_t * waiting_mutex
pthread_cond_t * task_cond
pthread_cond_t * waiting_cond
pthread_mutex_t * task_mutex