NEURON
splitcell.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 
3 #include <vector>
4 #include <errno.h>
5 #include <nrnoc2iv.h>
6 #include <nrnmpi.h>
7 
8 /*
9 Started out attempting a general implementation in which the subtrees could be
10 on any host and any number of them. That required a distinct gid for each
11 subtree. However, since the only purpose of cellsplit is for load balance
12 efficiency, we settled on a very restrictive but still adequate policy of
13 subtrees being on adjacent hosts and at most one cell split between i and i+1
14 and at most one cell split between i and i-1. We also disallow a split where
15 both subtrees are on the same host. This policy allows a very simple and direct
16 setting up and transfer of matrix information. Note that gid information about
17 the subtrees is no longer required by this implementation.
18 */
19 
20 extern "C" int structure_change_cnt;
21 
22 #if PARANEURON
23 void nrnmpi_split_clear();
24 extern void (*nrnmpi_splitcell_compute_)();
25 extern void nrnmpi_send_doubles(double*, int cnt, int dest, int tag);
26 extern void nrnmpi_recv_doubles(double*, int cnt, int src, int tag);
27 extern double nrnmpi_splitcell_wait_;
28 
29 static int change_cnt_;
30 static void transfer();
31 static void set_structure();
32 static void splitcell_compute();
33 
34 struct SplitCell {
35  Section* rootsec_;
36  int that_host_;
37 };
38 
39 static std::vector<SplitCell> splitcell_list_;
40 
41 #define ip 0
42 #define im 2
43 static bool splitcell_connected_[2];
44 static double* transfer_p_[4];
45 
46 #endif
47 
48 // that_host must be adjacent to nrnmpi_myid
49 void nrnmpi_splitcell_connect(int that_host) {
50 #if PARANEURON
51  Section* rootsec = chk_access();
52  if (std::abs(nrnmpi_myid - that_host) != 1) {
53  hoc_execerror("cells may be split only on adjacent hosts", 0);
54  }
55  if (that_host < 0 || that_host >= nrnmpi_numprocs) {
56  hoc_execerror("adjacent host out of range", 0);
57  }
58  if (rootsec->parentsec) {
59  hoc_execerror(secname(rootsec), "is not a root section");
60  }
61  nrnmpi_splitcell_compute_ = splitcell_compute;
62  for (size_t i = 0; i < 2; ++i)
63  if (that_host == nrnmpi_myid + i * 2 - 1) {
64  if (splitcell_connected_[i]) {
65  char buf[100];
66  sprintf(buf, "%d and %d", nrnmpi_myid, that_host);
67  hoc_execerror("splitcell connection already exists between hosts", buf);
68  }
69  splitcell_connected_[i] = true;
70  }
71  splitcell_list_.push_back({rootsec, that_host});
72 #else
73  if (nrnmpi_myid == 0) {
74  hoc_execerror("ParallelContext.splitcell not available.",
75  "NEURON not configured with --with-paranrn");
76  }
77 #endif
78 }
79 
80 #if PARANEURON
81 
82 void nrnmpi_split_clear() {
83  if (nrnmpi_splitcell_compute_ == splitcell_compute) {
84  if (nrnmpi_myid == 0) {
85  hoc_execerror("nrnmpi_split_clear ", "not implemented");
86  }
87  }
88 }
89 
90 void splitcell_compute() {
91  if (structure_change_cnt != change_cnt_) {
92  set_structure();
93  change_cnt_ = structure_change_cnt;
94  }
95  transfer();
96 }
97 
98 void transfer() {
99  double trans[2], trans_sav[2];
100  double wt = nrnmpi_wtime();
101  if (transfer_p_[ip]) {
102  trans[0] = *transfer_p_[ip + 0];
103  trans[1] = *transfer_p_[ip + 1];
104  nrnmpi_send_doubles(trans, 2, nrnmpi_myid + 1, 1);
105  }
106  if (transfer_p_[im]) {
107  nrnmpi_recv_doubles(trans_sav, 2, nrnmpi_myid - 1, 1);
108  // defer copying to the d and rhs variables since the
109  // old info needs to be transferred next
110  trans[0] = *transfer_p_[im + 0];
111  trans[1] = *transfer_p_[im + 1];
112  *transfer_p_[im + 0] += trans_sav[0];
113  *transfer_p_[im + 1] += trans_sav[1];
114  nrnmpi_send_doubles(trans, 2, nrnmpi_myid - 1, 1);
115  }
116  if (transfer_p_[ip]) {
117  nrnmpi_recv_doubles(trans, 2, nrnmpi_myid + 1, 1);
118  *transfer_p_[ip + 0] += trans[0];
119  *transfer_p_[ip + 1] += trans[1];
120  }
122  errno = 0;
123 }
124 
125 void set_structure() {
126  for (auto& sc: splitcell_list_) {
127  if (sc.that_host_ == nrnmpi_myid + 1) {
128  transfer_p_[ip + 0] = &NODED(sc.rootsec_->parentnode);
129  transfer_p_[ip + 1] = &NODERHS(sc.rootsec_->parentnode);
130  } else {
131  assert(sc.that_host_ == nrnmpi_myid - 1);
132  transfer_p_[im + 0] = &NODED(sc.rootsec_->parentnode);
133  transfer_p_[im + 1] = &NODERHS(sc.rootsec_->parentnode);
134  }
135  }
136 }
137 
138 #endif
const char * secname(Section *sec)
Definition: cabcode.cpp:1776
Section * chk_access(void)
Definition: cabcode.cpp:444
sprintf(buf, " if (secondorder) {\n" " int _i;\n" " for (_i = 0; _i < %d; ++_i) {\n" " _p[_slist%d[_i]] += dt*_p[_dlist%d[_i]];\n" " }}\n", numeqn, listnum, listnum)
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:754
char buf[512]
Definition: init.cpp:13
#define assert(ex)
Definition: hocassrt.h:32
void
int abs(int)
#define i
Definition: md1redef.h:12
static double nrnmpi_splitcell_wait_
Definition: multisplit.cpp:43
static double nrnmpi_wtime()
Definition: multisplit.cpp:55
static void nrnmpi_send_doubles(double *, int, int, int)
Definition: multisplit.cpp:52
int nrnmpi_myid
int nrnmpi_numprocs
#define NODERHS(n)
Definition: section.h:105
#define NODED(n)
Definition: section.h:104
void nrnmpi_splitcell_connect(int that_host)
Definition: splitcell.cpp:49
int structure_change_cnt
Definition: splitcell.cpp:20
#define cnt
Definition: spt2queue.cpp:19
struct Section * parentsec
Definition: section.h:42