multi_domain.cc
Go to the documentation of this file.
1// LIC// ====================================================================
2// LIC// This file forms part of oomph-lib, the object-oriented,
3// LIC// multi-physics finite-element library, available
4// LIC// at http://www.oomph-lib.org.
5// LIC//
6// LIC// Copyright (C) 2006-2022 Matthias Heil and Andrew Hazel
7// LIC//
8// LIC// This library is free software; you can redistribute it and/or
9// LIC// modify it under the terms of the GNU Lesser General Public
10// LIC// License as published by the Free Software Foundation; either
11// LIC// version 2.1 of the License, or (at your option) any later version.
12// LIC//
13// LIC// This library is distributed in the hope that it will be useful,
14// LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// LIC// Lesser General Public License for more details.
17// LIC//
18// LIC// You should have received a copy of the GNU Lesser General Public
19// LIC// License along with this library; if not, write to the Free Software
20// LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21// LIC// 02110-1301 USA.
22// LIC//
23// LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24// LIC//
25// LIC//====================================================================
26// Non-templated multi-domain functions which act on more than one mesh
27// and set up the storage and interaction between the two
28
29// oomph-lib header
30#include "multi_domain.h"
32#include "mesh.h"
33#include "algebraic_elements.h"
35#include "Qelements.h"
36
37namespace oomph
38{
39 //======================================================================
40 // Namespace for "global" multi-domain functions
41 //======================================================================
42 namespace Multi_domain_functions
43 {
44 /// Output file to document the boundary coordinate
45 /// along the mesh boundary of the bulk mesh during call to
46 /// setup_bulk_elements_adjacent_to_face_mesh(...)
48
49 // Workspace for locate zeta methods
50 //----------------------------------
51
52 /// Boolean to indicate that failure in setup multi domain
53 /// functions is acceptable; defaults to false. If set to true
54 /// external element pointers are set to null for those elements
55 /// for which external elements couldn't be located.
57
58 /// Dimension of zeta tuples (set by get_dim_helper) -- needed
59 /// because we store the scalar coordinates in flat-packed form.
60 unsigned Dim;
61
62 /// Lookup scheme for whether a local element's integration point
63 /// has had an external element assigned to it -- essentially boolean.
64 /// External_element_located[e][ipt] = {0,1} if external element
65 /// for ipt-th integration in local element e {has not, has} been found.
66 /// Used locally to ensure that we're not searching for the same
67 /// elements over and over again when we go around the spirals.
69
70 /// Vector of flat-packed zeta coordinates for which the external
71 /// element could not be found during current local search. These
72 /// will be sent to the next processor in the ring-like parallel search.
73 /// The zeta coordinates come in groups of Dim (scalar) coordinates.
75
76 /// Vector of flat-packed zeta coordinates for which the external
77 /// element could not be found on another processor and for which
78 /// we're currently searching here. Whatever can't be found here,
79 /// gets written into Flat_packed_zetas_not_found_locally and then
80 /// passed on to the next processor during the ring-like parallel search.
81 /// The zeta coordinates come in groups of Dim (scalar) coordinates.
83
84 /// Proc_id_plus_one_of_external_element[i] contains the
85 /// processor id (plus one) of the processor
86 /// on which the i-th zeta coordinate tuple received from elsewhere
87 /// (in the order in which these are stored in
88 /// Received_flat_packed_zetas_to_be_found) was located; it's zero if
89 /// it wasn't found during the current stage of the ring-like parallel
90 /// search.
92
93 /// Vector to indicate (to another processor) whether a
94 /// located element (that will have to represented as an external
95 /// halo element on that processor) should be newly created on that
96 /// processor (2), already exists on that processor (1), or
97 /// is not on the current processor either (0).
99
100 /// Vector of flat-packed local coordinates for zeta tuples
101 /// that have been located
103
104 /// Vector of flat-packed doubles to be communicated with
105 /// other processors
107
108 /// Counter used when processing vector of flat-packed
109 /// doubles -- this is really "private" data, declared here
110 /// to avoid having to pass it (and the associated array)
111 /// between the various helper functions
113
114 /// Vector of flat-packed unsigneds to be communicated with
115 /// other processors -- this is really "private" data, declared here
116 /// to avoid having to pass the array between the various helper
117 /// functions
119
120#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
121
122 // Temporary vector of strings to enable full annotation of multi domain
123 // comms (but keep alive because it would be such a bloody pain to
124 // rewrite it if things ever go wrong again...)
126
127
128#endif
129
130 /// Counter used when processing vector of flat-packed
131 /// unsigneds -- this is really "private" data, declared here
132 /// to avoid having to pass it (and the associated array)
133 /// between the various helper functions
135
136 // Other parameters
137 //-----------------
138
139 /// Boolean to indicate when to use the bulk element as the
140 /// external element. Defaults to false, you must have set up FaceElements
141 /// properly first in order for it to work
143
144 /// Boolean to indicate if we're allowed to use halo elements
145 /// as external elements. Can drastically reduce the number of
146 /// external halo elements -- currently not aware of any problems
147 /// therefore set to true by default but retention
148 /// of this flag allows easy return to previous implementation.
150
151 /// Indicate whether we are allowed to use halo elements as
152 /// external elements for projection, possibly only required in
153 /// parallel unstructured mesh generation during the projection
154 /// stage. Default set to true
156
157 /// Boolean to indicate whether to doc timings or not.
158 bool Doc_timings = false;
159
160 /// Boolean to indicate whether to output basic info during
161 /// setup_multi_domain_interaction() routines
162 bool Doc_stats = false;
163
164 /// Boolean to indicate whether to output further info during
165 /// setup_multi_domain_interaction() routines
166 bool Doc_full_stats = false;
167
168#ifdef OOMPH_HAS_MPI
169
170 // Functions for location method in multi-domain problems
171
172
173 //========================================================================
174 /// Send the zeta coordinates from the current process to
175 /// the next process; receive from the previous process
176 //========================================================================
178 {
179 // MPI info
180 MPI_Status status;
181 MPI_Request request;
182
183 // Storage for number of processors, current process and communicator
184 int n_proc = problem_pt->communicator_pt()->nproc();
185 int my_rank = problem_pt->communicator_pt()->my_rank();
186 OomphCommunicator* comm_pt = problem_pt->communicator_pt();
187
188 // Work out processors to send and receive from
189 int send_to_proc = my_rank + 1;
190 int recv_from_proc = my_rank - 1;
191 if (send_to_proc == n_proc)
192 {
193 send_to_proc = 0;
194 }
195 if (recv_from_proc < 0)
196 {
197 recv_from_proc = n_proc - 1;
198 }
199
200 // Send the number of flat-packed zetas that we couldn't find
201 // locally to the next processor
202 int n_missing_local_zetas = Flat_packed_zetas_not_found_locally.size();
203 MPI_Isend(&n_missing_local_zetas,
204 1,
205 MPI_INT,
206 send_to_proc,
207 4,
208 comm_pt->mpi_comm(),
209 &request);
210
211 // Receive the number of flat-packed zetas that couldn't be found
212 // on the "previous" processor
213 int count_zetas = 0;
214 MPI_Recv(&count_zetas,
215 1,
216 MPI_INT,
217 recv_from_proc,
218 4,
219 comm_pt->mpi_comm(),
220 &status);
221
222 MPI_Wait(&request, MPI_STATUS_IGNORE);
223
224 // Send the vector of flat-packed zetas that we couldn't find
225 // locally to the next processor
226 if (n_missing_local_zetas != 0)
227 {
229 n_missing_local_zetas,
230 MPI_DOUBLE,
231 send_to_proc,
232 5,
233 comm_pt->mpi_comm(),
234 &request);
235 }
236
237 // Receive the vector of flat-packed zetas that couldn't be found
238 // on the "previous" processor
239 if (count_zetas != 0)
240 {
241 Received_flat_packed_zetas_to_be_found.resize(count_zetas);
243 count_zetas,
244 MPI_DOUBLE,
245 recv_from_proc,
246 5,
247 comm_pt->mpi_comm(),
248 &status);
249 MPI_Wait(&request, MPI_STATUS_IGNORE);
250 }
251 else
252 {
254 }
255
256 // Now we should have the Zeta arrays set up correctly
257 // for the next round of locations
258 }
259
260 //========start of send_and_receive_located_info==========================
261 /// Send location information from current process; Received location
262 /// information from (current process + iproc) modulo (nproc)
263 //========================================================================
265 Mesh* const& external_mesh_pt,
266 Problem* problem_pt)
267 {
268 // Set MPI info
269 MPI_Status status;
270 MPI_Request request;
271
272 // Storage for number of processors, current process and communicator
273 OomphCommunicator* comm_pt = problem_pt->communicator_pt();
274 int n_proc = comm_pt->nproc();
275 int my_rank = comm_pt->my_rank();
276
277 // Prepare vectors to receive information
278 Vector<double> received_double_values;
279 Vector<unsigned> received_unsigned_values;
280 Vector<double> received_located_coord;
281 Vector<int> received_proc_id_plus_one_of_external_element;
282 Vector<unsigned> received_located_element_status;
283
284 // Communicate the located information back to the original process
285 int orig_send_proc = my_rank - iproc;
286 if (my_rank < iproc)
287 {
288 orig_send_proc = n_proc + orig_send_proc;
289 }
290 int orig_recv_proc = my_rank + iproc;
291 if ((my_rank + iproc) >= n_proc)
292 {
293 orig_recv_proc = orig_recv_proc - n_proc;
294 }
295
296 // Send the double values associated with external halos
297 //------------------------------------------------------
298 unsigned send_count_double_values = Flat_packed_doubles.size();
299 MPI_Isend(&send_count_double_values,
300 1,
301 MPI_UNSIGNED,
302 orig_send_proc,
303 1,
304 comm_pt->mpi_comm(),
305 &request);
306 int receive_count_double_values = 0;
307 MPI_Recv(&receive_count_double_values,
308 1,
309 MPI_INT,
310 orig_recv_proc,
311 1,
312 comm_pt->mpi_comm(),
313 &status);
314 MPI_Wait(&request, MPI_STATUS_IGNORE);
315
316 if (send_count_double_values != 0)
317 {
318 MPI_Isend(&Flat_packed_doubles[0],
319 send_count_double_values,
320 MPI_DOUBLE,
321 orig_send_proc,
322 2,
323 comm_pt->mpi_comm(),
324 &request);
325 }
326 if (receive_count_double_values != 0)
327 {
328 received_double_values.resize(receive_count_double_values);
329 MPI_Recv(&received_double_values[0],
330 receive_count_double_values,
331 MPI_DOUBLE,
332 orig_recv_proc,
333 2,
334 comm_pt->mpi_comm(),
335 &status);
336 }
337 if (send_count_double_values != 0)
338 {
339 MPI_Wait(&request, MPI_STATUS_IGNORE);
340 }
341
342 // Now send unsigned values associated with external halos
343 //---------------------------------------------------------
344 unsigned send_count_unsigned_values = Flat_packed_unsigneds.size();
345 MPI_Isend(&send_count_unsigned_values,
346 1,
347 MPI_UNSIGNED,
348 orig_send_proc,
349 14,
350 comm_pt->mpi_comm(),
351 &request);
352
353 int receive_count_unsigned_values = 0;
354 MPI_Recv(&receive_count_unsigned_values,
355 1,
356 MPI_INT,
357 orig_recv_proc,
358 14,
359 comm_pt->mpi_comm(),
360 &status);
361
362 MPI_Wait(&request, MPI_STATUS_IGNORE);
363
364 if (send_count_unsigned_values != 0)
365 {
366 MPI_Isend(&Flat_packed_unsigneds[0],
367 send_count_unsigned_values,
368 MPI_UNSIGNED,
369 orig_send_proc,
370 15,
371 comm_pt->mpi_comm(),
372 &request);
373#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
374 for (unsigned i = 0; i < send_count_unsigned_values; i++)
375 {
376 oomph_info << "Sent:" << i << " to orig_proc:" << orig_send_proc
377 << " " << Flat_packed_unsigneds_string[i] << ": "
378 << Flat_packed_unsigneds[i] << std::endl;
379 }
380#endif
381 }
382 if (receive_count_unsigned_values != 0)
383 {
384 received_unsigned_values.resize(receive_count_unsigned_values);
385 MPI_Recv(&received_unsigned_values[0],
386 receive_count_unsigned_values,
387 MPI_UNSIGNED,
388 orig_recv_proc,
389 15,
390 comm_pt->mpi_comm(),
391 &status);
392 }
393
394 if (send_count_unsigned_values != 0)
395 {
396 MPI_Wait(&request, MPI_STATUS_IGNORE);
397 }
398
399 // Send and receive the Located_element_status
400 //--------------------------------------------
401 int send_count = Received_flat_packed_zetas_to_be_found.size() / Dim;
402 MPI_Isend(&send_count,
403 1,
404 MPI_INT,
405 orig_send_proc,
406 20,
407 comm_pt->mpi_comm(),
408 &request);
409 int receive_count = 0;
410 MPI_Recv(&receive_count,
411 1,
412 MPI_INT,
413 orig_recv_proc,
414 20,
415 comm_pt->mpi_comm(),
416 &status);
417 MPI_Wait(&request, MPI_STATUS_IGNORE);
418
419 if (send_count != 0)
420 {
421 MPI_Isend(&Located_element_status[0],
422 send_count,
423 MPI_UNSIGNED,
424 orig_send_proc,
425 3,
426 comm_pt->mpi_comm(),
427 &request);
428 }
429
430 if (receive_count != 0)
431 {
432 received_located_element_status.resize(receive_count);
433 MPI_Recv(&received_located_element_status[0],
434 receive_count,
435 MPI_UNSIGNED,
436 orig_recv_proc,
437 3,
438 comm_pt->mpi_comm(),
439 &status);
440 }
441 if (send_count != 0)
442 {
443 MPI_Wait(&request, MPI_STATUS_IGNORE);
444 }
445
446 // Send and receive Proc_id_plus_one_of_external_element array
447 //------------------------------------------------------------
448 if (send_count != 0)
449 {
451 send_count,
452 MPI_INT,
453 orig_send_proc,
454 13,
455 comm_pt->mpi_comm(),
456 &request);
457 }
458 if (receive_count != 0)
459 {
460 received_proc_id_plus_one_of_external_element.resize(receive_count);
461 MPI_Recv(&received_proc_id_plus_one_of_external_element[0],
462 receive_count,
463 MPI_INT,
464 orig_recv_proc,
465 13,
466 comm_pt->mpi_comm(),
467 &status);
468 }
469 if (send_count != 0)
470 {
471 MPI_Wait(&request, MPI_STATUS_IGNORE);
472 }
473
474
475 // And finally the Flat_packed_located_coordinates array
476 //------------------------------------------------------
477 unsigned send_count_located_coord =
479 MPI_Isend(&send_count_located_coord,
480 1,
481 MPI_UNSIGNED,
482 orig_send_proc,
483 4,
484 comm_pt->mpi_comm(),
485 &request);
486 unsigned receive_count_located_coord = 0;
487 MPI_Recv(&receive_count_located_coord,
488 1,
489 MPI_UNSIGNED,
490 orig_recv_proc,
491 4,
492 comm_pt->mpi_comm(),
493 &status);
494 MPI_Wait(&request, MPI_STATUS_IGNORE);
495
496 if (send_count_located_coord != 0)
497 {
499 send_count_located_coord,
500 MPI_DOUBLE,
501 orig_send_proc,
502 5,
503 comm_pt->mpi_comm(),
504 &request);
505 }
506 if (receive_count_located_coord != 0)
507 {
508 received_located_coord.resize(receive_count_located_coord);
509 MPI_Recv(&received_located_coord[0],
510 receive_count_located_coord,
511 MPI_DOUBLE,
512 orig_recv_proc,
513 5,
514 comm_pt->mpi_comm(),
515 &status);
516 }
517 if (send_count_located_coord != 0)
518 {
519 MPI_Wait(&request, MPI_STATUS_IGNORE);
520 }
521
522 // Copy across into original containers -- these can now
523 //------------------------------------------------------
524 // be processed by create_external_halo_elements() to generate
525 //------------------------------------------------------------
526 // external halo elements
527 //------------------------
528 Flat_packed_doubles.resize(receive_count_double_values);
529 for (int ii = 0; ii < receive_count_double_values; ii++)
530 {
531 Flat_packed_doubles[ii] = received_double_values[ii];
532 }
533 Flat_packed_unsigneds.resize(receive_count_unsigned_values);
534 for (int ii = 0; ii < receive_count_unsigned_values; ii++)
535 {
536 Flat_packed_unsigneds[ii] = received_unsigned_values[ii];
537 }
538 Proc_id_plus_one_of_external_element.resize(receive_count);
539 Located_element_status.resize(receive_count);
540 for (int ii = 0; ii < receive_count; ii++)
541 {
543 received_proc_id_plus_one_of_external_element[ii];
544 Located_element_status[ii] = received_located_element_status[ii];
545 }
546 Flat_packed_located_coordinates.resize(receive_count_located_coord);
547 for (int ii = 0; ii < int(receive_count_located_coord); ii++)
548 {
549 Flat_packed_located_coordinates[ii] = received_located_coord[ii];
550 }
551 }
552
553
554 //========start of add_external_haloed_node_to_storage====================
555 /// Helper function to add external haloed nodes, including any masters
556 //========================================================================
558 Node* nod_pt,
559 Problem* problem_pt,
560 Mesh* const& external_mesh_pt,
561 int& n_cont_inter_values)
562 {
563 // Add the node if required
565 iproc, nod_pt, problem_pt, external_mesh_pt, n_cont_inter_values);
566
567 // Recursively add any master nodes (and their master nodes etc)
569 iproc, nod_pt, problem_pt, external_mesh_pt, n_cont_inter_values);
570 }
571
572
573 //========================================================================
574 /// Recursively add any master nodes (and their master nodes etc) of
575 /// external nodes
576 //========================================================================
578 int& iproc,
579 Node* nod_pt,
580 Problem* problem_pt,
581 Mesh* const& external_mesh_pt,
582 int& n_cont_inter_values)
583 {
584 // Loop over continuously interpolated values and add masters
585 for (int i_cont = -1; i_cont < n_cont_inter_values; i_cont++)
586 {
587 if (nod_pt->is_hanging(i_cont))
588 {
589 // Indicate that this node is a hanging node so the other
590 // process knows to create HangInfo and masters, etc.
591 Flat_packed_unsigneds.push_back(1);
592#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
593 Flat_packed_unsigneds_string.push_back("Is hanging");
594#endif
595 // If this is a hanging node then add all its masters as
596 // external halo nodes if they have not yet been added
597 HangInfo* hang_pt = nod_pt->hanging_pt(i_cont);
598 // Loop over masters
599 unsigned n_master = hang_pt->nmaster();
600
601 // Indicate number of master nodes to add on other process
602 Flat_packed_unsigneds.push_back(n_master);
603#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
604 Flat_packed_unsigneds_string.push_back("nmaster");
605#endif
606 for (unsigned m = 0; m < n_master; m++)
607 {
608 Node* master_nod_pt = hang_pt->master_node_pt(m);
609
610 // Call the helper function for master nodes
612 master_nod_pt,
613 problem_pt,
614 external_mesh_pt,
615 n_cont_inter_values);
616
617 // Indicate the weight of this master
618 Flat_packed_doubles.push_back(hang_pt->master_weight(m));
619
620 // Recursively add any master nodes (and their master nodes etc)
622 iproc,
623 master_nod_pt,
624 problem_pt,
625 external_mesh_pt,
626 n_cont_inter_values);
627 }
628 }
629 else
630 {
631 // Indicate that it's not a hanging node in this variable
632 Flat_packed_unsigneds.push_back(0);
633#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
634 Flat_packed_unsigneds_string.push_back("Not hanging");
635#endif
636 }
637 } // end loop over continously interpolated values
638 }
639
640 //==========start of add_external_haloed_node_helper======================
641 /// Helper to add external haloed node that is not a master
642 //========================================================================
644 Node* nod_pt,
645 Problem* problem_pt,
646 Mesh* const& external_mesh_pt,
647 int& n_cont_inter_values)
648 {
649 // Attempt to add this node as an external haloed node
650 unsigned n_ext_haloed_nod =
651 external_mesh_pt->nexternal_haloed_node(iproc);
652 unsigned external_haloed_node_index =
653 external_mesh_pt->add_external_haloed_node_pt(iproc, nod_pt);
654
655 // If it was added then the new index should match the size of the storage
656 if (external_haloed_node_index == n_ext_haloed_nod)
657 {
658 Flat_packed_unsigneds.push_back(1);
659
660#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
661 std::stringstream junk;
662 junk << "Node needs to be constructed [size="
663 << Flat_packed_unsigneds.size() << "]; last entry: "
665 Flat_packed_unsigneds_string.push_back(junk.str());
666#endif
667
668 // This helper function gets all the required information for the
669 // specified node and stores it into MPI-sendable information
670 // so that a halo copy can be made on the receiving process
672 iproc, nod_pt, problem_pt, external_mesh_pt, n_cont_inter_values);
673 }
674 else // It was already added
675 {
676 Flat_packed_unsigneds.push_back(0);
677#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
678 std::stringstream junk;
679 junk << "Node was already added [size=" << Flat_packed_unsigneds.size()
680 << "]; last entry: "
682
683 Flat_packed_unsigneds_string.push_back(junk.str());
684#endif
685
686 // This node is already an external haloed node, so tell
687 // the other process its index in the equivalent external halo storage
688 Flat_packed_unsigneds.push_back(external_haloed_node_index);
689#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
690 Flat_packed_unsigneds_string.push_back("external haloed node index");
691#endif
692 }
693 }
694
695
696 //==========start of add_external_haloed_master_node_helper===============
697 /// Helper function to add external haloed node that is a master
698 //========================================================================
700 Node* master_nod_pt,
701 Problem* problem_pt,
702 Mesh* const& external_mesh_pt,
703 int& n_cont_inter_values)
704 {
705 // Attempt to add node as an external haloed node
706 unsigned n_ext_haloed_nod =
707 external_mesh_pt->nexternal_haloed_node(iproc);
708 unsigned external_haloed_node_index;
709 external_haloed_node_index =
710 external_mesh_pt->add_external_haloed_node_pt(iproc, master_nod_pt);
711
712 // If it was added the returned index is the same as current storage size
713 if (external_haloed_node_index == n_ext_haloed_nod)
714 {
715 // Indicate that this node needs to be constructed on
716 // the other process
717 Flat_packed_unsigneds.push_back(1);
718#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
720 "Node needs to be constructed[2]");
721#endif
722
723 // This gets all the required information for the specified
724 // master node and stores it into MPI-sendable information
725 // so that a halo copy can be made on the receiving process
727 master_nod_pt,
728 problem_pt,
729 external_mesh_pt,
730 n_cont_inter_values);
731 }
732 else // It was already added
733 {
734 Flat_packed_unsigneds.push_back(0);
735#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
736 Flat_packed_unsigneds_string.push_back("Node was already added[2]");
737#endif
738
739 // This node is already an external haloed node, so tell
740 // the other process its index in the equivalent external halo storage
741 Flat_packed_unsigneds.push_back(external_haloed_node_index);
742#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
743 Flat_packed_unsigneds_string.push_back("external haloed node index[2]");
744#endif
745 }
746 }
747
748
749 //========start of get_required_nodal_information_helper==================
750 /// Helper function to get the required nodal information from an
751 /// external haloed node so that a fully-functional external halo
752 /// node (and therefore element) can be created on the receiving process
753 //========================================================================
755 Node* nod_pt,
756 Problem* problem_pt,
757 Mesh* const& external_mesh_pt,
758 int& n_cont_inter_values)
759 {
760 // Tell the halo copy of this node how many values there are
761 // [NB this may be different for nodes within the same element, e.g.
762 // when using Lagrange multipliers]
763 unsigned n_val = nod_pt->nvalue();
764 Flat_packed_unsigneds.push_back(n_val);
765#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
766 Flat_packed_unsigneds_string.push_back("Number of values");
767#endif
768
769 unsigned n_dim = nod_pt->ndim();
770 TimeStepper* time_stepper_pt = nod_pt->time_stepper_pt();
771
772 // Find the timestepper in the list of problem timesteppers
773 bool found_timestepper = false;
774 unsigned time_stepper_index;
775 unsigned n_time_steppers = problem_pt->ntime_stepper();
776 for (unsigned i = 0; i < n_time_steppers; i++)
777 {
778 if (time_stepper_pt == problem_pt->time_stepper_pt(i))
779 {
780 // Indicate the timestepper's index
781 found_timestepper = true;
782 time_stepper_index = i;
783 break;
784 }
785 }
786
787 if (found_timestepper)
788 {
789 Flat_packed_unsigneds.push_back(1);
790#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
791 Flat_packed_unsigneds_string.push_back("Found timestepper");
792#endif
793 Flat_packed_unsigneds.push_back(time_stepper_index);
794#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
795 Flat_packed_unsigneds_string.push_back("Timestepper index");
796#endif
797 }
798 else
799 {
800 Flat_packed_unsigneds.push_back(0);
801#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
802 Flat_packed_unsigneds_string.push_back("Not found timestepper");
803#endif
804 }
805
806 // Default number of previous values to 1
807 unsigned n_prev = 1;
808 if (time_stepper_pt != 0)
809 {
810 // Add number of history values to n_prev
811 n_prev = time_stepper_pt->ntstorage();
812 }
813
814 // Is the node on any boundaries?
815 if (nod_pt->is_on_boundary())
816 {
817 Flat_packed_unsigneds.push_back(1);
818#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
819 Flat_packed_unsigneds_string.push_back("Node is on boundary");
820#endif
821
822 // Loop over the boundaries of the external mesh
823 Vector<unsigned> boundaries;
824 unsigned n_bnd = external_mesh_pt->nboundary();
825 for (unsigned i_bnd = 0; i_bnd < n_bnd; i_bnd++)
826 {
827 // Which boundaries (could be more than one) is it on?
828 if (nod_pt->is_on_boundary(i_bnd))
829 {
830 boundaries.push_back(i_bnd);
831 }
832 }
833 unsigned nb = boundaries.size();
834 Flat_packed_unsigneds.push_back(nb);
835#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
836 std::stringstream junk;
837 junk << "Node is on " << nb << " boundaries";
838 Flat_packed_unsigneds_string.push_back(junk.str());
839#endif
840 for (unsigned i = 0; i < nb; i++)
841 {
842 Flat_packed_unsigneds.push_back(boundaries[i]);
843#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
844 std::stringstream junk;
845 junk << "Node is on boundary " << boundaries[i] << " of " << n_bnd;
846 Flat_packed_unsigneds_string.push_back(junk.str());
847#endif
848 }
849
850 // Get pointer to the map of indices associated with
851 // additional values created by face elements
852 BoundaryNodeBase* bnod_pt = dynamic_cast<BoundaryNodeBase*>(nod_pt);
853#ifdef PARANOID
854 if (bnod_pt == 0)
855 {
856 throw OomphLibError("Failed to cast new node to boundary node\n",
857 OOMPH_CURRENT_FUNCTION,
858 OOMPH_EXCEPTION_LOCATION);
859 }
860#endif
861 std::map<unsigned, unsigned>* map_pt =
863
864 // No additional values created
865 if (map_pt == 0)
866 {
867 Flat_packed_unsigneds.push_back(0);
868#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
869 std::stringstream junk;
871 "No additional values were created by face element");
872#endif
873 }
874 // Created additional values
875 else
876 {
877 // How many?
878 Flat_packed_unsigneds.push_back(map_pt->size());
879#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
880 std::stringstream junk;
881 junk << "Map size " << map_pt->size() << n_bnd;
882 Flat_packed_unsigneds_string.push_back(junk.str());
883#endif
884 // Loop over entries in map and add to send data
885 for (std::map<unsigned, unsigned>::iterator p = map_pt->begin();
886 p != map_pt->end();
887 p++)
888 {
889 Flat_packed_unsigneds.push_back((*p).first);
890#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
891 std::stringstream junk;
892 Flat_packed_unsigneds_string.push_back("Key of map entry");
893#endif
894 Flat_packed_unsigneds.push_back((*p).second);
895#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
896 Flat_packed_unsigneds_string.push_back("Value of map entry");
897#endif
898 }
899 }
900 }
901 else
902 {
903 // Not on any boundary
904 Flat_packed_unsigneds.push_back(0);
905#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
906 Flat_packed_unsigneds_string.push_back("Node is not on any boundary");
907#endif
908 }
909
910 // Is the Node algebraic? If so, send its ref values and
911 // an indication of its geometric objects if they are stored
912 // in the algebraic mesh
913 AlgebraicNode* alg_nod_pt = dynamic_cast<AlgebraicNode*>(nod_pt);
914 if (alg_nod_pt != 0)
915 {
916 // The external mesh should be algebraic
917 AlgebraicMesh* alg_mesh_pt =
918 dynamic_cast<AlgebraicMesh*>(external_mesh_pt);
919
920 // Get default node update function ID
921 unsigned update_id = alg_nod_pt->node_update_fct_id();
922 Flat_packed_unsigneds.push_back(update_id);
923#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
924 Flat_packed_unsigneds_string.push_back("Alg Node update id");
925#endif
926
927 // Get reference values at default...
928 unsigned n_ref_val = alg_nod_pt->nref_value();
929 Flat_packed_unsigneds.push_back(n_ref_val);
930#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
931 Flat_packed_unsigneds_string.push_back("Alg Node n ref values");
932#endif
933 for (unsigned i_ref_val = 0; i_ref_val < n_ref_val; i_ref_val++)
934 {
935 Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
936 }
937
938 // Access geometric objects at default...
939 unsigned n_geom_obj = alg_nod_pt->ngeom_object();
940 Flat_packed_unsigneds.push_back(n_geom_obj);
941#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
942 Flat_packed_unsigneds_string.push_back("Alg Node n geom objects");
943#endif
944 for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
945 {
946 GeomObject* geom_obj_pt = alg_nod_pt->geom_object_pt(i_geom);
947
948 // Check this against the stored geometric objects in mesh
949 unsigned n_geom_list = alg_mesh_pt->ngeom_object_list_pt();
950
951 // Default found index to zero
952 unsigned found_geom_object = 0;
953 for (unsigned i_list = 0; i_list < n_geom_list; i_list++)
954 {
955 if (geom_obj_pt == alg_mesh_pt->geom_object_list_pt(i_list))
956 {
957 found_geom_object = i_list;
958 }
959 }
960 Flat_packed_unsigneds.push_back(found_geom_object);
961#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
962 Flat_packed_unsigneds_string.push_back("Found geom object");
963#endif
964 }
965 }
966
967 // If it is a MacroElementNodeUpdateNode, everything has been
968 // dealt with by the new element already
969
970 // Is it a SolidNode?
971 SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(nod_pt);
972 if (solid_nod_pt != 0)
973 {
974 unsigned n_solid_val = solid_nod_pt->variable_position_pt()->nvalue();
975 for (unsigned i_val = 0; i_val < n_solid_val; i_val++)
976 {
977 for (unsigned t = 0; t < n_prev; t++)
978 {
979 Flat_packed_doubles.push_back(
980 solid_nod_pt->variable_position_pt()->value(t, i_val));
981 }
982 }
983 }
984
985 // Finally copy info required for all node types
986 for (unsigned i_val = 0; i_val < n_val; i_val++)
987 {
988 for (unsigned t = 0; t < n_prev; t++)
989 {
990 Flat_packed_doubles.push_back(nod_pt->value(t, i_val));
991 }
992 }
993
994 // Now do positions
995 for (unsigned idim = 0; idim < n_dim; idim++)
996 {
997 for (unsigned t = 0; t < n_prev; t++)
998 {
999 Flat_packed_doubles.push_back(nod_pt->x(t, idim));
1000 }
1001 }
1002 }
1003
1004 //=========start of get_required_master_nodal_information_helper==========
1005 /// Helper function to get the required master nodal information from an
1006 /// external haloed master node so that a fully-functional external halo
1007 /// master node (and possible element) can be created on the receiving
1008 /// process
1009 //========================================================================
1011 int& iproc,
1012 Node* master_nod_pt,
1013 Problem* problem_pt,
1014 Mesh* const& external_mesh_pt,
1015 int& n_cont_inter_values)
1016 {
1017 // Need to send over dimension, position type and number of values
1018 Flat_packed_unsigneds.push_back(master_nod_pt->ndim());
1019#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1020 Flat_packed_unsigneds_string.push_back("Master node ndim");
1021#endif
1022 Flat_packed_unsigneds.push_back(master_nod_pt->nposition_type());
1023#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1024 Flat_packed_unsigneds_string.push_back("Master node npos_type");
1025#endif
1026 Flat_packed_unsigneds.push_back(master_nod_pt->nvalue());
1027#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1028 Flat_packed_unsigneds_string.push_back("Master node nvalue");
1029#endif
1030
1031 // If it's a solid node, also need to send lagrangian dim and type
1032 SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(master_nod_pt);
1033 if (solid_nod_pt != 0)
1034 {
1035 Flat_packed_unsigneds.push_back(solid_nod_pt->nlagrangian());
1036#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1037 Flat_packed_unsigneds_string.push_back("Master solid node nlagr");
1038#endif
1039 Flat_packed_unsigneds.push_back(solid_nod_pt->nlagrangian_type());
1040#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1041 Flat_packed_unsigneds_string.push_back("Master solid node nlagr_type");
1042#endif
1043 }
1044
1045 unsigned n_dim = master_nod_pt->ndim();
1046 TimeStepper* time_stepper_pt = master_nod_pt->time_stepper_pt();
1047
1048 // Find the timestepper in the list of problem timesteppers
1049 bool found_timestepper = false;
1050 unsigned time_stepper_index;
1051 unsigned n_time_steppers = problem_pt->ntime_stepper();
1052 for (unsigned i = 0; i < n_time_steppers; i++)
1053 {
1054 if (time_stepper_pt == problem_pt->time_stepper_pt(i))
1055 {
1056 // Indicate the timestepper's index
1057 // add 1 to the index so that 0 indicates no timestepper?
1058 found_timestepper = true;
1059 time_stepper_index = i;
1060 break;
1061 }
1062 }
1063
1064 if (found_timestepper)
1065 {
1066 Flat_packed_unsigneds.push_back(1);
1067#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1068 Flat_packed_unsigneds_string.push_back("Master node Found timestepper");
1069#endif
1070 Flat_packed_unsigneds.push_back(time_stepper_index);
1071#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1072 Flat_packed_unsigneds_string.push_back("Master node Timestepper index");
1073#endif
1074 }
1075 else
1076 {
1077 Flat_packed_unsigneds.push_back(0);
1078#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1080 "Master node Not found timestepper");
1081#endif
1082 }
1083
1084 // Default number of previous values to 1
1085 unsigned n_prev = 1;
1086 if (time_stepper_pt != 0)
1087 {
1088 // Add number of history values to n_prev
1089 n_prev = time_stepper_pt->ntstorage();
1090 }
1091
1092 // Is the node on any boundaries?
1093 if (master_nod_pt->is_on_boundary())
1094 {
1095 Flat_packed_unsigneds.push_back(1);
1096#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1097 Flat_packed_unsigneds_string.push_back("Master node is on boundary");
1098#endif
1099 // Loop over the boundaries of the external mesh
1100 Vector<unsigned> boundaries;
1101 unsigned n_bnd = external_mesh_pt->nboundary();
1102 for (unsigned i_bnd = 0; i_bnd < n_bnd; i_bnd++)
1103 {
1104 // Which boundaries (could be more than one) is it on?
1105 if (master_nod_pt->is_on_boundary(i_bnd))
1106 {
1107 boundaries.push_back(i_bnd);
1108 }
1109 }
1110 unsigned nb = boundaries.size();
1111 Flat_packed_unsigneds.push_back(nb);
1112#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1113 std::stringstream junk;
1114 junk << "Master node is on " << nb << " boundaries";
1115 Flat_packed_unsigneds_string.push_back(junk.str());
1116#endif
1117 for (unsigned i = 0; i < nb; i++)
1118 {
1119 Flat_packed_unsigneds.push_back(boundaries[i]);
1120#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1121 std::stringstream junk;
1122 junk << "Master noode is on boundary " << boundaries[i] << " of "
1123 << n_bnd;
1124 Flat_packed_unsigneds_string.push_back(junk.str());
1125#endif
1126 }
1127
1128 // Get pointer to the map of indices associated with
1129 // additional values created by face elements
1130 BoundaryNodeBase* bnod_pt =
1131 dynamic_cast<BoundaryNodeBase*>(master_nod_pt);
1132#ifdef PARANOID
1133 if (bnod_pt == 0)
1134 {
1135 throw OomphLibError("Failed to cast new node to boundary node\n",
1136 OOMPH_CURRENT_FUNCTION,
1137 OOMPH_EXCEPTION_LOCATION);
1138 }
1139#endif
1140 std::map<unsigned, unsigned>* map_pt =
1142
1143 // No additional values created
1144 if (map_pt == 0)
1145 {
1146 Flat_packed_unsigneds.push_back(0);
1147#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1148 std::stringstream junk;
1150 "No additional values were created by face element for this master "
1151 "node");
1152#endif
1153 }
1154 // Created additional values
1155 else
1156 {
1157 // How many?
1158 Flat_packed_unsigneds.push_back(map_pt->size());
1159#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1160 std::stringstream junk;
1161 junk << "Map size for master node " << map_pt->size() << n_bnd;
1162 Flat_packed_unsigneds_string.push_back(junk.str());
1163#endif
1164 // Loop over entries in map and add to send data
1165 for (std::map<unsigned, unsigned>::iterator p = map_pt->begin();
1166 p != map_pt->end();
1167 p++)
1168 {
1169 Flat_packed_unsigneds.push_back((*p).first);
1170#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1171 std::stringstream junk;
1173 "Key of map entry for master node");
1174#endif
1175 Flat_packed_unsigneds.push_back((*p).second);
1176#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1178 "Value of map entry for master node");
1179#endif
1180 }
1181 }
1182 }
1183 else
1184 {
1185 // Not on any boundary
1186 Flat_packed_unsigneds.push_back(0);
1187#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1189 "Master node is not on any boundary");
1190#endif
1191 }
1192
1193 // Is the Node algebraic? If so, send its ref values and
1194 // an indication of its geometric objects if they are stored
1195 // in the algebraic mesh
1196 AlgebraicNode* alg_nod_pt = dynamic_cast<AlgebraicNode*>(master_nod_pt);
1197 if (alg_nod_pt != 0)
1198 {
1199 // The external mesh should be algebraic
1200 AlgebraicMesh* alg_mesh_pt =
1201 dynamic_cast<AlgebraicMesh*>(external_mesh_pt);
1202
1203 // Get default node update function ID
1204 unsigned update_id = alg_nod_pt->node_update_fct_id();
1205 Flat_packed_unsigneds.push_back(update_id);
1206#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1207 Flat_packed_unsigneds_string.push_back("Master Alg Node update id");
1208#endif
1209
1210 // Get reference values at default...
1211 unsigned n_ref_val = alg_nod_pt->nref_value();
1212 Flat_packed_unsigneds.push_back(n_ref_val);
1213#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1214 Flat_packed_unsigneds_string.push_back("Master Alg Node n ref values");
1215#endif
1216 for (unsigned i_ref_val = 0; i_ref_val < n_ref_val; i_ref_val++)
1217 {
1218 Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
1219 }
1220
1221 // Access geometric objects at default...
1222 unsigned n_geom_obj = alg_nod_pt->ngeom_object();
1223 Flat_packed_unsigneds.push_back(n_geom_obj);
1224#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1226 "Master Alg Node n geom objects");
1227#endif
1228 for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
1229 {
1230 GeomObject* geom_obj_pt = alg_nod_pt->geom_object_pt(i_geom);
1231 // Check this against the stored geometric objects in mesh
1232 unsigned n_geom_list = alg_mesh_pt->ngeom_object_list_pt();
1233 // Default found index to zero
1234 unsigned found_geom_object = 0;
1235 for (unsigned i_list = 0; i_list < n_geom_list; i_list++)
1236 {
1237 if (geom_obj_pt == alg_mesh_pt->geom_object_list_pt(i_list))
1238 {
1239 found_geom_object = i_list;
1240 }
1241 }
1242 Flat_packed_unsigneds.push_back(found_geom_object);
1243#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1245 "Master node Found geom object");
1246#endif
1247 }
1248 } // end AlgebraicNode check
1249
1250 // Is it a MacroElementNodeUpdateNode?
1251 MacroElementNodeUpdateNode* macro_nod_pt =
1252 dynamic_cast<MacroElementNodeUpdateNode*>(master_nod_pt);
1253 if (macro_nod_pt != 0)
1254 {
1255 // Loop over current external haloed elements - has the element which
1256 // controls the node update for this node been added yet?
1257 GeneralisedElement* macro_node_update_el_pt =
1258 macro_nod_pt->node_update_element_pt();
1259
1260 unsigned n_ext_haloed_el =
1261 external_mesh_pt->nexternal_haloed_element(iproc);
1262 unsigned external_haloed_el_index;
1263 external_haloed_el_index =
1264 external_mesh_pt->add_external_haloed_element_pt(
1265 iproc, macro_node_update_el_pt);
1266
1267 // If it wasn't already added, we need to create a halo copy
1268 if (external_haloed_el_index == n_ext_haloed_el)
1269 {
1270 Flat_packed_unsigneds.push_back(1);
1271#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1273 "Master Node needs to be constructed");
1274#endif
1275 // Cast to a finite elemnet
1276 FiniteElement* macro_node_update_finite_el_pt =
1277 dynamic_cast<FiniteElement*>(macro_node_update_el_pt);
1278
1279 // We're using macro elements to update...
1280 MacroElementNodeUpdateMesh* macro_mesh_pt =
1281 dynamic_cast<MacroElementNodeUpdateMesh*>(external_mesh_pt);
1282 if (macro_mesh_pt != 0)
1283 {
1284 Flat_packed_unsigneds.push_back(1);
1285#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1287 "Mesh is macro element mesh");
1288#endif
1289 // Need to send the macro element number in the mesh across
1290 MacroElement* macro_el_pt =
1291 macro_node_update_finite_el_pt->macro_elem_pt();
1292 unsigned macro_el_num = macro_el_pt->macro_element_number();
1293 Flat_packed_unsigneds.push_back(macro_el_num);
1294#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1295 Flat_packed_unsigneds_string.push_back("Number of macro element");
1296#endif
1297 // Also need to send
1298 // the lower left and upper right coordinates of the macro element
1299 QElementBase* q_el_pt =
1300 dynamic_cast<QElementBase*>(macro_node_update_el_pt);
1301 if (q_el_pt != 0)
1302 {
1303 // The macro element needs to be set first before
1304 // its lower left and upper right coordinates can be accessed
1305 // Now send the lower left and upper right coordinates
1306 unsigned el_dim = q_el_pt->dim();
1307 for (unsigned i_dim = 0; i_dim < el_dim; i_dim++)
1308 {
1309 Flat_packed_doubles.push_back(q_el_pt->s_macro_ll(i_dim));
1310 Flat_packed_doubles.push_back(q_el_pt->s_macro_ur(i_dim));
1311 }
1312 }
1313 else // Throw an error
1314 {
1315 std::ostringstream error_stream;
1316 error_stream << "You are using a MacroElement node update\n"
1317 << "in a case with non-QElements. This has not\n"
1318 << "yet been implemented.\n";
1319 throw OomphLibError(error_stream.str(),
1320 OOMPH_CURRENT_FUNCTION,
1321 OOMPH_EXCEPTION_LOCATION);
1322 }
1323 }
1324 else // Not using macro elements for node update... umm, we're
1325 // already inside a loop over macro elements, so this
1326 // should never get here... an error should be thrown I suppose
1327 {
1328 Flat_packed_unsigneds.push_back(0);
1329#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1331 "Mesh is not a macro element mesh");
1332#endif
1333 }
1334
1335 // This element needs to be fully functioning on the other
1336 // process, so send all the information required to create it
1337 unsigned n_node = macro_node_update_finite_el_pt->nnode();
1338 for (unsigned j = 0; j < n_node; j++)
1339 {
1340 Node* new_nod_pt = macro_node_update_finite_el_pt->node_pt(j);
1342 new_nod_pt,
1343 problem_pt,
1344 external_mesh_pt,
1345 n_cont_inter_values);
1346 }
1347 }
1348 else // The external haloed element already exists
1349 {
1350 Flat_packed_unsigneds.push_back(0);
1351#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1353 "External haloed element already exists");
1354#endif
1355 Flat_packed_unsigneds.push_back(external_haloed_el_index);
1356#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1358 "Index of existing external haloed element");
1359#endif
1360 }
1361
1362 } // end of MacroElementNodeUpdateNode check
1363
1364 // Is it a SolidNode?
1365 if (solid_nod_pt != 0)
1366 {
1367 unsigned n_val = solid_nod_pt->variable_position_pt()->nvalue();
1368 for (unsigned i_val = 0; i_val < n_val; i_val++)
1369 {
1370 for (unsigned t = 0; t < n_prev; t++)
1371 {
1372 Flat_packed_doubles.push_back(
1373 solid_nod_pt->variable_position_pt()->value(t, i_val));
1374 }
1375 }
1376 }
1377
1378 // Finally copy info required for all node types
1379
1380 // Halo copy needs to know all the history values
1381 unsigned n_val = master_nod_pt->nvalue();
1382 for (unsigned i_val = 0; i_val < n_val; i_val++)
1383 {
1384 for (unsigned t = 0; t < n_prev; t++)
1385 {
1386 Flat_packed_doubles.push_back(master_nod_pt->value(t, i_val));
1387 }
1388 }
1389
1390 // Now do positions
1391 for (unsigned idim = 0; idim < n_dim; idim++)
1392 {
1393 for (unsigned t = 0; t < n_prev; t++)
1394 {
1395 Flat_packed_doubles.push_back(master_nod_pt->x(t, idim));
1396 }
1397 }
1398 }
1399
1400
1401 //=======start of add_external_halo_node_helper===========================
1402 /// Helper functiono to add external halo node that is not a master
1403 //========================================================================
1405 Mesh* const& external_mesh_pt,
1406 unsigned& loc_p,
1407 unsigned& node_index,
1408 FiniteElement* const& new_el_pt,
1409 int& n_cont_inter_values,
1410 Problem* problem_pt)
1411 {
1412 // Given the node and the external mesh, and received information
1413 // about them from process loc_p, construct them on the current process
1414#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1416 << " Bool: New node needs to be constructed "
1418 << std::endl;
1419#endif
1421 {
1422 // Construct a new node based upon sent information
1424 loc_p,
1425 node_index,
1426 new_el_pt,
1427 external_mesh_pt,
1428 problem_pt);
1429 }
1430 else
1431 {
1432#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1434 << " Index of existing external halo node "
1436 << std::endl;
1437#endif
1438
1439 // Copy node from received location
1440 new_nod_pt = external_mesh_pt->external_halo_node_pt(
1442
1443 new_el_pt->node_pt(node_index) = new_nod_pt;
1444 }
1445 }
1446
1447
1448 //========start of construct_new_external_halo_node_helper=================
1449 /// Helper function which constructs a new external halo node (on new
1450 /// element) with the required information sent from the haloed process
1451 //========================================================================
1453 Node*& new_nod_pt,
1454 unsigned& loc_p,
1455 unsigned& node_index,
1456 FiniteElement* const& new_el_pt,
1457 Mesh* const& external_mesh_pt,
1458 Problem* problem_pt)
1459 {
1460 // The first entry indicates the number of values at this new Node
1461 // (which may be different across the same element e.g. Lagrange
1462 // multipliers)
1463#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1465 << " Number of values of external halo node "
1467 << std::endl;
1468#endif
1469 unsigned n_val =
1471
1472 // Null TimeStepper for now
1473 TimeStepper* time_stepper_pt = 0;
1474 // Default number of previous values to 1
1475 unsigned n_prev = 1;
1476
1477 // The next entry in Flat_packed_unsigneds indicates
1478 // if a timestepper is required for this halo node
1479#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1481 << " Timestepper req'd for node "
1483 << std::endl;
1484#endif
1486 {
1487#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1489 << " Index of timestepper "
1491 << std::endl;
1492#endif
1493 // Index
1494 time_stepper_pt = problem_pt->time_stepper_pt(
1496
1497 // Check whether number of prev values is "sent" across
1498 n_prev = time_stepper_pt->ntstorage();
1499 }
1500
1501 // If this node was on a boundary then it needs to
1502 // be on the same boundary here
1503#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1505 << " Is node on boundary? "
1507 << std::endl;
1508#endif
1510 {
1511 // Construct a new boundary node
1512 if (time_stepper_pt != 0)
1513 {
1514 new_nod_pt =
1515 new_el_pt->construct_boundary_node(node_index, time_stepper_pt);
1516 }
1517 else
1518 {
1519 new_nod_pt = new_el_pt->construct_boundary_node(node_index);
1520 }
1521
1522 // How many boundaries does the node live on?
1523#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1525 << " Number of boundaries the node is on: "
1527 << std::endl;
1528#endif
1529 unsigned nb =
1531 for (unsigned i = 0; i < nb; i++)
1532 {
1533 // Boundary number
1534#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1536 << " Node is on boundary "
1538 << std::endl;
1539#endif
1540 unsigned i_bnd =
1542 external_mesh_pt->add_boundary_node(i_bnd, new_nod_pt);
1543 }
1544
1545 // Do we have additional values created by face elements?
1546#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1548 << " Number of additional values created by face element "
1550 << std::endl;
1551#endif
1552 unsigned n_entry =
1554 if (n_entry > 0)
1555 {
1556 // Create storage, if it doesn't already exist, for the map
1557 // that will contain the position of the first entry of
1558 // this face element's additional values,
1559 BoundaryNodeBase* bnew_nod_pt =
1560 dynamic_cast<BoundaryNodeBase*>(new_nod_pt);
1561#ifdef PARANOID
1562 if (bnew_nod_pt == 0)
1563 {
1564 throw OomphLibError("Failed to cast new node to boundary node\n",
1565 OOMPH_CURRENT_FUNCTION,
1566 OOMPH_EXCEPTION_LOCATION);
1567 }
1568#endif
1570 0)
1571 {
1573 new std::map<unsigned, unsigned>;
1574 }
1575
1576 // Get pointer to the map of indices associated with
1577 // additional values created by face elements
1578 std::map<unsigned, unsigned>* map_pt =
1580
1581 // Loop over number of entries in map
1582 for (unsigned i = 0; i < n_entry; i++)
1583 {
1584 // Read out pairs...
1585
1586#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1589 << " Key of map entry"
1591 << std::endl;
1592#endif
1593 unsigned first =
1595
1596#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1599 << " Value of map entry"
1601 << std::endl;
1602#endif
1603 unsigned second =
1605
1606 // ...and assign
1607 (*map_pt)[first] = second;
1608 }
1609 }
1610 }
1611 else
1612 {
1613 // Construct an ordinary (non-boundary) node
1614 if (time_stepper_pt != 0)
1615 {
1616 new_nod_pt = new_el_pt->construct_node(node_index, time_stepper_pt);
1617 }
1618 else
1619 {
1620 new_nod_pt = new_el_pt->construct_node(node_index);
1621 }
1622 }
1623
1624 // Node constructed: add to external halo nodes
1625 external_mesh_pt->add_external_halo_node_pt(loc_p, new_nod_pt);
1626
1627 // Is the new constructed node Algebraic?
1628 AlgebraicNode* new_alg_nod_pt = dynamic_cast<AlgebraicNode*>(new_nod_pt);
1629
1630 // If it is algebraic, its node update functions will
1631 // not yet have been set up properly
1632 if (new_alg_nod_pt != 0)
1633 {
1634 // The AlgebraicMesh is the external mesh
1635 AlgebraicMesh* alg_mesh_pt =
1636 dynamic_cast<AlgebraicMesh*>(external_mesh_pt);
1637
1638 /// The first entry of All_alg_nodal_info contains
1639 /// the default node update id
1640 /// e.g. for the quarter circle there are
1641 /// "Upper_left_box", "Lower right box" etc...
1642#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1644 << " Alg node update id "
1646 << std::endl;
1647#endif
1648
1649 unsigned update_id =
1651
1652 Vector<double> ref_value;
1653
1654 // The size of this vector is in the next entry
1655 // of All_alg_nodal_info
1656#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1658 << " Alg node # of ref values "
1660 << std::endl;
1661#endif
1662 unsigned n_ref_val =
1664
1665 // The reference values themselves are in
1666 // All_alg_ref_value
1667 ref_value.resize(n_ref_val);
1668 for (unsigned i_ref = 0; i_ref < n_ref_val; i_ref++)
1669 {
1670 ref_value[i_ref] =
1672 }
1673
1674 Vector<GeomObject*> geom_object_pt;
1675 /// again we need the size of this vector as it varies
1676 /// between meshes; we also need some indication
1677 /// as to which geometric object should be used...
1678
1679 // The size of this vector is in the next entry
1680 // of All_alg_nodal_info
1681#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1683 << " Alg node # of geom objects "
1685 << std::endl;
1686#endif
1687 unsigned n_geom_obj =
1689
1690 // The remaining indices are in the rest of
1691 // All_alg_nodal_info
1692 geom_object_pt.resize(n_geom_obj);
1693 for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
1694 {
1695#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1697 << " Alg node: geom object index "
1699 << std::endl;
1700#endif
1701 unsigned geom_index =
1703 // This index indicates which of the AlgebraicMesh's
1704 // stored geometric objects should be used
1705 // (0 is a null pointer; everything else should have
1706 // been filled in by the specific Mesh). If it
1707 // hasn't been filled in then the update_node_update
1708 // call should fix it
1709 geom_object_pt[i_geom] = alg_mesh_pt->geom_object_list_pt(geom_index);
1710 }
1711
1712 /// For the received update_id, ref_value, geom_object
1713 /// call add_node_update_info
1714 new_alg_nod_pt->add_node_update_info(
1715 update_id, alg_mesh_pt, geom_object_pt, ref_value);
1716
1717 /// Now call update_node_update
1718 alg_mesh_pt->update_node_update(new_alg_nod_pt);
1719 }
1720
1721 // Is the node a MacroElementNodeUpdateNode?
1722 MacroElementNodeUpdateNode* macro_nod_pt =
1723 dynamic_cast<MacroElementNodeUpdateNode*>(new_nod_pt);
1724
1725 if (macro_nod_pt != 0)
1726 {
1727 // Need to call set_node_update_info; this requires
1728 // a Vector<GeomObject*> (taken from the mesh)
1729 Vector<GeomObject*> geom_object_vector_pt;
1730
1731 // Access the required geom objects from the
1732 // MacroElementNodeUpdateMesh
1733 MacroElementNodeUpdateMesh* macro_mesh_pt =
1734 dynamic_cast<MacroElementNodeUpdateMesh*>(external_mesh_pt);
1735 geom_object_vector_pt = macro_mesh_pt->geom_object_vector_pt();
1736
1737 // Get local coordinate of node in new element
1738 Vector<double> s_in_macro_node_update_element;
1739 new_el_pt->local_coordinate_of_node(node_index,
1740 s_in_macro_node_update_element);
1741
1742 // Set node update info for this node
1743 macro_nod_pt->set_node_update_info(
1744 new_el_pt, s_in_macro_node_update_element, geom_object_vector_pt);
1745 }
1746
1747 // Is the new node a SolidNode?
1748 SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(new_nod_pt);
1749 if (solid_nod_pt != 0)
1750 {
1751 unsigned n_solid_val = solid_nod_pt->variable_position_pt()->nvalue();
1752 for (unsigned i_val = 0; i_val < n_solid_val; i_val++)
1753 {
1754 for (unsigned t = 0; t < n_prev; t++)
1755 {
1756 solid_nod_pt->variable_position_pt()->set_value(
1758 }
1759 }
1760 }
1761
1762 // If there are additional values, resize the node
1763 unsigned n_new_val = new_nod_pt->nvalue();
1764 if (n_val > n_new_val)
1765 {
1766 new_nod_pt->resize(n_val);
1767 }
1768
1769 // Get copied history values
1770 // unsigned n_val=new_nod_pt->nvalue();
1771 for (unsigned i_val = 0; i_val < n_val; i_val++)
1772 {
1773 for (unsigned t = 0; t < n_prev; t++)
1774 {
1775 new_nod_pt->set_value(
1777 }
1778 }
1779
1780 // Get copied history values for positions
1781 unsigned n_dim = new_nod_pt->ndim();
1782 for (unsigned idim = 0; idim < n_dim; idim++)
1783 {
1784 for (unsigned t = 0; t < n_prev; t++)
1785 {
1786 // Copy to coordinate
1787 new_nod_pt->x(t, idim) =
1789 }
1790 }
1791 }
1792
1793
1794 //=====================================================================
1795 /// Locate zeta for current set of missing coordinates; vector-based version
1796 //=====================================================================
1798 int& iproc,
1799 Mesh* const& external_mesh_pt,
1800 Problem* problem_pt,
1801 Vector<MeshAsGeomObject*>& mesh_geom_obj_pt)
1802 {
1803 // How many meshes are we dealing with?
1804 unsigned n_mesh = mesh_geom_obj_pt.size();
1805
1806 // Storage for number of processors, current process and communicator
1807 OomphCommunicator* comm_pt = problem_pt->communicator_pt();
1808 int n_proc = comm_pt->nproc();
1809 int my_rank = comm_pt->my_rank();
1810
1811 // Clear vectors containing data to be sent
1812 Flat_packed_doubles.resize(0);
1813#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1815#endif
1816 Flat_packed_unsigneds.resize(0);
1818
1819 // Flush storage for zetas not found locally (when
1820 // processing the zeta coordinates received from "previous"
1821 // processor)
1823
1824 // Number of zeta tuples to be dealt with (includes padding!)
1825 unsigned n_zeta = Received_flat_packed_zetas_to_be_found.size() / Dim;
1826
1827 // Create storage for the processor id (plus one) on which
1828 // the zetas stored in Flat_packed_zetas_not_found_locally[...]
1829 // were located. (Remains zero for padded entries).
1830 Proc_id_plus_one_of_external_element.resize(n_zeta, 0);
1831
1832 // Create storage for the status of the (external halo) element associated
1833 // the zetas stored in Flat_packed_zetas_not_found_locally[...].
1834 // It either hasn't been found, already exists on the processor
1835 // that needs it, or needs to be newly created. (Remains Not_found
1836 // for padded entries).
1837 Located_element_status.resize(n_zeta, Not_found);
1838
1839 // Counter for flat-packed array of external zeta coordinates
1840 unsigned count = 0;
1841
1842 // Current mesh
1843 unsigned i_mesh = 0;
1844
1845 // Loop over the zeta tuples that we received from elsewhere and
1846 // are trying to find here for current mesh
1847 for (unsigned i = 0; i < n_zeta; i++)
1848 {
1849 // Storage for global coordinates to be located
1850 Vector<double> x_global(Dim);
1851
1852 // Loop to fill in coordinates
1853 for (unsigned ii = 0; ii < Dim; ii++)
1854 {
1855 x_global[ii] = Received_flat_packed_zetas_to_be_found[count];
1856 count++;
1857 }
1858
1859 // Check if we've reached the end of the mesh
1860 bool reached_end_of_mesh = false;
1861 unsigned dbl_max_count = 0;
1862 for (unsigned ii = 0; ii < Dim; ii++)
1863 {
1864 if (x_global[ii] == DBL_MAX)
1865 {
1866 dbl_max_count++;
1867 reached_end_of_mesh = true;
1868 }
1869 }
1870
1871 // Reached end of mesh
1872 if (reached_end_of_mesh)
1873 {
1874#ifdef PARANOID
1875 // Check if all coordinates were set to DBX_MAX
1876 if (dbl_max_count != Dim)
1877 {
1878 std::ostringstream error_stream;
1879 error_stream << "Appear to have reached end of mesh " << i_mesh
1880 << " but only " << dbl_max_count << " out of " << Dim
1881 << " zeta coordinates have been set to DBX_MAX\n";
1882 throw OomphLibError(error_stream.str(),
1883 OOMPH_CURRENT_FUNCTION,
1884 OOMPH_EXCEPTION_LOCATION);
1885 }
1886#endif
1887 // Indicate end of mesh in flat packed data
1888 for (unsigned ii = 0; ii < Dim; ii++)
1889 {
1890 Flat_packed_zetas_not_found_locally.push_back(DBL_MAX);
1891 }
1892
1893 // Bump mesh counter
1894 i_mesh++;
1895
1896 // Bail out if we're done
1897 if (i_mesh == n_mesh)
1898 {
1899 return;
1900 }
1901 }
1902
1903 // Perform locate_zeta for these coordinates and current mesh
1904 GeomObject* sub_geom_obj_pt = 0;
1905 Vector<double> ss(Dim);
1906 if (!reached_end_of_mesh)
1907 {
1908 mesh_geom_obj_pt[i_mesh]->locate_zeta(x_global, sub_geom_obj_pt, ss);
1909
1910 // Did the locate method work?
1911 if (sub_geom_obj_pt != 0)
1912 {
1913 // Get the source element - bulk or not?
1914 GeneralisedElement* source_el_pt = 0;
1916 {
1917 source_el_pt = dynamic_cast<FiniteElement*>(sub_geom_obj_pt);
1918 }
1919 else
1920 {
1921 FaceElement* face_el_pt =
1922 dynamic_cast<FaceElement*>(sub_geom_obj_pt);
1923 source_el_pt =
1924 dynamic_cast<FiniteElement*>(face_el_pt->bulk_element_pt());
1925 }
1926
1927 // Check if the returned element is halo
1928 if (!source_el_pt->is_halo()) // cannot accept halo here
1929 {
1930 // The correct non-halo element has been located; this will become
1931 // an external haloed element on the current process, and an
1932 // external halo copy needs to be created on the current process
1933 // minus wherever we are in the "ring-loop"
1934 int halo_copy_proc = my_rank - iproc;
1935
1936 // If iproc is bigger than my_rank then we've "gone through"
1937 // nproc-1
1938 if (my_rank < iproc)
1939 {
1940 halo_copy_proc = n_proc + halo_copy_proc;
1941 }
1942
1943 // So, we found zeta on the current processor
1945
1946 // This source element is an external halo on process
1947 // halo_copy_proc but it should only be added to the storage if it
1948 // hasn't been added already, and this information also needs to
1949 // be communicated over to the other process
1950
1951 unsigned n_extern_haloed =
1952 external_mesh_pt->nexternal_haloed_element(halo_copy_proc);
1953 unsigned external_haloed_el_index =
1954 external_mesh_pt->add_external_haloed_element_pt(halo_copy_proc,
1955 source_el_pt);
1956
1957 // If it was added to the storage then the returned index
1958 // will be the same as the (old) size of the storage
1959 if (external_haloed_el_index == n_extern_haloed)
1960 {
1961 // Set Located_element_status to say it
1962 // should be newly created
1964
1965 // How many continuously interpolated values are there?
1966 int n_cont_inter_values = -1;
1967 if (dynamic_cast<RefineableElement*>(source_el_pt) != 0)
1968 {
1969 n_cont_inter_values =
1970 dynamic_cast<RefineableElement*>(source_el_pt)
1971 ->ncont_interpolated_values();
1972 }
1973
1974 // Since it is (externally) haloed from the current process,
1975 // the info required to create a new element in the equivalent
1976 // external halo layer on process halo_copy_proc needs to be
1977 // sent there
1978
1979 // If we're using macro elements to update...
1980 MacroElementNodeUpdateMesh* macro_mesh_pt =
1981 dynamic_cast<MacroElementNodeUpdateMesh*>(external_mesh_pt);
1982 if (macro_mesh_pt != 0)
1983 {
1984 Flat_packed_unsigneds.push_back(1);
1985#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1987 "Mesh is macro element mesh[2]");
1988#endif
1989 // Cast to finite element... this must work because it's
1990 // a macroelement no update mesh
1991 FiniteElement* source_finite_el_pt =
1992 dynamic_cast<FiniteElement*>(source_el_pt);
1993
1994 MacroElement* macro_el_pt =
1995 source_finite_el_pt->macro_elem_pt();
1996 // Send the macro element number across
1997 unsigned macro_el_num = macro_el_pt->macro_element_number();
1998 Flat_packed_unsigneds.push_back(macro_el_num);
1999#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2001 "Number of macro element[2]");
2002#endif
2003 // we need to send
2004 // the lower left and upper right coordinates of the macro
2005 QElementBase* q_el_pt =
2006 dynamic_cast<QElementBase*>(source_el_pt);
2007 if (q_el_pt != 0)
2008 {
2009 // The macro element needs to be set first before
2010 // its lower left and upper right coordinates can be
2011 // accessed Now send the lower left and upper right
2012 // coordinates
2013 unsigned el_dim = q_el_pt->dim();
2014 for (unsigned i_dim = 0; i_dim < el_dim; i_dim++)
2015 {
2016 Flat_packed_doubles.push_back(q_el_pt->s_macro_ll(i_dim));
2017 Flat_packed_doubles.push_back(q_el_pt->s_macro_ur(i_dim));
2018 }
2019 }
2020 else // Throw an error
2021 {
2022 std::ostringstream error_stream;
2023 error_stream
2024 << "You are using a MacroElement node update\n"
2025 << "in a case with non-QElements. This has not\n"
2026 << "yet been implemented.\n";
2027 throw OomphLibError(error_stream.str(),
2028 OOMPH_CURRENT_FUNCTION,
2029 OOMPH_EXCEPTION_LOCATION);
2030 }
2031 }
2032 else // Not using macro elements to update
2033 {
2034 Flat_packed_unsigneds.push_back(0);
2035#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2037 "Mesh is not a macro element mesh [2]");
2038#endif
2039 }
2040
2041
2042 // Cast to finite element... this must work because it's
2043 // a macroelement no update mesh
2044 FiniteElement* source_finite_el_pt =
2045 dynamic_cast<FiniteElement*>(source_el_pt);
2046#ifdef PARANOID
2047 if (source_finite_el_pt == 0)
2048 {
2049 throw OomphLibError(
2050 "Unable to cast source function to finite element\n",
2051 "Multi_domain_functions::locate_zeta_for_missing_"
2052 "coordinates()",
2053 OOMPH_EXCEPTION_LOCATION);
2054 }
2055#endif
2056
2057
2058 // Loop over the nodes of the new source element
2059 unsigned n_node = source_finite_el_pt->nnode();
2060 for (unsigned j = 0; j < n_node; j++)
2061 {
2062 Node* nod_pt = source_finite_el_pt->node_pt(j);
2063
2064 // Add the node to the storage; this routine
2065 // also takes care of any master nodes if the
2066 // node is hanging
2068 nod_pt,
2069 problem_pt,
2070 external_mesh_pt,
2071 n_cont_inter_values);
2072 }
2073 }
2074 else // it has already been added, so tell the other process
2075 {
2076 // Set Located_element_status to indicate an element has
2077 // already been added
2079 Flat_packed_unsigneds.push_back(external_haloed_el_index);
2080#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2082 "Index of existing external haloed element[2]");
2083#endif
2084 }
2085
2086 // The coordinates returned by locate_zeta are also needed
2087 // in the setup of the source elements on the other process
2089 {
2090 for (unsigned ii = 0; ii < Dim; ii++)
2091 {
2092 Flat_packed_located_coordinates.push_back(ss[ii]);
2093 }
2094 }
2095 else // translate the coordinates to the bulk element
2096 {
2097 // The translation is from Lagrangian to Eulerian
2098 FaceElement* face_el_pt =
2099 dynamic_cast<FaceElement*>(sub_geom_obj_pt);
2100 // Get the dimension of the BulkElement
2101 unsigned bulk_el_dim =
2102 dynamic_cast<FiniteElement*>(source_el_pt)->dim();
2103 Vector<double> s_trans(bulk_el_dim);
2104 face_el_pt->get_local_coordinate_in_bulk(ss, s_trans);
2105 for (unsigned ii = 0; ii < bulk_el_dim; ii++)
2106 {
2107 Flat_packed_located_coordinates.push_back(s_trans[ii]);
2108 }
2109 }
2110 }
2111 else // halo, so search again until non-halo equivalent is located
2112 {
2113 // Add required information to arrays (as below)
2114 for (unsigned ii = 0; ii < Dim; ii++)
2115 {
2116 Flat_packed_zetas_not_found_locally.push_back(x_global[ii]);
2117 }
2118 // It wasn't found here
2120
2121 // Set Located_element_status to indicate not found
2123 }
2124 }
2125 else // not successful this time (i.e. sub_geom_obj_pt==0), so
2126 // prepare for next process to try
2127 {
2128 // Add this global coordinate to the LOCAL zeta array
2129 for (unsigned ii = 0; ii < Dim; ii++)
2130 {
2131 Flat_packed_zetas_not_found_locally.push_back(x_global[ii]);
2132 }
2133 // It wasn't found here
2135
2136 // Set Located_element_status to indicate not found
2138 }
2139
2140 } // end of mesh not reached
2141
2142 } // end of loop over flat-packed zeta tuples
2143 }
2144
2145
2146#endif
2147
2148
2149 //=====================================================================
2150 /// locate zeta for current set of "local" coordinates
2151 /// vector-based version
2152 //=====================================================================
2154 const Vector<Mesh*>& mesh_pt,
2155 Mesh* const& external_mesh_pt,
2156 Vector<MeshAsGeomObject*>& mesh_geom_obj_pt,
2157 const unsigned& interaction_index)
2158 {
2159 // Flush storage for zetas not found locally
2161
2162 // Number of meshes
2163 unsigned n_mesh = mesh_pt.size();
2164
2165#ifdef PARANOID
2166 if (mesh_geom_obj_pt.size() != n_mesh)
2167 {
2168 std::ostringstream error_stream;
2169 error_stream << "Sizes of mesh_geom_obj_pt [ "
2170 << mesh_geom_obj_pt.size() << " ] and "
2171 << "mesh_pt [ " << n_mesh << " ] don't match.\n";
2172 throw OomphLibError(
2173 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2174 }
2175#endif
2176
2177 // Element counter
2178 unsigned e_count = 0;
2179
2180 // Loop over meshes
2181 for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
2182 {
2183 // Number of local elements
2184 unsigned n_element = mesh_pt[i_mesh]->nelement();
2185
2186 // Loop over this processor's elements
2187 for (unsigned e = 0; e < n_element; e++)
2188 {
2190 dynamic_cast<ElementWithExternalElement*>(
2191 mesh_pt[i_mesh]->element_pt(e));
2192#ifdef OOMPH_HAS_MPI
2193 // Only visit non-halo elements -- we're not setting up external
2194 // elements for on-halos!
2195 if (!el_pt->is_halo())
2196#endif
2197 {
2198 // Find number of Gauss points and element dimension
2199 unsigned n_intpt = el_pt->integral_pt()->nweight();
2200 unsigned el_dim = el_pt->dim();
2201
2202
2203#ifdef PARANOID
2204 if (el_dim != Dim)
2205 {
2206 std::ostringstream error_stream;
2207 error_stream << "Dimension of element " << el_dim
2208 << " is not consitent with dimension assumed \n"
2209 << " in multidomain namespace, " << Dim << std::endl;
2210 throw OomphLibError(error_stream.str(),
2211 OOMPH_CURRENT_FUNCTION,
2212 OOMPH_EXCEPTION_LOCATION);
2213 }
2214#endif
2215
2216 // Set storage for local and global coordinates
2217 Vector<double> s_local(el_dim);
2218 Vector<double> x_global(el_dim);
2219
2220 // Loop over integration points
2221 for (unsigned ipt = 0; ipt < n_intpt; ipt++)
2222 {
2223 // Has this integration point been done yet?
2224 if (External_element_located[e_count][ipt] == 0)
2225 {
2226 // Get local coordinates
2227 for (unsigned i = 0; i < el_dim; i++)
2228 {
2229 s_local[i] = el_pt->integral_pt()->knot(ipt, i);
2230 }
2231 // Interpolate to global coordinates
2232 el_pt->interpolated_zeta(s_local, x_global);
2233
2234 // Storage for geometric object and its local coordinates
2235 GeomObject* sub_geom_obj_pt = 0;
2236 Vector<double> s_ext(el_dim);
2237 mesh_geom_obj_pt[i_mesh]->locate_zeta(
2238 x_global, sub_geom_obj_pt, s_ext);
2239
2240 // Has the required element been located?
2241 if (sub_geom_obj_pt != 0)
2242 {
2243 // The required element has been located
2244 // The located coordinates have the same dimension as the bulk
2245 GeneralisedElement* source_el_pt;
2246 Vector<double> s_source(el_dim);
2247
2248 // Is the bulk element the actual external element?
2250 {
2251 // Use the object directly (it must be a finite element)
2252 source_el_pt =
2253 dynamic_cast<FiniteElement*>(sub_geom_obj_pt);
2254 s_source = s_ext;
2255 }
2256 else
2257 {
2258 // Cast to a FaceElement and use the bulk element
2259 FaceElement* face_el_pt =
2260 dynamic_cast<FaceElement*>(sub_geom_obj_pt);
2261 source_el_pt = face_el_pt->bulk_element_pt();
2262
2263 // Need to resize the located coordinates to have the same
2264 // dimension as the bulk element
2265 s_source.resize(
2266 dynamic_cast<FiniteElement*>(source_el_pt)->dim());
2267
2268 // Translate the returned local coords into the bulk element
2269 face_el_pt->get_local_coordinate_in_bulk(s_ext, s_source);
2270 }
2271
2272 // Check if it's a halo; if it is then the non-halo equivalent
2273 // needs to be located from another processor (unless we
2274 // accept halo elements as external elements)
2275#ifdef OOMPH_HAS_MPI
2277 (!source_el_pt->is_halo()))
2278#endif
2279 {
2280 // Need to cast to a FiniteElement
2281 FiniteElement* source_finite_el_pt =
2282 dynamic_cast<FiniteElement*>(source_el_pt);
2283
2284 // Set the external element pointer and local coordinates
2285 el_pt->external_element_pt(interaction_index, ipt) =
2286 source_finite_el_pt;
2287 el_pt->external_element_local_coord(interaction_index,
2288 ipt) = s_source;
2289
2290 // Set the lookup array to 1/true
2291 External_element_located[e_count][ipt] = 1;
2292 }
2293#ifdef OOMPH_HAS_MPI
2294 // located element is halo and we're not accepting haloes
2295 // obviously only makes sense in mpi mode...
2296 else
2297 {
2298 // Add required information to arrays
2299 for (unsigned i = 0; i < el_dim; i++)
2300 {
2302 x_global[i]);
2303 }
2304 }
2305#endif
2306 }
2307 else
2308 {
2309 // Search has failed then add the required information to the
2310 // arrays which need to be sent to the other processors so
2311 // that they can perform the locate_zeta
2312
2313 // Add this global coordinate to the LOCAL zeta array
2314 for (unsigned i = 0; i < el_dim; i++)
2315 {
2316 Flat_packed_zetas_not_found_locally.push_back(x_global[i]);
2317 }
2318 }
2319 }
2320 } // end loop over integration points
2321 } // end for halo
2322
2323 // Bump up counter for all elements
2324 e_count++;
2325
2326 } // end loop over local elements
2327
2328 // Mark end of mesh data in flat packed array
2329 for (unsigned i = 0; i < Dim; i++)
2330 {
2331 Flat_packed_zetas_not_found_locally.push_back(DBL_MAX);
2332 }
2333
2334 } // end of loop over meshes
2335 }
2336
2337
2338 //=====================================================================
2339 /// Helper function that computes the dimension of the elements within
2340 /// each of the specified meshes (and checks they are the same).
2341 /// Stores result in Dim.
2342 //=====================================================================
2343 void get_dim_helper(Problem* problem_pt,
2344 Mesh* const& mesh_pt,
2345 Mesh* const& external_mesh_pt)
2346 {
2347#ifdef OOMPH_HAS_MPI
2348 // Storage for number of processors, current process and communicator
2349 OomphCommunicator* comm_pt = problem_pt->communicator_pt();
2350#endif
2351
2352 // Extract the element dimensions from the first element of each mesh
2353 unsigned mesh_dim = 0;
2354 if (mesh_pt->nelement() > 0)
2355 {
2356 mesh_dim = dynamic_cast<FiniteElement*>(mesh_pt->element_pt(0))->dim();
2357 }
2358 unsigned external_mesh_dim = 0;
2359 if (external_mesh_pt->nelement() > 0)
2360 {
2361 external_mesh_dim =
2362 dynamic_cast<FiniteElement*>(external_mesh_pt->element_pt(0))->dim();
2363 }
2364
2365 // Need to do an Allreduce
2366#ifdef OOMPH_HAS_MPI
2367 int n_proc = comm_pt->nproc();
2368 if (n_proc > 1)
2369 {
2370 unsigned mesh_dim_reduce;
2371 MPI_Allreduce(&mesh_dim,
2372 &mesh_dim_reduce,
2373 1,
2374 MPI_UNSIGNED,
2375 MPI_MAX,
2376 comm_pt->mpi_comm());
2377 mesh_dim = mesh_dim_reduce;
2378
2379 unsigned external_mesh_dim_reduce;
2380 MPI_Allreduce(&external_mesh_dim,
2381 &external_mesh_dim_reduce,
2382 1,
2383 MPI_UNSIGNED,
2384 MPI_MAX,
2385 comm_pt->mpi_comm());
2386 external_mesh_dim = external_mesh_dim_reduce;
2387 }
2388#endif
2389
2390 // Check the dimensions are the same!
2391 if (mesh_dim != external_mesh_dim)
2392 {
2393 std::ostringstream error_stream;
2394 error_stream << "The elements within the two meshes do not\n"
2395 << "have the same dimension, so the multi-domain\n"
2396 << "method will not work.\n"
2397 << "For the mesh, dim=" << mesh_dim
2398 << ", and the external mesh, dim=" << external_mesh_dim
2399 << "\n";
2400 throw OomphLibError(
2401 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2402 }
2403
2404 // Set dimension
2405 Dim = mesh_dim;
2406 }
2407
2408
2409 //=================================================================
2410 /// Helper function that clears all the information used
2411 /// during the external storage creation
2412 //=================================================================
2414 {
2418 Located_element_status.clear();
2420 Flat_packed_doubles.clear();
2421 Flat_packed_unsigneds.clear();
2423 }
2424
2425 /// Vector of zeta coordinates that we're currently trying to locate;
2426 /// used in sorting of bin entries in further_away() comparison function
2428
2429 /// Comparison function for sorting entries in bin: Returns true if
2430 /// point identified by p1 (comprising pointer to finite element and
2431 /// vector of local coordinates within that element) is closer to
2432 /// Zeta_coords_for_further_away_comparison than p2
2434 const std::pair<FiniteElement*, Vector<double>>& p1,
2435 const std::pair<FiniteElement*, Vector<double>>& p2)
2436 {
2437 // First point
2438 FiniteElement* el_pt = p1.first;
2439 Vector<double> s(p1.second);
2440 Vector<double> zeta(Dim);
2441 el_pt->interpolated_zeta(s, zeta);
2442 double dist_squared1 = 0.0;
2443 for (unsigned i = 0; i < Dim; i++)
2444 {
2445 dist_squared1 +=
2448 }
2449
2450 // Second point
2451 el_pt = p2.first;
2452 s = p2.second;
2453 el_pt->interpolated_zeta(s, zeta);
2454 double dist_squared2 = 0.0;
2455 for (unsigned i = 0; i < Dim; i++)
2456 {
2457 dist_squared2 +=
2460 }
2461
2462 // Which one is further
2463 if (dist_squared1 < dist_squared2)
2464 {
2465 return true;
2466 }
2467 else
2468 {
2469 return false;
2470 }
2471 }
2472 } // namespace Multi_domain_functions
2473
2474} // namespace oomph
e
Definition: cfortran.h:571
static char t char * s
Definition: cfortran.h:568
cstr elem_len * i
Definition: cfortran.h:603
char t
Definition: cfortran.h:568
////////////////////////////////////////////////////////////////////
virtual void update_node_update(AlgebraicNode *&node_pt)=0
Update the node update info for given node, following mesh adaptation. Must be implemented for every ...
GeomObject * geom_object_list_pt(const unsigned &i)
Access function to the ith GeomObject.
unsigned ngeom_object_list_pt()
Return number of geometric objects associated with AlgebraicMesh.
////////////////////////////////////////////////////////////////////
unsigned ngeom_object(const int &id)
Number of geometric objects involved in id-th update function.
unsigned nref_value(const int &id)
Number of reference values involved in id-th update function.
GeomObject * geom_object_pt(const unsigned &i)
Return pointer to i-th geometric object involved in default (usually first) update function.
int node_update_fct_id()
Default (usually first if there are multiple ones) node update fct id.
double ref_value(const unsigned &i)
Return i-th reference value involved in default (usually first) update function.
void add_node_update_info(const int &id, AlgebraicMesh *mesh_pt, const Vector< GeomObject * > &geom_object_pt, const Vector< double > &ref_value, const bool &called_from_constructor=false)
Add algebraic update information for node: What's the ID of the mesh update function (typically used ...
A class that contains the information required by Nodes that are located on Mesh boundaries....
Definition: nodes.h:1996
std::map< unsigned, unsigned > *& index_of_first_value_assigned_by_face_element_pt()
Return pointer to the map giving the index of the first face element value.
Definition: nodes.h:2046
TimeStepper *& time_stepper_pt()
Return the pointer to the timestepper.
Definition: nodes.h:238
void set_value(const unsigned &i, const double &value_)
Set the i-th stored data value to specified value. The only reason that we require an explicit set fu...
Definition: nodes.h:271
unsigned nvalue() const
Return number of values stored in data object (incl pinned ones).
Definition: nodes.h:483
double value(const unsigned &i) const
Return i-th stored value. This function is not virtual so that it can be inlined. This means that if ...
Definition: nodes.h:293
This is a base class for all elements that require external sources (e.g. FSI, multi-domain problems ...
Vector< double > & external_element_local_coord(const unsigned &interaction_index, const unsigned &ipt)
Access function to get source element's local coords for specified interaction index at specified int...
FiniteElement *& external_element_pt(const unsigned &interaction_index, const unsigned &ipt)
Access function to source element for specified interaction index at specified integration point.
FaceElements are elements that coincide with the faces of higher-dimensional "bulk" elements....
Definition: elements.h:4338
FiniteElement *& bulk_element_pt()
Pointer to higher-dimensional "bulk" element.
Definition: elements.h:4735
void get_local_coordinate_in_bulk(const Vector< double > &s, Vector< double > &s_bulk) const
Calculate the vector of local coordinate in the bulk element given the local coordinates in this Face...
Definition: elements.cc:6384
A general Finite Element class.
Definition: elements.h:1313
Integral *const & integral_pt() const
Return the pointer to the integration scheme (const version)
Definition: elements.h:1963
virtual void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Get local coordinates of node j in the element; vector sets its own size (broken virtual)
Definition: elements.h:1842
void interpolated_zeta(const Vector< double > &s, Vector< double > &zeta) const
Calculate the interpolated value of zeta, the intrinsic coordinate of the element when viewed as a co...
Definition: elements.cc:4675
virtual Node * construct_node(const unsigned &n)
Construct the local node n and return a pointer to the newly created node object.
Definition: elements.h:2509
unsigned dim() const
Return the spatial dimension of the element, i.e. the number of local coordinates required to paramet...
Definition: elements.h:2611
unsigned nnode() const
Return the number of nodes.
Definition: elements.h:2210
MacroElement * macro_elem_pt()
Access function to pointer to macro element.
Definition: elements.h:1878
virtual Node * construct_boundary_node(const unsigned &n)
Construct the local node n as a boundary node; that is a node that MAY be placed on a mesh boundary a...
Definition: elements.h:2538
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2175
A Generalised Element class.
Definition: elements.h:73
bool is_halo() const
Is this element a halo?
Definition: elements.h:1163
/////////////////////////////////////////////////////////////////////
Definition: geom_objects.h:101
Class that contains data for hanging nodes.
Definition: nodes.h:742
Node *const & master_node_pt(const unsigned &i) const
Return a pointer to the i-th master node.
Definition: nodes.h:791
unsigned nmaster() const
Return the number of master nodes.
Definition: nodes.h:785
double const & master_weight(const unsigned &i) const
Return weight for dofs on i-th master node.
Definition: nodes.h:808
virtual double knot(const unsigned &i, const unsigned &j) const =0
Return local coordinate s[j] of i-th integration point.
virtual unsigned nweight() const =0
Return the number of integration points of the scheme.
MacroElementNodeUpdateMeshes contain MacroElementNodeUpdateNodes which have their own node update fun...
Vector< GeomObject * > geom_object_vector_pt()
Access function to the vector of GeomObject.
////////////////////////////////////////////////////////////////////
void set_node_update_info(FiniteElement *node_update_element_pt, const Vector< double > &s_in_node_update_element, const Vector< GeomObject * > &geom_object_pt)
Set node update information for node: Pass the pointer to the element that performs the update operat...
FiniteElement *& node_update_element_pt()
Pointer to finite element that performs the update by referring to its macro-element representation (...
Base class for MacroElement s that are used during mesh refinement in domains with curvlinear and/or ...
Definition: macro_element.h:73
unsigned & macro_element_number()
Access function to the Macro_element_number.
A general mesh class.
Definition: mesh.h:67
void add_boundary_node(const unsigned &b, Node *const &node_pt)
Add a (pointer to) a node to the b-th boundary.
Definition: mesh.cc:243
Node *& external_halo_node_pt(const unsigned &p, const unsigned &j)
Access fct to the j-th external halo node in this Mesh whose non-halo external counterpart is held on...
Definition: mesh.h:2377
unsigned nexternal_haloed_element()
Total number of external haloed elements in this Mesh.
Definition: mesh.h:2267
unsigned add_external_haloed_node_pt(const unsigned &p, Node *&nod_pt)
Add external haloed node whose halo (external) counterpart is held on processor p to the storage sche...
Definition: mesh.cc:9516
unsigned nboundary() const
Return number of boundaries.
Definition: mesh.h:827
unsigned add_external_haloed_element_pt(const unsigned &p, GeneralisedElement *&el_pt)
Add external haloed element whose non-halo counterpart is held on processor p to the storage scheme f...
Definition: mesh.cc:9475
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
Definition: mesh.h:448
void add_external_halo_node_pt(const unsigned &p, Node *&nod_pt)
Add external halo node whose non-halo (external) counterpart is held on processor p to the storage sc...
Definition: mesh.h:2368
unsigned nexternal_haloed_node()
Total number of external haloed nodes in this Mesh.
Definition: mesh.h:2412
unsigned long nelement() const
Return number of elements in the mesh.
Definition: mesh.h:590
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:906
virtual bool is_on_boundary() const
Test whether the Node lies on a boundary. The "bulk" Node cannot lie on a boundary,...
Definition: nodes.h:1373
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
Definition: nodes.h:1054
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition: nodes.h:1060
void resize(const unsigned &n_value)
Resize the number of equations.
Definition: nodes.cc:2167
unsigned nposition_type() const
Number of coordinate types needed in the mapping between local and global coordinates.
Definition: nodes.h:1016
bool is_hanging() const
Test whether the node is geometrically hanging.
Definition: nodes.h:1285
double value(const unsigned &i) const
Return i-th value (dofs or pinned) at this node either directly or via hanging node representation....
Definition: nodes.cc:2408
HangInfo *const & hanging_pt() const
Return pointer to hanging node data (this refers to the geometric hanging node status) (const version...
Definition: nodes.h:1228
An oomph-lib wrapper to the MPI_Comm communicator object. Just contains an MPI_Comm object (which is ...
Definition: communicator.h:54
An OomphLibError object which should be thrown when an run-time error is encountered....
////////////////////////////////////////////////////////////////// //////////////////////////////////...
Definition: problem.h:151
OomphCommunicator * communicator_pt()
access function to the oomph-lib communicator
Definition: problem.h:1246
TimeStepper *& time_stepper_pt()
Access function for the pointer to the first (presumably only) timestepper.
Definition: problem.h:1524
unsigned ntime_stepper() const
Return the number of time steppers.
Definition: problem.h:1680
/////////////////////////////////////////////////////////////////// /////////////////////////////////...
Definition: Qelements.h:91
double & s_macro_ur(const unsigned &i)
Access fct to the i-th coordinate of the element's "upper right" vertex in the associated MacroElemen...
Definition: Qelements.h:202
double & s_macro_ll(const unsigned &i)
Access fct to the i-th coordinate of the element's "lower left" vertex in the associated MacroElement...
Definition: Qelements.h:186
RefineableElements are FiniteElements that may be subdivided into children to provide a better local ...
A Class for nodes that deform elastically (i.e. position is an unknown in the problem)....
Definition: nodes.h:1686
Data *const & variable_position_pt() const
Pointer to variable_position data (const version)
Definition: nodes.h:1765
unsigned nlagrangian_type() const
Number of types of Lagrangian coordinates used to interpolate the Lagrangian coordinates within the e...
Definition: nodes.h:1877
unsigned nlagrangian() const
Return number of lagrangian coordinates.
Definition: nodes.h:1870
////////////////////////////////////////////////////////////////////// //////////////////////////////...
Definition: timesteppers.h:231
unsigned ntstorage() const
Return the number of doubles required to represent history (one for steady)
Definition: timesteppers.h:601
A slight extension to the standard template vector class so that we can include "graceful" array rang...
Definition: Vector.h:58
Vector< int > Proc_id_plus_one_of_external_element
Proc_id_plus_one_of_external_element[i] contains the processor id (plus one) of the processor on whic...
Definition: multi_domain.cc:91
Vector< double > Flat_packed_located_coordinates
Vector of flat-packed local coordinates for zeta tuples that have been located.
void send_and_receive_located_info(int &iproc, Mesh *const &external_mesh_pt, Problem *problem_pt)
Send location information from current process; Received location information from (current process +...
unsigned Counter_for_flat_packed_unsigneds
Counter used when processing vector of flat-packed unsigneds – this is really "private" data,...
Vector< Vector< unsigned > > External_element_located
Lookup scheme for whether a local element's integration point has had an external element assigned to...
Definition: multi_domain.cc:68
unsigned Dim
Dimension of zeta tuples (set by get_dim_helper) – needed because we store the scalar coordinates in ...
Definition: multi_domain.cc:60
Vector< double > Flat_packed_doubles
Vector of flat-packed doubles to be communicated with other processors.
void send_and_receive_missing_zetas(Problem *problem_pt)
Send the zeta coordinates from the current process to the next process; receive from the previous pro...
void get_required_master_nodal_information_helper(int &iproc, Node *master_nod_pt, Problem *problem_pt, Mesh *const &external_mesh_pt, int &n_cont_inter_values)
Helper function to get the required master nodal information from an external haloed master node so t...
void clean_up()
Helper function that clears all the information used during the external storage creation.
Vector< unsigned > Flat_packed_unsigneds
Vector of flat-packed unsigneds to be communicated with other processors – this is really "private" d...
Vector< double > Zeta_coords_for_further_away_comparison
Vector of zeta coordinates that we're currently trying to locate; used in sorting of bin entries in f...
bool Doc_timings
Boolean to indicate whether to doc timings or not.
void add_external_haloed_master_node_helper(int &iproc, Node *master_nod_pt, Problem *problem_pt, Mesh *const &external_mesh_pt, int &n_cont_inter_values)
Helper function to add external haloed node that is a master.
void get_dim_helper(Problem *problem_pt, Mesh *const &mesh_pt, Mesh *const &external_mesh_pt)
Helper function that computes the dimension of the elements within each of the specified meshes (and ...
std::ofstream Doc_boundary_coordinate_file
Output file to document the boundary coordinate along the mesh boundary of the bulk mesh during call ...
Definition: multi_domain.cc:47
Vector< double > Flat_packed_zetas_not_found_locally
Vector of flat-packed zeta coordinates for which the external element could not be found during curre...
Definition: multi_domain.cc:74
Vector< std::string > Flat_packed_unsigneds_string
void locate_zeta_for_local_coordinates(const Vector< Mesh * > &mesh_pt, Mesh *const &external_mesh_pt, Vector< MeshAsGeomObject * > &mesh_geom_obj_pt, const unsigned &interaction_index)
locate zeta for current set of "local" coordinates vector-based version
void construct_new_external_halo_node_helper(Node *&new_nod_pt, unsigned &loc_p, unsigned &node_index, FiniteElement *const &new_el_pt, Mesh *const &external_mesh_pt, Problem *problem_pt)
Helper function which constructs a new external halo node (on new element) with the required informat...
bool Allow_use_of_halo_elements_as_external_elements
Boolean to indicate if we're allowed to use halo elements as external elements. Can drastically reduc...
bool Allow_use_of_halo_elements_as_external_elements_for_projection
Indicate whether we are allowed to use halo elements as external elements for projection,...
bool Doc_stats
Boolean to indicate whether to output basic info during setup_multi_domain_interaction() routines.
bool Doc_full_stats
Boolean to indicate whether to output further info during setup_multi_domain_interaction() routines.
Vector< double > Received_flat_packed_zetas_to_be_found
Vector of flat-packed zeta coordinates for which the external element could not be found on another p...
Definition: multi_domain.cc:82
void add_external_haloed_node_helper(int &iproc, Node *nod_pt, Problem *problem_pt, Mesh *const &external_mesh_pt, int &n_cont_inter_values)
Helper to add external haloed node that is not a master.
void get_required_nodal_information_helper(int &iproc, Node *nod_pt, Problem *problem_pt, Mesh *const &external_mesh_pt, int &n_cont_inter_values)
Helper function to get the required nodal information from an external haloed node so that a fully-fu...
void recursively_add_masters_of_external_haloed_node(int &iproc, Node *nod_pt, Problem *problem_pt, Mesh *const &external_mesh_pt, int &n_cont_inter_values)
Recursively add any master nodes (and their master nodes etc) of external nodes.
void add_external_halo_node_helper(Node *&new_nod_pt, Mesh *const &external_mesh_pt, unsigned &loc_p, unsigned &node_index, FiniteElement *const &new_el_pt, int &n_cont_inter_values, Problem *problem_pt)
Helper functiono to add external halo node that is not a master.
bool Use_bulk_element_as_external
Boolean to indicate when to use the bulk element as the external element. Defaults to false,...
Vector< unsigned > Located_element_status
Vector to indicate (to another processor) whether a located element (that will have to represented as...
Definition: multi_domain.cc:98
void add_external_haloed_node_to_storage(int &iproc, Node *nod_pt, Problem *problem_pt, Mesh *const &external_mesh_pt, int &n_cont_inter_values)
Helper function to add external haloed nodes, including any masters.
unsigned Counter_for_flat_packed_doubles
Counter used when processing vector of flat-packed doubles – this is really "private" data,...
bool first_closer_than_second(const std::pair< FiniteElement *, Vector< double > > &p1, const std::pair< FiniteElement *, Vector< double > > &p2)
Comparison function for sorting entries in bin: Returns true if point identified by p1 (comprising po...
void locate_zeta_for_missing_coordinates(int &iproc, Mesh *const &external_mesh_pt, Problem *problem_pt, Vector< MeshAsGeomObject * > &mesh_geom_obj_pt)
Locate zeta for current set of missing coordinates; vector-based version.
bool Accept_failed_locate_zeta_in_setup_multi_domain_interaction
Boolean to indicate that failure in setup multi domain functions is acceptable; defaults to false....
Definition: multi_domain.cc:56
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...