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