1 | /* |
2 | * nn_processor.hpp |
3 | * |
4 | * Created on: Aug 9, 2015 |
5 | * Author: i-bird |
6 | */ |
7 | |
8 | #ifndef SRC_DECOMPOSITION_NN_PROCESSOR_HPP_ |
9 | #define SRC_DECOMPOSITION_NN_PROCESSOR_HPP_ |
10 | |
11 | #include "common.hpp" |
12 | #include <unordered_map> |
13 | |
14 | /*! \brief This class store the adjacent processors and the adjacent sub_domains |
15 | * |
16 | * \tparam dim is the dimensionality of the physical domain we are going to decompose. |
17 | * \tparam T type of the space we decompose, Real, Integer, Complex ... |
18 | * |
19 | * \see CartDecomposition |
20 | * |
21 | */ |
22 | template<unsigned int dim, typename T, template <typename> class layout_base, typename Memory> |
23 | class nn_prcs |
24 | { |
25 | //! Virtual cluster |
26 | Vcluster<> & v_cl; |
27 | |
28 | //! List of adjacent processors |
29 | openfpm::vector<size_t> nn_processors; |
30 | |
31 | //! for each near processor store the sub-domains of the near processors |
32 | std::unordered_map<size_t, N_box<dim,T>> nn_processor_subdomains; |
33 | |
34 | //! when we add new boxes, are added here |
35 | std::unordered_map<size_t, N_box<dim,T>> nn_processor_subdomains_tmp; |
36 | |
37 | //! contain the same information as the member boxes with the difference that |
38 | //! instead of the Box itself, it contain the sub-domain id in the list of the |
39 | //! local sub-domains |
40 | openfpm::vector<openfpm::vector<size_t>> proc_adj_box; |
41 | |
42 | //! contain the set of sub-domains sent to the other processors |
43 | openfpm::vector< openfpm::vector< ::SpaceBox<dim,T>> > boxes; |
44 | |
45 | //! Receive counter |
46 | size_t recv_cnt; |
47 | |
48 | //! applyBC function is suppose to be called only one time |
49 | bool aBC; |
50 | |
51 | /*! \brief It shift a box but it does consistently |
52 | * |
53 | * In calculating internal and external ghost boxes, domains are shifted by periodicity. |
54 | * In particular, consider a box touching with the left bolder the left border of the domain |
55 | * |
56 | |
57 | before shift after shift |
58 | |
59 | +-----------------------------+ +------------------------------+ |
60 | | | | | |
61 | | domain | | domain | |
62 | | | | | |
63 | | | | | |
64 | +---------+ | | +---------+ |
65 | | | | | | | |
66 | | | | | | | |
67 | | box | | | | box | |
68 | | | | | | | |
69 | | | | | | | |
70 | +---------+ | | +---------+ |
71 | | | | | |
72 | | | | | |
73 | | | | | |
74 | | | | | |
75 | | | | | |
76 | +-----------------------------+ +------------------------------+ |
77 | |
78 | * |
79 | * |
80 | * |
81 | * |
82 | * |
83 | * shifting the box on the right by the size of the domain, we expect to have a box touching with |
84 | * the left side the right side of the domain. Because of rounding off problem this is not possible |
85 | * with a simple shift. This function ensure consistency like ensuring the previous condition, with |
86 | * the assumption that the shift is +/- the domain size |
87 | * |
88 | * \param box to shift |
89 | * \param domain |
90 | * \param shift |
91 | * |
92 | */ |
93 | inline void consistent_shift(Box<dim,T> & box, const Box<dim,T> & domain, const Point<dim,T> & shift) |
94 | { |
95 | for (size_t k = 0 ; k < dim ; k++) |
96 | { |
97 | // if it touch on the left and shift on the right |
98 | if (box.getLow(k) == domain.getLow(k) && shift.get(k) > 0) |
99 | { |
100 | box.setLow(k,domain.getHigh(k)); |
101 | box.setHigh(k,box.getHigh(k) + shift.get(k)); |
102 | } |
103 | else if (box.getLow(k) == domain.getHigh(k) && shift.get(k) < 0) |
104 | { |
105 | box.setLow(k,domain.getLow(k)); |
106 | box.setHigh(k,box.getHigh(k) + shift.get(k)); |
107 | } |
108 | else if (box.getHigh(k) == domain.getHigh(k) && shift.get(k) < 0) |
109 | { |
110 | box.setHigh(k,domain.getLow(k)); |
111 | box.setLow(k,box.getLow(k) + shift.get(k)); |
112 | } |
113 | else if (box.getHigh(k) == domain.getLow(k) && shift.get(k) > 0) |
114 | { |
115 | box.setHigh(k,domain.getHigh(k)); |
116 | box.setLow(k,box.getLow(k) + shift.get(k)); |
117 | } |
118 | else |
119 | { |
120 | box.setHigh(k,box.getHigh(k) + shift.get(k)); |
121 | box.setLow(k,box.getLow(k) + shift.get(k)); |
122 | } |
123 | } |
124 | } |
125 | |
126 | /*! \brief Message allocation |
127 | * |
128 | * \param msg_i message size required to receive from i |
129 | * \param total_msg total message size to receive from all the processors |
130 | * \param total_p the total number of processor want to communicate with you |
131 | * \param i processor id from which we receive |
132 | * \param ri request id (it is an id that goes from 0 to total_p, and is unique |
133 | * every time message_alloc is called) |
134 | * \param ptr a pointer to the vector_dist structure |
135 | * |
136 | * \return the pointer where to store the message |
137 | * |
138 | */ |
139 | static void * message_alloc(size_t msg_i ,size_t total_msg, size_t total_p, size_t i, size_t ri, size_t tag, void * ptr) |
140 | { |
141 | // cast the pointer |
142 | nn_prcs<dim,T,layout_base,Memory> * cd = static_cast< nn_prcs<dim,T,layout_base,Memory> *>(ptr); |
143 | |
144 | cd->nn_processor_subdomains[i].bx.resize(msg_i / sizeof(::Box<dim,T>) ); |
145 | |
146 | // Return the receive pointer |
147 | return cd->nn_processor_subdomains[i].bx.getPointer(); |
148 | } |
149 | |
150 | /*! \brief add sub-domains to processor for a near processor i |
151 | * |
152 | * \param i near processor |
153 | * \param r_sub real sub-domain id |
154 | * \param bx Box to add |
155 | * \param c from which sector the sub-domain come from |
156 | * |
157 | */ |
158 | inline void add_nn_subdomain(size_t i, size_t r_sub, const Box<dim,T> & bx, const comb<dim> & c) |
159 | { |
160 | N_box<dim,T> & nnpst = nn_processor_subdomains_tmp[i]; |
161 | nnpst.bx.add(bx); |
162 | nnpst.pos.add(c); |
163 | nnpst.r_sub.add(r_sub); |
164 | } |
165 | |
166 | /*! \brief In case of periodic boundary conditions we replicate the sub-domains at the border |
167 | * |
168 | * \param domain Domain |
169 | * \param ghost ghost part |
170 | * \param bc boundary boundary conditions |
171 | * |
172 | */ |
173 | void add_box_periodic(const Box<dim,T> & domain, const Ghost<dim,T> & ghost, const size_t (&bc)[dim]) |
174 | { |
175 | HyperCube<dim> hyp; |
176 | |
177 | // first we create boxes at the border of the domain used to detect the sub-domain |
178 | // that must be adjusted, each of this boxes define a shift in case of periodic boundary condition |
179 | for (long int i = dim-1 ; i >= 0 ; i--) |
180 | { |
181 | std::vector<comb<dim>> cmbs = hyp.getCombinations_R_bc(i,bc); |
182 | |
183 | for (size_t j = 0 ; j < cmbs.size() ; j++) |
184 | { |
185 | if (check_valid(cmbs[j],bc) == false) |
186 | continue; |
187 | |
188 | // Calculate the sector box |
189 | Box<dim,T> bp; |
190 | Point<dim,T> shift; |
191 | |
192 | for (size_t k = 0 ; k < dim ; k++) |
193 | { |
194 | switch (cmbs[j][k]) |
195 | { |
196 | case 1: |
197 | bp.setLow(k,domain.getHigh(k)+ghost.getLow(k)); |
198 | bp.setHigh(k,domain.getHigh(k)); |
199 | shift.get(k) = -domain.getHigh(k)+domain.getLow(k); |
200 | break; |
201 | case 0: |
202 | bp.setLow(k,domain.getLow(k)); |
203 | bp.setHigh(k,domain.getHigh(k)); |
204 | shift.get(k) = 0; |
205 | break; |
206 | case -1: |
207 | bp.setLow(k,domain.getLow(k)); |
208 | bp.setHigh(k,domain.getLow(k)+ghost.getHigh(k)); |
209 | shift.get(k) = domain.getHigh(k)-domain.getLow(k); |
210 | break; |
211 | } |
212 | } |
213 | |
214 | // Detect all the sub-domain involved, shift them and add to the list |
215 | // Detection is performed intersecting the sub-domains with the ghost |
216 | // parts near the domain borders |
217 | for (size_t k = 0 ; k < getNNProcessors() ; k++) |
218 | { |
219 | // sub-domains of the near processor |
220 | const openfpm::vector< ::Box<dim,T> > & nn_sub = getNearSubdomains(IDtoProc(k)); |
221 | |
222 | for (size_t l = 0 ; l < nn_sub.size(); l++) |
223 | { |
224 | Box<dim,T> sub = nn_sub.get(l); |
225 | Box<dim,T> b_int; |
226 | |
227 | if (sub.Intersect(bp,b_int) == true) |
228 | { |
229 | Box<dim,T> sub2 = sub; |
230 | sub2 += shift; |
231 | |
232 | // Here we have to be careful of rounding off problems, in particular if any part |
233 | // of the sub-domain touch the border of the domain |
234 | |
235 | consistent_shift(sub,domain,shift); |
236 | |
237 | add_nn_subdomain(IDtoProc(k),l,sub,cmbs[j]); |
238 | } |
239 | } |
240 | } |
241 | } |
242 | } |
243 | |
244 | flush(); |
245 | } |
246 | |
247 | /*! \brief Flush the temporal added sub-domain to the processor sub-domain |
248 | * |
249 | * |
250 | */ |
251 | void flush() |
252 | { |
253 | for ( auto it = nn_processor_subdomains_tmp.begin(); it != nn_processor_subdomains_tmp.end(); ++it ) |
254 | { |
255 | const N_box<dim,T> & nnp_bx = it->second; |
256 | |
257 | for (size_t i = 0 ; i < nnp_bx.bx.size() ; i++) |
258 | { |
259 | N_box<dim,T> & nnps = nn_processor_subdomains[it->first]; |
260 | const N_box<dim,T> & nnps_tmp = nn_processor_subdomains_tmp[it->first]; |
261 | |
262 | nnps.bx.add(nnps_tmp.bx.get(i)); |
263 | nnps.pos.add(nnps_tmp.pos.get(i)); |
264 | nnps.r_sub.add(nnps_tmp.r_sub.get(i)); |
265 | } |
266 | } |
267 | |
268 | nn_processor_subdomains_tmp.clear(); |
269 | } |
270 | |
271 | public: |
272 | |
273 | //! Constructor require Vcluster |
274 | nn_prcs(Vcluster<> & v_cl) |
275 | :v_cl(v_cl),recv_cnt(0),aBC(false) |
276 | {} |
277 | |
278 | //! Constructor from another nn_prcs |
279 | nn_prcs(const nn_prcs<dim,T,layout_base,Memory> & ilg) |
280 | :v_cl(ilg.v_cl),recv_cnt(0),aBC(false) |
281 | { |
282 | this->operator=(ilg); |
283 | }; |
284 | |
285 | //! Constructor from temporal ie_loc_ghost |
286 | nn_prcs(nn_prcs<dim,T,layout_base,Memory> && ilg) |
287 | :v_cl(ilg.v_cl),recv_cnt(0),aBC(false) |
288 | { |
289 | this->operator=(ilg); |
290 | } |
291 | |
292 | /*! Check that the combination is valid |
293 | * |
294 | * Is a function that is used in otder to understand if a sub-domain |
295 | * must be mirrored because of boundary conditions |
296 | * |
297 | * \param cmb combination |
298 | * \param bc boundary conditions |
299 | * |
300 | * \return true if the combination is valid |
301 | * |
302 | */ |
303 | static bool inline check_valid(comb<dim> cmb,const size_t (& bc)[dim]) |
304 | { |
305 | // the combination 0 is not valid |
306 | if (cmb.n_zero() == dim) |
307 | return false; |
308 | |
309 | for (size_t i = 0 ; i < dim ; i++) |
310 | { |
311 | if (bc[i] == NON_PERIODIC && cmb.getComb()[i] != 0) |
312 | return false; |
313 | } |
314 | return true; |
315 | } |
316 | |
317 | /*! \brief Copy the object |
318 | * |
319 | * \param nnp object to copy |
320 | * |
321 | * \return itself |
322 | * |
323 | */ |
324 | nn_prcs<dim,T,layout_base,Memory> & operator=(const nn_prcs<dim,T,layout_base,Memory> & nnp) |
325 | { |
326 | nn_processors = nnp.nn_processors; |
327 | nn_processor_subdomains = nnp.nn_processor_subdomains; |
328 | proc_adj_box = nnp.proc_adj_box; |
329 | boxes = nnp.boxes; |
330 | |
331 | return *this; |
332 | } |
333 | |
334 | /*! \brief Copy the object |
335 | * |
336 | * \param nnp object to copy |
337 | * |
338 | * \return itself |
339 | * |
340 | */ |
341 | nn_prcs<dim,T,layout_base,Memory> & operator=(nn_prcs<dim,T,layout_base,Memory> && nnp) |
342 | { |
343 | nn_processors.swap(nnp.nn_processors); |
344 | nn_processor_subdomains.swap(nnp.nn_processor_subdomains); |
345 | proc_adj_box.swap(nnp.proc_adj_box); |
346 | boxes = nnp.boxes; |
347 | |
348 | return *this; |
349 | } |
350 | |
351 | /*! \brief Copy the object |
352 | * |
353 | * \param nnp object to copy |
354 | * |
355 | * \return itself |
356 | * |
357 | */ |
358 | template<typename Memory2, template <typename> class layout_base2> |
359 | nn_prcs<dim,T,layout_base,Memory> & operator=(const nn_prcs<dim,T,layout_base2,Memory2> & nnp) |
360 | { |
361 | nn_processors = nnp.private_get_nn_processors(); |
362 | nn_processor_subdomains = nnp.private_get_nn_processor_subdomains(); |
363 | proc_adj_box = nnp.private_get_proc_adj_box(); |
364 | boxes = nnp.private_get_boxes(); |
365 | |
366 | return *this; |
367 | } |
368 | |
369 | /*! \brief Return the internal nn_processor struct |
370 | * |
371 | * \return the internal nn_processor struct |
372 | * |
373 | */ |
374 | openfpm::vector<size_t> & private_get_nn_processors() |
375 | { |
376 | return nn_processors; |
377 | } |
378 | |
379 | /*! \brief Return the internal nn_processor_subdomains |
380 | * |
381 | * \return the internal nn_processor_subdomains |
382 | * |
383 | */ |
384 | std::unordered_map<size_t, N_box<dim,T>> & private_get_nn_processor_subdomains() |
385 | { |
386 | return nn_processor_subdomains; |
387 | } |
388 | |
389 | /*! \brief Return the internal proc_adj_box |
390 | * |
391 | * \return the internal proc_adj_box |
392 | * |
393 | */ |
394 | openfpm::vector<openfpm::vector<size_t>> & private_get_proc_adj_box() |
395 | { |
396 | return proc_adj_box; |
397 | } |
398 | |
399 | /*! \brief Return the internal boxes structure |
400 | * |
401 | * \return the internal boxes structure |
402 | * |
403 | */ |
404 | openfpm::vector< openfpm::vector< ::SpaceBox<dim,T>> > & private_get_boxes() |
405 | { |
406 | return boxes; |
407 | } |
408 | |
409 | /*! \brief Copy the object |
410 | * |
411 | * \param nnp object to copy |
412 | * |
413 | * \return itself |
414 | * |
415 | */ |
416 | template<typename Memory2, template <typename> class layout_base2> |
417 | nn_prcs<dim,T,layout_base,Memory> & operator=(nn_prcs<dim,T,layout_base2,Memory2> && nnp) |
418 | { |
419 | nn_processors.swap(nnp.private_get_nn_processors()); |
420 | nn_processor_subdomains.swap(nnp.private_get_nn_processor_subdomains()); |
421 | proc_adj_box.swap(nnp.private_get_proc_adj_box()); |
422 | boxes = nnp.private_get_boxes(); |
423 | |
424 | return *this; |
425 | } |
426 | |
427 | /*! \brief Create the list of adjacent processors and the list of adjacent sub-domains |
428 | * |
429 | * \param box_nn_processor list of adjacent processors for each sub-domain |
430 | * \param sub_domains list of local sub-domains |
431 | * |
432 | */ |
433 | void create(const openfpm::vector<openfpm::vector<long unsigned int> > & box_nn_processor, |
434 | const openfpm::vector<SpaceBox<dim,T>,Memory,layout_base> & sub_domains) |
435 | { |
436 | // produce the list of the adjacent processor (nn_processors) list |
437 | for (size_t i = 0 ; i < box_nn_processor.size() ; i++) |
438 | { |
439 | for (size_t j = 0 ; j < box_nn_processor.get(i).size() ; j++) |
440 | { |
441 | nn_processors.add(box_nn_processor.get(i).get(j)); |
442 | } |
443 | } |
444 | |
445 | // make the list of the processor sort and unique |
446 | std::sort(nn_processors.begin(), nn_processors.end()); |
447 | auto last = std::unique(nn_processors.begin(), nn_processors.end()); |
448 | nn_processors.erase(last, nn_processors.end()); |
449 | |
450 | // link nn_processor_subdomains to nn_processors |
451 | // it is used to quickly convert the Processor rank to the position in the list of the |
452 | // near processors |
453 | for (size_t i = 0 ; i < box_nn_processor.size() ; i++) |
454 | { |
455 | for (size_t j = 0 ; j < box_nn_processor.get(i).size() ; j++) |
456 | { |
457 | // processor id adjacent to this sub-domain |
458 | size_t proc_id = box_nn_processor.get(i).get(j); |
459 | |
460 | size_t k = 0; |
461 | // search inside near processor list |
462 | for (k = 0 ; k < nn_processors.size() ; k++) |
463 | if (nn_processors.get(k) == proc_id) break; |
464 | |
465 | nn_processor_subdomains[proc_id].id = k; |
466 | } |
467 | } |
468 | |
469 | // create a buffer with the sub-domains that can have an intersection with |
470 | // the near processors |
471 | proc_adj_box.resize(getNNProcessors()); |
472 | boxes.resize(getNNProcessors()); |
473 | |
474 | for (size_t b = 0 ; b < box_nn_processor.size() ; b++) |
475 | { |
476 | for (size_t p = 0 ; p < box_nn_processor.get(b).size() ; p++) |
477 | { |
478 | size_t prc = box_nn_processor.get(b).get(p); |
479 | |
480 | // id of the processor in the processor list |
481 | // [value between 0 and the number of the near processors] |
482 | size_t id = ProctoID(prc); |
483 | |
484 | boxes.get(id).add(sub_domains.get(b)); |
485 | proc_adj_box.get(id).add(b); |
486 | } |
487 | } |
488 | |
489 | nn_processor_subdomains.reserve(nn_processors.size()); |
490 | |
491 | // Get the sub-domains of the near processors |
492 | v_cl.sendrecvMultipleMessagesNBX(nn_processors,boxes,nn_prcs<dim,T,layout_base,Memory>::message_alloc, this ,NEED_ALL_SIZE); |
493 | |
494 | // Add to all the received sub-domains the information that they live in the central sector |
495 | for ( auto it = nn_processor_subdomains.begin(); it != nn_processor_subdomains.end(); ++it ) |
496 | { |
497 | const N_box<dim,T> & nnp_bx = it->second; |
498 | |
499 | for (size_t i = 0 ; i < nnp_bx.bx.size() ; i++) |
500 | { |
501 | comb<dim> c; |
502 | c.zero(); |
503 | |
504 | N_box<dim,T> & nnps = nn_processor_subdomains[it->first]; |
505 | |
506 | nnps.pos.add(c); |
507 | nnps.r_sub.add(i); |
508 | nnps.n_real_sub = nnps.bx.size(); |
509 | } |
510 | } |
511 | } |
512 | |
513 | /*! \brief Get the number of Near processors |
514 | * |
515 | * \return the number of near processors |
516 | * |
517 | */ |
518 | inline size_t getNNProcessors() const |
519 | { |
520 | return nn_processors.size(); |
521 | } |
522 | |
523 | /*! \brief Return the processor id of the near processor list at place id |
524 | * |
525 | * \param id |
526 | * |
527 | * \return return the processor rank |
528 | * |
529 | */ |
530 | inline size_t IDtoProc(size_t id) const |
531 | { |
532 | return nn_processors.get(id); |
533 | } |
534 | |
535 | /*! \brief Get the real-id of the sub-domains of a near processor |
536 | * |
537 | * \param p_id near processor rank |
538 | * |
539 | * \return the sub-domains real id |
540 | * |
541 | */ |
542 | inline const openfpm::vector< size_t > & getNearSubdomainsRealId(size_t p_id) const |
543 | { |
544 | auto key = nn_processor_subdomains.find(p_id); |
545 | #ifdef SE_CLASS1 |
546 | if (key == nn_processor_subdomains.end()) |
547 | { |
548 | std::cerr << "Error " << __FILE__ << ":" << __LINE__ << " error this process rank is not adjacent to the local processor" ; |
549 | } |
550 | #endif |
551 | |
552 | return key->second.r_sub; |
553 | } |
554 | |
555 | /*! \brief Get the sub-domains of a near processor |
556 | * |
557 | * \param p_id near processor rank |
558 | * |
559 | * \return the sub-domains |
560 | * |
561 | */ |
562 | inline const openfpm::vector< ::Box<dim,T> > & getNearSubdomains(size_t p_id) const |
563 | { |
564 | auto key = nn_processor_subdomains.find(p_id); |
565 | #ifdef SE_CLASS1 |
566 | if (key == nn_processor_subdomains.end()) |
567 | { |
568 | std::cerr << "Error " << __FILE__ << ":" << __LINE__ << " error this process rank is not adjacent to the local processor" ; |
569 | } |
570 | #endif |
571 | |
572 | return key->second.bx; |
573 | } |
574 | |
575 | /*! \brief Get the number of real sub-domains of a near processor |
576 | * |
577 | * \note the real sub-domain are the subdomain in the central sector, or any sub-domain that has not been create because of boundary conditions |
578 | * |
579 | * \param p_id near processor rank |
580 | * |
581 | * \return the number of real sub-domains |
582 | * |
583 | */ |
584 | inline size_t getNRealSubdomains(size_t p_id) const |
585 | { |
586 | auto key = nn_processor_subdomains.find(p_id); |
587 | #ifdef SE_CLASS1 |
588 | if (key == nn_processor_subdomains.end()) |
589 | { |
590 | std::cerr << "Error " << __FILE__ << ":" << __LINE__ << " error this process rank is not adjacent to the local processor" ; |
591 | } |
592 | #endif |
593 | |
594 | return key->second.n_real_sub; |
595 | } |
596 | |
597 | /*! \brief Get the sub-domains sector position of a near processor |
598 | * |
599 | * \param p_id near processor rank |
600 | * |
601 | * \return the sub-domains positions |
602 | * |
603 | */ |
604 | inline const openfpm::vector< comb<dim> > & getNearSubdomainsPos(size_t p_id) const |
605 | { |
606 | auto key = nn_processor_subdomains.find(p_id); |
607 | #ifdef SE_CLASS1 |
608 | if (key == nn_processor_subdomains.end()) |
609 | { |
610 | std::cerr << "Error " << __FILE__ << ":" << __LINE__ << " error this process rank is not adjacent to the local processor" ; |
611 | } |
612 | #endif |
613 | return key->second.pos; |
614 | } |
615 | |
616 | /*! \brief Get the near processor id |
617 | * |
618 | * \param p_id adjacent processor rank |
619 | * |
620 | * \return the processor rank |
621 | * |
622 | */ |
623 | inline size_t getNearProcessor(size_t p_id) const |
624 | { |
625 | auto key = nn_processor_subdomains.find(p_id); |
626 | #ifdef SE_CLASS1 |
627 | if (key == nn_processor_subdomains.end()) |
628 | { |
629 | std::cerr << "Error " << __FILE__ << ":" << __LINE__ << " error this process rank is not adjacent to the local processor" ; |
630 | } |
631 | #endif |
632 | return key->second.id; |
633 | } |
634 | |
635 | |
636 | /*! \brief For each near processor it give a vector with the id |
637 | * of the local sub-domain sent to that processor |
638 | * |
639 | * \param p_id adjacent processor (id from 0 to getNNProcessors()) |
640 | * |
641 | * \return a vector of sub-domains id |
642 | * |
643 | */ |
644 | inline const openfpm::vector<size_t> & getSentSubdomains(size_t p_id) const |
645 | { |
646 | return proc_adj_box.get(p_id); |
647 | } |
648 | |
649 | /*! \brief Convert the processor rank to the id in the list |
650 | * |
651 | * \param p processor rank |
652 | * |
653 | * \return the id |
654 | * |
655 | */ |
656 | inline size_t ProctoID(size_t p) const |
657 | { |
658 | auto key = nn_processor_subdomains.find(p); |
659 | #ifdef SE_CLASS1 |
660 | if (key == nn_processor_subdomains.end()) |
661 | { |
662 | std::cerr << "Error " << __FILE__ << ":" << __LINE__ << " error this process rank is not adjacent to the local processor" ; |
663 | } |
664 | #endif |
665 | |
666 | return key->second.id; |
667 | } |
668 | |
669 | /*! \brief Write the decomposition as VTK file |
670 | * |
671 | * The function generate several files |
672 | * |
673 | * 1) subdomains_adjacent_X.vtk sub-domains adjacent to the local processor (X) |
674 | * |
675 | * where X is the local processor rank |
676 | * |
677 | * \param output directory where to write the files |
678 | * |
679 | * \return true if the write procedure succeed |
680 | * |
681 | */ |
682 | bool write(std::string output) const |
683 | { |
684 | //! subdomains_adjacent_X.vtk sub-domains adjacent to the local processor (X) |
685 | VTKWriter<openfpm::vector<::Box<dim,T>>,VECTOR_BOX> vtk_box2; |
686 | for (size_t p = 0 ; p < nn_processors.size() ; p++) |
687 | { |
688 | size_t prc = nn_processors.get(p); |
689 | auto it = nn_processor_subdomains.find(prc); |
690 | if (it != nn_processor_subdomains.end()) |
691 | vtk_box2.add(nn_processor_subdomains.at(prc).bx); |
692 | } |
693 | vtk_box2.write(output + std::string("subdomains_adjacent_" ) + std::to_string(v_cl.getProcessUnitID()) + std::string(".vtk" )); |
694 | |
695 | return true; |
696 | } |
697 | |
698 | /*! \brief Apply boundary conditions |
699 | * |
700 | * \param domain The simulation domain |
701 | * \param ghost ghost part |
702 | * \param bc Boundary conditions |
703 | * |
704 | */ |
705 | void applyBC(const Box<dim,T> & domain, const Ghost<dim,T> & ghost, const size_t (&bc)[dim]) |
706 | { |
707 | if (aBC == true) |
708 | { |
709 | std::cerr << "Warning " << __FILE__ << ":" << __LINE__ << " apply BC is suppose to be called only one time\n" ; |
710 | return; |
711 | } |
712 | |
713 | aBC=true; |
714 | |
715 | add_box_periodic(domain,ghost,bc); |
716 | } |
717 | |
718 | /*! \brief Check if the nn_prcs contain the same information |
719 | * |
720 | * \param np Element to check |
721 | * |
722 | * \return true if they are equal |
723 | * |
724 | */ |
725 | bool is_equal(nn_prcs<dim,T,layout_base,Memory> & np) |
726 | { |
727 | if (np.getNNProcessors() != getNNProcessors()) |
728 | return false; |
729 | |
730 | for (size_t p = 0 ; p < getNNProcessors() ; p++) |
731 | { |
732 | if (getNearSubdomains(IDtoProc(p)) != np.getNearSubdomains(IDtoProc(p))) |
733 | return false; |
734 | if (getNearProcessor(IDtoProc(p)) != np.getNearProcessor(IDtoProc(p))) |
735 | return false; |
736 | if (getSentSubdomains(p) != np.getSentSubdomains(p)) |
737 | return false; |
738 | } |
739 | |
740 | return true; |
741 | } |
742 | |
743 | /*! \brief Reset the nn_prcs structure |
744 | * |
745 | */ |
746 | void reset() |
747 | { |
748 | nn_processors.clear(); |
749 | nn_processor_subdomains.clear(); |
750 | nn_processor_subdomains_tmp.clear(); |
751 | proc_adj_box.clear(); |
752 | boxes.clear(); |
753 | recv_cnt = 0; |
754 | aBC = false; |
755 | } |
756 | |
757 | //! Used for testing porpose do not use |
758 | std::unordered_map<size_t, N_box<dim,T>> & get_nn_processor_subdomains() |
759 | { |
760 | return nn_processor_subdomains; |
761 | } |
762 | |
763 | //! Used for testing porpose do not use |
764 | openfpm::vector<size_t> & get_nn_processors() |
765 | { |
766 | return nn_processors; |
767 | } |
768 | }; |
769 | |
770 | |
771 | #endif /* SRC_DECOMPOSITION_NN_PROCESSOR_HPP_ */ |
772 | |