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-2025 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"
31#include "mesh.h"
32#include "algebraic_elements.h"
34#include "Qelements.h"
35
36namespace oomph
37{
38 //======================================================================
39 // Namespace for "global" multi-domain functions
40 //======================================================================
41 namespace Multi_domain_functions
42 {
43 /// Output file to document the boundary coordinate
44 /// along the mesh boundary of the bulk mesh during call to
45 /// setup_bulk_elements_adjacent_to_face_mesh(...)
47
48 // Workspace for locate zeta methods
49 //----------------------------------
50
51 /// Boolean to indicate that failure in setup multi domain
52 /// functions is acceptable; defaults to false. If set to true
53 /// external element pointers are set to null for those elements
54 /// for which external elements couldn't be located.
56
57 /// Dimension of zeta tuples (set by get_dim_helper) -- needed
58 /// because we store the scalar coordinates in flat-packed form.
59 unsigned Dim;
60
61 /// Lookup scheme for whether a local element's integration point
62 /// has had an external element assigned to it -- essentially boolean.
63 /// External_element_located[e][ipt] = {0,1} if external element
64 /// for ipt-th integration in local element e {has not, has} been found.
65 /// Used locally to ensure that we're not searching for the same
66 /// elements over and over again when we go around the spirals.
68
69 /// Vector of flat-packed zeta coordinates for which the external
70 /// element could not be found during current local search. These
71 /// will be sent to the next processor in the ring-like parallel search.
72 /// The zeta coordinates come in groups of Dim (scalar) coordinates.
74
75 /// Vector of flat-packed zeta coordinates for which the external
76 /// element could not be found on another processor and for which
77 /// we're currently searching here. Whatever can't be found here,
78 /// gets written into Flat_packed_zetas_not_found_locally and then
79 /// passed on to the next processor during the ring-like parallel search.
80 /// The zeta coordinates come in groups of Dim (scalar) coordinates.
82
83 /// Proc_id_plus_one_of_external_element[i] contains the
84 /// processor id (plus one) of the processor
85 /// on which the i-th zeta coordinate tuple received from elsewhere
86 /// (in the order in which these are stored in
87 /// Received_flat_packed_zetas_to_be_found) was located; it's zero if
88 /// it wasn't found during the current stage of the ring-like parallel
89 /// search.
91
92 /// Vector to indicate (to another processor) whether a
93 /// located element (that will have to represented as an external
94 /// halo element on that processor) should be newly created on that
95 /// processor (2), already exists on that processor (1), or
96 /// is not on the current processor either (0).
98
99 /// Vector of flat-packed local coordinates for zeta tuples
100 /// that have been located
102
103 /// Vector of flat-packed doubles to be communicated with
104 /// other processors
106
107 /// Counter used when processing vector of flat-packed
108 /// doubles -- this is really "private" data, declared here
109 /// to avoid having to pass it (and the associated array)
110 /// between the various helper functions
112
113 /// Vector of flat-packed unsigneds to be communicated with
114 /// other processors -- this is really "private" data, declared here
115 /// to avoid having to pass the array between the various helper
116 /// functions
118
119#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
120
121 // Temporary vector of strings to enable full annotation of multi domain
122 // comms (but keep alive because it would be such a bloody pain to
123 // rewrite it if things ever go wrong again...)
125
126
127#endif
128
129 /// Counter used when processing vector of flat-packed
130 /// unsigneds -- this is really "private" data, declared here
131 /// to avoid having to pass it (and the associated array)
132 /// between the various helper functions
134
135 // Other parameters
136 //-----------------
137
138 /// Boolean to indicate when to use the bulk element as the
139 /// external element. Defaults to false, you must have set up FaceElements
140 /// properly first in order for it to work
142
143 /// Boolean to indicate if we're allowed to use halo elements
144 /// as external elements. Can drastically reduce the number of
145 /// external halo elements -- currently not aware of any problems
146 /// therefore set to true by default but retention
147 /// of this flag allows easy return to previous implementation.
149
150 /// Indicate whether we are allowed to use halo elements as
151 /// external elements for projection, possibly only required in
152 /// parallel unstructured mesh generation during the projection
153 /// stage. Default set to true
155
156 /// Boolean to indicate whether to doc timings or not.
157 bool Doc_timings = false;
158
159 /// Boolean to indicate whether to output basic info during
160 /// setup_multi_domain_interaction() routines
161 bool Doc_stats = false;
162
163 /// Boolean to indicate whether to output further info during
164 /// setup_multi_domain_interaction() routines
165 bool Doc_full_stats = false;
166
167#ifdef OOMPH_HAS_MPI
168
169 // Functions for location method in multi-domain problems
170
171
172 //========================================================================
173 /// Send the zeta coordinates from the current process to
174 /// the next process; receive from the previous process
175 //========================================================================
177 {
178 // MPI info
181
182 // Storage for number of processors, current process and communicator
183 int n_proc = problem_pt->communicator_pt()->nproc();
184 int my_rank = problem_pt->communicator_pt()->my_rank();
185 OomphCommunicator* comm_pt = problem_pt->communicator_pt();
186
187 // Work out processors to send and receive from
188 int send_to_proc = my_rank + 1;
189 int recv_from_proc = my_rank - 1;
190 if (send_to_proc == n_proc)
191 {
192 send_to_proc = 0;
193 }
194 if (recv_from_proc < 0)
195 {
197 }
198
199 // Send the number of flat-packed zetas that we couldn't find
200 // locally to the next processor
203 1,
204 MPI_INT,
206 4,
207 comm_pt->mpi_comm(),
208 &request);
209
210 // Receive the number of flat-packed zetas that couldn't be found
211 // on the "previous" processor
212 int count_zetas = 0;
214 1,
215 MPI_INT,
217 4,
218 comm_pt->mpi_comm(),
219 &status);
220
222
223 // Send the vector of flat-packed zetas that we couldn't find
224 // locally to the next processor
225 if (n_missing_local_zetas != 0)
226 {
231 5,
232 comm_pt->mpi_comm(),
233 &request);
234 }
235
236 // Receive the vector of flat-packed zetas that couldn't be found
237 // on the "previous" processor
238 if (count_zetas != 0)
239 {
245 5,
246 comm_pt->mpi_comm(),
247 &status);
249 }
250 else
251 {
253 }
254
255 // Now we should have the Zeta arrays set up correctly
256 // for the next round of locations
257 }
258
259 //========start of send_and_receive_located_info==========================
260 /// Send location information from current process; Received location
261 /// information from (current process + iproc) modulo (nproc)
262 //========================================================================
264 Mesh* const& external_mesh_pt,
265 Problem* problem_pt)
266 {
267 // Set MPI info
270
271 // Storage for number of processors, current process and communicator
272 OomphCommunicator* comm_pt = problem_pt->communicator_pt();
273 int n_proc = comm_pt->nproc();
274 int my_rank = comm_pt->my_rank();
275
276 // Prepare vectors to receive information
282
283 // Communicate the located information back to the original process
285 if (my_rank < iproc)
286 {
288 }
290 if ((my_rank + iproc) >= n_proc)
291 {
293 }
294
295 // Send the double values associated with external halos
296 //------------------------------------------------------
299 1,
302 1,
303 comm_pt->mpi_comm(),
304 &request);
307 1,
308 MPI_INT,
310 1,
311 comm_pt->mpi_comm(),
312 &status);
314
316 {
321 2,
322 comm_pt->mpi_comm(),
323 &request);
324 }
326 {
332 2,
333 comm_pt->mpi_comm(),
334 &status);
335 }
337 {
339 }
340
341 // Now send unsigned values associated with external halos
342 //---------------------------------------------------------
345 1,
348 14,
349 comm_pt->mpi_comm(),
350 &request);
351
354 1,
355 MPI_INT,
357 14,
358 comm_pt->mpi_comm(),
359 &status);
360
362
364 {
369 15,
370 comm_pt->mpi_comm(),
371 &request);
372#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
373 for (unsigned i = 0; i < send_count_unsigned_values; i++)
374 {
375 oomph_info << "Sent:" << i << " to orig_proc:" << orig_send_proc
376 << " " << Flat_packed_unsigneds_string[i] << ": "
377 << Flat_packed_unsigneds[i] << std::endl;
378 }
379#endif
380 }
382 {
388 15,
389 comm_pt->mpi_comm(),
390 &status);
391 }
392
394 {
396 }
397
398 // Send and receive the Located_element_status
399 //--------------------------------------------
402 1,
403 MPI_INT,
405 20,
406 comm_pt->mpi_comm(),
407 &request);
408 int receive_count = 0;
410 1,
411 MPI_INT,
413 20,
414 comm_pt->mpi_comm(),
415 &status);
417
418 if (send_count != 0)
419 {
424 3,
425 comm_pt->mpi_comm(),
426 &request);
427 }
428
429 if (receive_count != 0)
430 {
436 3,
437 comm_pt->mpi_comm(),
438 &status);
439 }
440 if (send_count != 0)
441 {
443 }
444
445 // Send and receive Proc_id_plus_one_of_external_element array
446 //------------------------------------------------------------
447 if (send_count != 0)
448 {
451 MPI_INT,
453 13,
454 comm_pt->mpi_comm(),
455 &request);
456 }
457 if (receive_count != 0)
458 {
462 MPI_INT,
464 13,
465 comm_pt->mpi_comm(),
466 &status);
467 }
468 if (send_count != 0)
469 {
471 }
472
473
474 // And finally the Flat_packed_located_coordinates array
475 //------------------------------------------------------
476 unsigned send_count_located_coord =
479 1,
482 4,
483 comm_pt->mpi_comm(),
484 &request);
485 unsigned receive_count_located_coord = 0;
487 1,
490 4,
491 comm_pt->mpi_comm(),
492 &status);
494
496 {
501 5,
502 comm_pt->mpi_comm(),
503 &request);
504 }
506 {
512 5,
513 comm_pt->mpi_comm(),
514 &status);
515 }
517 {
519 }
520
521 // Copy across into original containers -- these can now
522 //------------------------------------------------------
523 // be processed by create_external_halo_elements() to generate
524 //------------------------------------------------------------
525 // external halo elements
526 //------------------------
528 for (int ii = 0; ii < receive_count_double_values; ii++)
529 {
531 }
533 for (int ii = 0; ii < receive_count_unsigned_values; ii++)
534 {
536 }
539 for (int ii = 0; ii < receive_count; ii++)
540 {
544 }
546 for (int ii = 0; ii < int(receive_count_located_coord); ii++)
547 {
549 }
550 }
551
552
553 //========start of add_external_haloed_node_to_storage====================
554 /// Helper function to add external haloed nodes, including any masters
555 //========================================================================
557 Node* nod_pt,
558 Problem* problem_pt,
559 Mesh* const& external_mesh_pt,
561 {
562 // Add the node if required
565
566 // Recursively add any master nodes (and their master nodes etc)
569 }
570
571
572 //========================================================================
573 /// Recursively add any master nodes (and their master nodes etc) of
574 /// external nodes
575 //========================================================================
577 int& iproc,
578 Node* nod_pt,
579 Problem* problem_pt,
580 Mesh* const& external_mesh_pt,
582 {
583 // Loop over continuously interpolated values and add masters
584 for (int i_cont = -1; i_cont < n_cont_inter_values; i_cont++)
585 {
586 if (nod_pt->is_hanging(i_cont))
587 {
588 // Indicate that this node is a hanging node so the other
589 // process knows to create HangInfo and masters, etc.
590 Flat_packed_unsigneds.push_back(1);
591#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
592 Flat_packed_unsigneds_string.push_back("Is hanging");
593#endif
594 // If this is a hanging node then add all its masters as
595 // external halo nodes if they have not yet been added
596 HangInfo* hang_pt = nod_pt->hanging_pt(i_cont);
597 // Loop over masters
598 unsigned n_master = hang_pt->nmaster();
599
600 // Indicate number of master nodes to add on other process
602#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
603 Flat_packed_unsigneds_string.push_back("nmaster");
604#endif
605 for (unsigned m = 0; m < n_master; m++)
606 {
607 Node* master_nod_pt = hang_pt->master_node_pt(m);
608
609 // Call the helper function for master nodes
612 problem_pt,
615
616 // Indicate the weight of this master
617 Flat_packed_doubles.push_back(hang_pt->master_weight(m));
618
619 // Recursively add any master nodes (and their master nodes etc)
621 iproc,
623 problem_pt,
626 }
627 }
628 else
629 {
630 // Indicate that it's not a hanging node in this variable
631 Flat_packed_unsigneds.push_back(0);
632#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
633 Flat_packed_unsigneds_string.push_back("Not hanging");
634#endif
635 }
636 } // end loop over continously interpolated values
637 }
638
639 //==========start of add_external_haloed_node_helper======================
640 /// Helper to add external haloed node that is not a master
641 //========================================================================
643 Node* nod_pt,
644 Problem* problem_pt,
645 Mesh* const& external_mesh_pt,
647 {
648 // Attempt to add this node as an external haloed node
649 unsigned n_ext_haloed_nod =
650 external_mesh_pt->nexternal_haloed_node(iproc);
652 external_mesh_pt->add_external_haloed_node_pt(iproc, nod_pt);
653
654 // If it was added then the new index should match the size of the storage
656 {
657 Flat_packed_unsigneds.push_back(1);
658
659#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
660 std::stringstream junk;
661 junk << "Node needs to be constructed [size="
662 << Flat_packed_unsigneds.size() << "]; last entry: "
664 Flat_packed_unsigneds_string.push_back(junk.str());
665#endif
666
667 // This helper function gets all the required information for the
668 // specified node and stores it into MPI-sendable information
669 // so that a halo copy can be made on the receiving process
672 }
673 else // It was already added
674 {
675 Flat_packed_unsigneds.push_back(0);
676#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
677 std::stringstream junk;
678 junk << "Node was already added [size=" << Flat_packed_unsigneds.size()
679 << "]; last entry: "
681
682 Flat_packed_unsigneds_string.push_back(junk.str());
683#endif
684
685 // This node is already an external haloed node, so tell
686 // the other process its index in the equivalent external halo storage
688#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
689 Flat_packed_unsigneds_string.push_back("external haloed node index");
690#endif
691 }
692 }
693
694
695 //==========start of add_external_haloed_master_node_helper===============
696 /// Helper function to add external haloed node that is a master
697 //========================================================================
700 Problem* problem_pt,
701 Mesh* const& external_mesh_pt,
703 {
704 // Attempt to add node as an external haloed node
705 unsigned n_ext_haloed_nod =
706 external_mesh_pt->nexternal_haloed_node(iproc);
709 external_mesh_pt->add_external_haloed_node_pt(iproc, master_nod_pt);
710
711 // If it was added the returned index is the same as current storage size
713 {
714 // Indicate that this node needs to be constructed on
715 // the other process
716 Flat_packed_unsigneds.push_back(1);
717#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
719 "Node needs to be constructed[2]");
720#endif
721
722 // This gets all the required information for the specified
723 // master node and stores it into MPI-sendable information
724 // so that a halo copy can be made on the receiving process
727 problem_pt,
730 }
731 else // It was already added
732 {
733 Flat_packed_unsigneds.push_back(0);
734#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
735 Flat_packed_unsigneds_string.push_back("Node was already added[2]");
736#endif
737
738 // This node is already an external haloed node, so tell
739 // the other process its index in the equivalent external halo storage
741#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
742 Flat_packed_unsigneds_string.push_back("external haloed node index[2]");
743#endif
744 }
745 }
746
747
748 //========start of get_required_nodal_information_helper==================
749 /// Helper function to get the required nodal information from an
750 /// external haloed node so that a fully-functional external halo
751 /// node (and therefore element) can be created on the receiving process
752 //========================================================================
754 Node* nod_pt,
755 Problem* problem_pt,
756 Mesh* const& external_mesh_pt,
758 {
759 // Tell the halo copy of this node how many values there are
760 // [NB this may be different for nodes within the same element, e.g.
761 // when using Lagrange multipliers]
762 unsigned n_val = nod_pt->nvalue();
763 Flat_packed_unsigneds.push_back(n_val);
764#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
765 Flat_packed_unsigneds_string.push_back("Number of values");
766#endif
767
768 unsigned n_dim = nod_pt->ndim();
769 TimeStepper* time_stepper_pt = nod_pt->time_stepper_pt();
770
771 // Find the timestepper in the list of problem timesteppers
772 bool found_timestepper = false;
773 unsigned time_stepper_index;
774 unsigned n_time_steppers = problem_pt->ntime_stepper();
775 for (unsigned i = 0; i < n_time_steppers; i++)
776 {
777 if (time_stepper_pt == problem_pt->time_stepper_pt(i))
778 {
779 // Indicate the timestepper's index
780 found_timestepper = true;
782 break;
783 }
784 }
785
787 {
788 Flat_packed_unsigneds.push_back(1);
789#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
790 Flat_packed_unsigneds_string.push_back("Found timestepper");
791#endif
793#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
794 Flat_packed_unsigneds_string.push_back("Timestepper index");
795#endif
796 }
797 else
798 {
799 Flat_packed_unsigneds.push_back(0);
800#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
801 Flat_packed_unsigneds_string.push_back("Not found timestepper");
802#endif
803 }
804
805 // Default number of previous values to 1
806 unsigned n_prev = 1;
807 if (time_stepper_pt != 0)
808 {
809 // Add number of history values to n_prev
810 n_prev = time_stepper_pt->ntstorage();
811 }
812
813 // Is the node on any boundaries?
814 if (nod_pt->is_on_boundary())
815 {
816 Flat_packed_unsigneds.push_back(1);
817#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
818 Flat_packed_unsigneds_string.push_back("Node is on boundary");
819#endif
820
821 // Loop over the boundaries of the external mesh
823 unsigned n_bnd = external_mesh_pt->nboundary();
824 for (unsigned i_bnd = 0; i_bnd < n_bnd; i_bnd++)
825 {
826 // Which boundaries (could be more than one) is it on?
827 if (nod_pt->is_on_boundary(i_bnd))
828 {
829 boundaries.push_back(i_bnd);
830 }
831 }
832 unsigned nb = boundaries.size();
833 Flat_packed_unsigneds.push_back(nb);
834#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
835 std::stringstream junk;
836 junk << "Node is on " << nb << " boundaries";
837 Flat_packed_unsigneds_string.push_back(junk.str());
838#endif
839 for (unsigned i = 0; i < nb; i++)
840 {
842#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
843 std::stringstream junk;
844 junk << "Node is on boundary " << boundaries[i] << " of " << n_bnd;
845 Flat_packed_unsigneds_string.push_back(junk.str());
846#endif
847 }
848
849 // Get pointer to the map of indices associated with
850 // additional values created by face elements
852#ifdef PARANOID
853 if (bnod_pt == 0)
854 {
855 throw OomphLibError("Failed to cast new node to boundary node\n",
858 }
859#endif
860 std::map<unsigned, unsigned>* map_pt =
861 bnod_pt->index_of_first_value_assigned_by_face_element_pt();
862
863 // No additional values created
864 if (map_pt == 0)
865 {
866 Flat_packed_unsigneds.push_back(0);
867#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
868 std::stringstream junk;
870 "No additional values were created by face element");
871#endif
872 }
873 // Created additional values
874 else
875 {
876 // How many?
877 Flat_packed_unsigneds.push_back(map_pt->size());
878#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
879 std::stringstream junk;
880 junk << "Map size " << map_pt->size() << n_bnd;
881 Flat_packed_unsigneds_string.push_back(junk.str());
882#endif
883 // Loop over entries in map and add to send data
884 for (std::map<unsigned, unsigned>::iterator p = map_pt->begin();
885 p != map_pt->end();
886 p++)
887 {
888 Flat_packed_unsigneds.push_back((*p).first);
889#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
890 std::stringstream junk;
891 Flat_packed_unsigneds_string.push_back("Key of map entry");
892#endif
893 Flat_packed_unsigneds.push_back((*p).second);
894#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
895 Flat_packed_unsigneds_string.push_back("Value of map entry");
896#endif
897 }
898 }
899 }
900 else
901 {
902 // Not on any boundary
903 Flat_packed_unsigneds.push_back(0);
904#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
905 Flat_packed_unsigneds_string.push_back("Node is not on any boundary");
906#endif
907 }
908
909 // Is the Node algebraic? If so, send its ref values and
910 // an indication of its geometric objects if they are stored
911 // in the algebraic mesh
912 AlgebraicNode* alg_nod_pt = dynamic_cast<AlgebraicNode*>(nod_pt);
913 if (alg_nod_pt != 0)
914 {
915 // The external mesh should be algebraic
917 dynamic_cast<AlgebraicMesh*>(external_mesh_pt);
918
919 // Get default node update function ID
920 unsigned update_id = alg_nod_pt->node_update_fct_id();
922#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
923 Flat_packed_unsigneds_string.push_back("Alg Node update id");
924#endif
925
926 // Get reference values at default...
927 unsigned n_ref_val = alg_nod_pt->nref_value();
929#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
930 Flat_packed_unsigneds_string.push_back("Alg Node n ref values");
931#endif
932 for (unsigned i_ref_val = 0; i_ref_val < n_ref_val; i_ref_val++)
933 {
934 Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
935 }
936
937 // Access geometric objects at default...
938 unsigned n_geom_obj = alg_nod_pt->ngeom_object();
940#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
941 Flat_packed_unsigneds_string.push_back("Alg Node n geom objects");
942#endif
943 for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
944 {
945 GeomObject* geom_obj_pt = alg_nod_pt->geom_object_pt(i_geom);
946
947 // Check this against the stored geometric objects in mesh
948 unsigned n_geom_list = alg_mesh_pt->ngeom_object_list_pt();
949
950 // Default found index to zero
951 unsigned found_geom_object = 0;
952 for (unsigned i_list = 0; i_list < n_geom_list; i_list++)
953 {
954 if (geom_obj_pt == alg_mesh_pt->geom_object_list_pt(i_list))
955 {
957 }
958 }
960#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
961 Flat_packed_unsigneds_string.push_back("Found geom object");
962#endif
963 }
964 }
965
966 // If it is a MacroElementNodeUpdateNode, everything has been
967 // dealt with by the new element already
968
969 // Is it a SolidNode?
970 SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(nod_pt);
971 if (solid_nod_pt != 0)
972 {
973 unsigned n_solid_val = solid_nod_pt->variable_position_pt()->nvalue();
974 for (unsigned i_val = 0; i_val < n_solid_val; i_val++)
975 {
976 for (unsigned t = 0; t < n_prev; t++)
977 {
978 Flat_packed_doubles.push_back(
979 solid_nod_pt->variable_position_pt()->value(t, i_val));
980 }
981 }
982 }
983
984 // Finally copy info required for all node types
985 for (unsigned i_val = 0; i_val < n_val; i_val++)
986 {
987 for (unsigned t = 0; t < n_prev; t++)
988 {
989 Flat_packed_doubles.push_back(nod_pt->value(t, i_val));
990 }
991 }
992
993 // Now do positions
994 for (unsigned idim = 0; idim < n_dim; idim++)
995 {
996 for (unsigned t = 0; t < n_prev; t++)
997 {
998 Flat_packed_doubles.push_back(nod_pt->x(t, idim));
999 }
1000 }
1001 }
1002
1003 //=========start of get_required_master_nodal_information_helper==========
1004 /// Helper function to get the required master nodal information from an
1005 /// external haloed master node so that a fully-functional external halo
1006 /// master node (and possible element) can be created on the receiving
1007 /// process
1008 //========================================================================
1010 int& iproc,
1012 Problem* problem_pt,
1013 Mesh* const& external_mesh_pt,
1015 {
1016 // Need to send over dimension, position type and number of values
1018#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1019 Flat_packed_unsigneds_string.push_back("Master node ndim");
1020#endif
1021 Flat_packed_unsigneds.push_back(master_nod_pt->nposition_type());
1022#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1023 Flat_packed_unsigneds_string.push_back("Master node npos_type");
1024#endif
1025 Flat_packed_unsigneds.push_back(master_nod_pt->nvalue());
1026#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1027 Flat_packed_unsigneds_string.push_back("Master node nvalue");
1028#endif
1029
1030 // If it's a solid node, also need to send lagrangian dim and type
1031 SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(master_nod_pt);
1032 if (solid_nod_pt != 0)
1033 {
1035#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1036 Flat_packed_unsigneds_string.push_back("Master solid node nlagr");
1037#endif
1038 Flat_packed_unsigneds.push_back(solid_nod_pt->nlagrangian_type());
1039#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1040 Flat_packed_unsigneds_string.push_back("Master solid node nlagr_type");
1041#endif
1042 }
1043
1044 unsigned n_dim = master_nod_pt->ndim();
1045 TimeStepper* time_stepper_pt = master_nod_pt->time_stepper_pt();
1046
1047 // Find the timestepper in the list of problem timesteppers
1048 bool found_timestepper = false;
1049 unsigned time_stepper_index;
1050 unsigned n_time_steppers = problem_pt->ntime_stepper();
1051 for (unsigned i = 0; i < n_time_steppers; i++)
1052 {
1053 if (time_stepper_pt == problem_pt->time_stepper_pt(i))
1054 {
1055 // Indicate the timestepper's index
1056 // add 1 to the index so that 0 indicates no timestepper?
1057 found_timestepper = true;
1059 break;
1060 }
1061 }
1062
1064 {
1065 Flat_packed_unsigneds.push_back(1);
1066#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1067 Flat_packed_unsigneds_string.push_back("Master node Found timestepper");
1068#endif
1070#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1071 Flat_packed_unsigneds_string.push_back("Master node Timestepper index");
1072#endif
1073 }
1074 else
1075 {
1076 Flat_packed_unsigneds.push_back(0);
1077#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1079 "Master node Not found timestepper");
1080#endif
1081 }
1082
1083 // Default number of previous values to 1
1084 unsigned n_prev = 1;
1085 if (time_stepper_pt != 0)
1086 {
1087 // Add number of history values to n_prev
1088 n_prev = time_stepper_pt->ntstorage();
1089 }
1090
1091 // Is the node on any boundaries?
1092 if (master_nod_pt->is_on_boundary())
1093 {
1094 Flat_packed_unsigneds.push_back(1);
1095#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1096 Flat_packed_unsigneds_string.push_back("Master node is on boundary");
1097#endif
1098 // Loop over the boundaries of the external mesh
1100 unsigned n_bnd = external_mesh_pt->nboundary();
1101 for (unsigned i_bnd = 0; i_bnd < n_bnd; i_bnd++)
1102 {
1103 // Which boundaries (could be more than one) is it on?
1104 if (master_nod_pt->is_on_boundary(i_bnd))
1105 {
1106 boundaries.push_back(i_bnd);
1107 }
1108 }
1109 unsigned nb = boundaries.size();
1110 Flat_packed_unsigneds.push_back(nb);
1111#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1112 std::stringstream junk;
1113 junk << "Master node is on " << nb << " boundaries";
1114 Flat_packed_unsigneds_string.push_back(junk.str());
1115#endif
1116 for (unsigned i = 0; i < nb; i++)
1117 {
1119#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1120 std::stringstream junk;
1121 junk << "Master noode is on boundary " << boundaries[i] << " of "
1122 << n_bnd;
1123 Flat_packed_unsigneds_string.push_back(junk.str());
1124#endif
1125 }
1126
1127 // Get pointer to the map of indices associated with
1128 // additional values created by face elements
1130 dynamic_cast<BoundaryNodeBase*>(master_nod_pt);
1131#ifdef PARANOID
1132 if (bnod_pt == 0)
1133 {
1134 throw OomphLibError("Failed to cast new node to boundary node\n",
1137 }
1138#endif
1139 std::map<unsigned, unsigned>* map_pt =
1140 bnod_pt->index_of_first_value_assigned_by_face_element_pt();
1141
1142 // No additional values created
1143 if (map_pt == 0)
1144 {
1145 Flat_packed_unsigneds.push_back(0);
1146#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1147 std::stringstream junk;
1149 "No additional values were created by face element for this master "
1150 "node");
1151#endif
1152 }
1153 // Created additional values
1154 else
1155 {
1156 // How many?
1157 Flat_packed_unsigneds.push_back(map_pt->size());
1158#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1159 std::stringstream junk;
1160 junk << "Map size for master node " << map_pt->size() << n_bnd;
1161 Flat_packed_unsigneds_string.push_back(junk.str());
1162#endif
1163 // Loop over entries in map and add to send data
1164 for (std::map<unsigned, unsigned>::iterator p = map_pt->begin();
1165 p != map_pt->end();
1166 p++)
1167 {
1168 Flat_packed_unsigneds.push_back((*p).first);
1169#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1170 std::stringstream junk;
1172 "Key of map entry for master node");
1173#endif
1174 Flat_packed_unsigneds.push_back((*p).second);
1175#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1177 "Value of map entry for master node");
1178#endif
1179 }
1180 }
1181 }
1182 else
1183 {
1184 // Not on any boundary
1185 Flat_packed_unsigneds.push_back(0);
1186#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1188 "Master node is not on any boundary");
1189#endif
1190 }
1191
1192 // Is the Node algebraic? If so, send its ref values and
1193 // an indication of its geometric objects if they are stored
1194 // in the algebraic mesh
1196 if (alg_nod_pt != 0)
1197 {
1198 // The external mesh should be algebraic
1200 dynamic_cast<AlgebraicMesh*>(external_mesh_pt);
1201
1202 // Get default node update function ID
1203 unsigned update_id = alg_nod_pt->node_update_fct_id();
1205#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1206 Flat_packed_unsigneds_string.push_back("Master Alg Node update id");
1207#endif
1208
1209 // Get reference values at default...
1210 unsigned n_ref_val = alg_nod_pt->nref_value();
1212#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1213 Flat_packed_unsigneds_string.push_back("Master Alg Node n ref values");
1214#endif
1215 for (unsigned i_ref_val = 0; i_ref_val < n_ref_val; i_ref_val++)
1216 {
1217 Flat_packed_doubles.push_back(alg_nod_pt->ref_value(i_ref_val));
1218 }
1219
1220 // Access geometric objects at default...
1221 unsigned n_geom_obj = alg_nod_pt->ngeom_object();
1223#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1225 "Master Alg Node n geom objects");
1226#endif
1227 for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
1228 {
1229 GeomObject* geom_obj_pt = alg_nod_pt->geom_object_pt(i_geom);
1230 // Check this against the stored geometric objects in mesh
1231 unsigned n_geom_list = alg_mesh_pt->ngeom_object_list_pt();
1232 // Default found index to zero
1233 unsigned found_geom_object = 0;
1234 for (unsigned i_list = 0; i_list < n_geom_list; i_list++)
1235 {
1236 if (geom_obj_pt == alg_mesh_pt->geom_object_list_pt(i_list))
1237 {
1239 }
1240 }
1242#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1244 "Master node Found geom object");
1245#endif
1246 }
1247 } // end AlgebraicNode check
1248
1249 // Is it a MacroElementNodeUpdateNode?
1252 if (macro_nod_pt != 0)
1253 {
1254 // Loop over current external haloed elements - has the element which
1255 // controls the node update for this node been added yet?
1257 macro_nod_pt->node_update_element_pt();
1258
1259 unsigned n_ext_haloed_el =
1260 external_mesh_pt->nexternal_haloed_element(iproc);
1261 unsigned external_haloed_el_index;
1263 external_mesh_pt->add_external_haloed_element_pt(
1265
1266 // If it wasn't already added, we need to create a halo copy
1268 {
1269 Flat_packed_unsigneds.push_back(1);
1270#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1272 "Master Node needs to be constructed");
1273#endif
1274 // Cast to a finite elemnet
1276 dynamic_cast<FiniteElement*>(macro_node_update_el_pt);
1277
1278 // We're using macro elements to update...
1281 if (macro_mesh_pt != 0)
1282 {
1283 Flat_packed_unsigneds.push_back(1);
1284#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1286 "Mesh is macro element mesh");
1287#endif
1288 // Need to send the macro element number in the mesh across
1291 unsigned macro_el_num = macro_el_pt->macro_element_number();
1293#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1294 Flat_packed_unsigneds_string.push_back("Number of macro element");
1295#endif
1296 // Also need to send
1297 // the lower left and upper right coordinates of the macro element
1299 dynamic_cast<QElementBase*>(macro_node_update_el_pt);
1300 if (q_el_pt != 0)
1301 {
1302 // The macro element needs to be set first before
1303 // its lower left and upper right coordinates can be accessed
1304 // Now send the lower left and upper right coordinates
1305 unsigned el_dim = q_el_pt->dim();
1306 for (unsigned i_dim = 0; i_dim < el_dim; i_dim++)
1307 {
1308 Flat_packed_doubles.push_back(q_el_pt->s_macro_ll(i_dim));
1309 Flat_packed_doubles.push_back(q_el_pt->s_macro_ur(i_dim));
1310 }
1311 }
1312 else // Throw an error
1313 {
1314 std::ostringstream error_stream;
1315 error_stream << "You are using a MacroElement node update\n"
1316 << "in a case with non-QElements. This has not\n"
1317 << "yet been implemented.\n";
1318 throw OomphLibError(error_stream.str(),
1321 }
1322 }
1323 else // Not using macro elements for node update... umm, we're
1324 // already inside a loop over macro elements, so this
1325 // should never get here... an error should be thrown I suppose
1326 {
1327 Flat_packed_unsigneds.push_back(0);
1328#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1330 "Mesh is not a macro element mesh");
1331#endif
1332 }
1333
1334 // This element needs to be fully functioning on the other
1335 // process, so send all the information required to create it
1337 for (unsigned j = 0; j < n_node; j++)
1338 {
1341 new_nod_pt,
1342 problem_pt,
1345 }
1346 }
1347 else // The external haloed element already exists
1348 {
1349 Flat_packed_unsigneds.push_back(0);
1350#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1352 "External haloed element already exists");
1353#endif
1355#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1357 "Index of existing external haloed element");
1358#endif
1359 }
1360
1361 } // end of MacroElementNodeUpdateNode check
1362
1363 // Is it a SolidNode?
1364 if (solid_nod_pt != 0)
1365 {
1366 unsigned n_val = solid_nod_pt->variable_position_pt()->nvalue();
1367 for (unsigned i_val = 0; i_val < n_val; i_val++)
1368 {
1369 for (unsigned t = 0; t < n_prev; t++)
1370 {
1371 Flat_packed_doubles.push_back(
1372 solid_nod_pt->variable_position_pt()->value(t, i_val));
1373 }
1374 }
1375 }
1376
1377 // Finally copy info required for all node types
1378
1379 // Halo copy needs to know all the history values
1380 unsigned n_val = master_nod_pt->nvalue();
1381 for (unsigned i_val = 0; i_val < n_val; i_val++)
1382 {
1383 for (unsigned t = 0; t < n_prev; t++)
1384 {
1385 Flat_packed_doubles.push_back(master_nod_pt->value(t, i_val));
1386 }
1387 }
1388
1389 // Now do positions
1390 for (unsigned idim = 0; idim < n_dim; idim++)
1391 {
1392 for (unsigned t = 0; t < n_prev; t++)
1393 {
1394 Flat_packed_doubles.push_back(master_nod_pt->x(t, idim));
1395 }
1396 }
1397 }
1398
1399
1400 //=======start of add_external_halo_node_helper===========================
1401 /// Helper functiono to add external halo node that is not a master
1402 //========================================================================
1404 Mesh* const& external_mesh_pt,
1405 unsigned& loc_p,
1406 unsigned& node_index,
1407 FiniteElement* const& new_el_pt,
1409 Problem* problem_pt)
1410 {
1411 // Given the node and the external mesh, and received information
1412 // about them from process loc_p, construct them on the current process
1413#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1415 << " Bool: New node needs to be constructed "
1417 << std::endl;
1418#endif
1420 {
1421 // Construct a new node based upon sent information
1423 loc_p,
1424 node_index,
1425 new_el_pt,
1427 problem_pt);
1428 }
1429 else
1430 {
1431#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1433 << " Index of existing external halo node "
1435 << std::endl;
1436#endif
1437
1438 // Copy node from received location
1439 new_nod_pt = external_mesh_pt->external_halo_node_pt(
1441
1443 }
1444 }
1445
1446
1447 //========start of construct_new_external_halo_node_helper=================
1448 /// Helper function which constructs a new external halo node (on new
1449 /// element) with the required information sent from the haloed process
1450 //========================================================================
1452 Node*& new_nod_pt,
1453 unsigned& loc_p,
1454 unsigned& node_index,
1455 FiniteElement* const& new_el_pt,
1456 Mesh* const& external_mesh_pt,
1457 Problem* problem_pt)
1458 {
1459 // The first entry indicates the number of values at this new Node
1460 // (which may be different across the same element e.g. Lagrange
1461 // multipliers)
1462#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1464 << " Number of values of external halo node "
1466 << std::endl;
1467#endif
1468 unsigned n_val =
1470
1471 // Null TimeStepper for now
1472 TimeStepper* time_stepper_pt = 0;
1473 // Default number of previous values to 1
1474 unsigned n_prev = 1;
1475
1476 // The next entry in Flat_packed_unsigneds indicates
1477 // if a timestepper is required for this halo node
1478#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1480 << " Timestepper req'd for node "
1482 << std::endl;
1483#endif
1485 {
1486#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1488 << " Index of timestepper "
1490 << std::endl;
1491#endif
1492 // Index
1493 time_stepper_pt = problem_pt->time_stepper_pt(
1495
1496 // Check whether number of prev values is "sent" across
1497 n_prev = time_stepper_pt->ntstorage();
1498 }
1499
1500 // If this node was on a boundary then it needs to
1501 // be on the same boundary here
1502#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1504 << " Is node on boundary? "
1506 << std::endl;
1507#endif
1509 {
1510 // Construct a new boundary node
1511 if (time_stepper_pt != 0)
1512 {
1513 new_nod_pt =
1514 new_el_pt->construct_boundary_node(node_index, time_stepper_pt);
1515 }
1516 else
1517 {
1519 }
1520
1521 // How many boundaries does the node live on?
1522#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1524 << " Number of boundaries the node is on: "
1526 << std::endl;
1527#endif
1528 unsigned nb =
1530 for (unsigned i = 0; i < nb; i++)
1531 {
1532 // Boundary number
1533#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1535 << " Node is on boundary "
1537 << std::endl;
1538#endif
1539 unsigned i_bnd =
1541 external_mesh_pt->add_boundary_node(i_bnd, new_nod_pt);
1542 }
1543
1544 // Do we have additional values created by face elements?
1545#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1547 << " Number of additional values created by face element "
1549 << std::endl;
1550#endif
1551 unsigned n_entry =
1553 if (n_entry > 0)
1554 {
1555 // Create storage, if it doesn't already exist, for the map
1556 // that will contain the position of the first entry of
1557 // this face element's additional values,
1559 dynamic_cast<BoundaryNodeBase*>(new_nod_pt);
1560#ifdef PARANOID
1561 if (bnew_nod_pt == 0)
1562 {
1563 throw OomphLibError("Failed to cast new node to boundary node\n",
1566 }
1567#endif
1568 if (bnew_nod_pt->index_of_first_value_assigned_by_face_element_pt() ==
1569 0)
1570 {
1571 bnew_nod_pt->index_of_first_value_assigned_by_face_element_pt() =
1572 new std::map<unsigned, unsigned>;
1573 }
1574
1575 // Get pointer to the map of indices associated with
1576 // additional values created by face elements
1577 std::map<unsigned, unsigned>* map_pt =
1578 bnew_nod_pt->index_of_first_value_assigned_by_face_element_pt();
1579
1580 // Loop over number of entries in map
1581 for (unsigned i = 0; i < n_entry; i++)
1582 {
1583 // Read out pairs...
1584
1585#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1588 << " Key of map entry"
1590 << std::endl;
1591#endif
1592 unsigned first =
1594
1595#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1598 << " Value of map entry"
1600 << std::endl;
1601#endif
1602 unsigned second =
1604
1605 // ...and assign
1606 (*map_pt)[first] = second;
1607 }
1608 }
1609 }
1610 else
1611 {
1612 // Construct an ordinary (non-boundary) node
1613 if (time_stepper_pt != 0)
1614 {
1615 new_nod_pt = new_el_pt->construct_node(node_index, time_stepper_pt);
1616 }
1617 else
1618 {
1620 }
1621 }
1622
1623 // Node constructed: add to external halo nodes
1624 external_mesh_pt->add_external_halo_node_pt(loc_p, new_nod_pt);
1625
1626 // Is the new constructed node Algebraic?
1628
1629 // If it is algebraic, its node update functions will
1630 // not yet have been set up properly
1631 if (new_alg_nod_pt != 0)
1632 {
1633 // The AlgebraicMesh is the external mesh
1635 dynamic_cast<AlgebraicMesh*>(external_mesh_pt);
1636
1637 /// The first entry of All_alg_nodal_info contains
1638 /// the default node update id
1639 /// e.g. for the quarter circle there are
1640 /// "Upper_left_box", "Lower right box" etc...
1641#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1643 << " Alg node update id "
1645 << std::endl;
1646#endif
1647
1648 unsigned update_id =
1650
1651 Vector<double> ref_value;
1652
1653 // The size of this vector is in the next entry
1654 // of All_alg_nodal_info
1655#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1657 << " Alg node # of ref values "
1659 << std::endl;
1660#endif
1661 unsigned n_ref_val =
1663
1664 // The reference values themselves are in
1665 // All_alg_ref_value
1666 ref_value.resize(n_ref_val);
1667 for (unsigned i_ref = 0; i_ref < n_ref_val; i_ref++)
1668 {
1669 ref_value[i_ref] =
1671 }
1672
1673 Vector<GeomObject*> geom_object_pt;
1674 /// again we need the size of this vector as it varies
1675 /// between meshes; we also need some indication
1676 /// as to which geometric object should be used...
1677
1678 // The size of this vector is in the next entry
1679 // of All_alg_nodal_info
1680#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1682 << " Alg node # of geom objects "
1684 << std::endl;
1685#endif
1686 unsigned n_geom_obj =
1688
1689 // The remaining indices are in the rest of
1690 // All_alg_nodal_info
1691 geom_object_pt.resize(n_geom_obj);
1692 for (unsigned i_geom = 0; i_geom < n_geom_obj; i_geom++)
1693 {
1694#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1696 << " Alg node: geom object index "
1698 << std::endl;
1699#endif
1700 unsigned geom_index =
1702 // This index indicates which of the AlgebraicMesh's
1703 // stored geometric objects should be used
1704 // (0 is a null pointer; everything else should have
1705 // been filled in by the specific Mesh). If it
1706 // hasn't been filled in then the update_node_update
1707 // call should fix it
1708 geom_object_pt[i_geom] = alg_mesh_pt->geom_object_list_pt(geom_index);
1709 }
1710
1711 /// For the received update_id, ref_value, geom_object
1712 /// call add_node_update_info
1713 new_alg_nod_pt->add_node_update_info(
1714 update_id, alg_mesh_pt, geom_object_pt, ref_value);
1715
1716 /// Now call update_node_update
1717 alg_mesh_pt->update_node_update(new_alg_nod_pt);
1718 }
1719
1720 // Is the node a MacroElementNodeUpdateNode?
1722 dynamic_cast<MacroElementNodeUpdateNode*>(new_nod_pt);
1723
1724 if (macro_nod_pt != 0)
1725 {
1726 // Need to call set_node_update_info; this requires
1727 // a Vector<GeomObject*> (taken from the mesh)
1728 Vector<GeomObject*> geom_object_vector_pt;
1729
1730 // Access the required geom objects from the
1731 // MacroElementNodeUpdateMesh
1734 geom_object_vector_pt = macro_mesh_pt->geom_object_vector_pt();
1735
1736 // Get local coordinate of node in new element
1740
1741 // Set node update info for this node
1742 macro_nod_pt->set_node_update_info(
1743 new_el_pt, s_in_macro_node_update_element, geom_object_vector_pt);
1744 }
1745
1746 // Is the new node a SolidNode?
1747 SolidNode* solid_nod_pt = dynamic_cast<SolidNode*>(new_nod_pt);
1748 if (solid_nod_pt != 0)
1749 {
1750 unsigned n_solid_val = solid_nod_pt->variable_position_pt()->nvalue();
1751 for (unsigned i_val = 0; i_val < n_solid_val; i_val++)
1752 {
1753 for (unsigned t = 0; t < n_prev; t++)
1754 {
1755 solid_nod_pt->variable_position_pt()->set_value(
1757 }
1758 }
1759 }
1760
1761 // If there are additional values, resize the node
1762 unsigned n_new_val = new_nod_pt->nvalue();
1763 if (n_val > n_new_val)
1764 {
1765 new_nod_pt->resize(n_val);
1766 }
1767
1768 // Get copied history values
1769 // unsigned n_val=new_nod_pt->nvalue();
1770 for (unsigned i_val = 0; i_val < n_val; i_val++)
1771 {
1772 for (unsigned t = 0; t < n_prev; t++)
1773 {
1774 new_nod_pt->set_value(
1776 }
1777 }
1778
1779 // Get copied history values for positions
1780 unsigned n_dim = new_nod_pt->ndim();
1781 for (unsigned idim = 0; idim < n_dim; idim++)
1782 {
1783 for (unsigned t = 0; t < n_prev; t++)
1784 {
1785 // Copy to coordinate
1786 new_nod_pt->x(t, idim) =
1788 }
1789 }
1790 }
1791
1792
1793 //=====================================================================
1794 /// Locate zeta for current set of missing coordinates; vector-based version
1795 //=====================================================================
1797 int& iproc,
1798 Mesh* const& external_mesh_pt,
1799 Problem* problem_pt,
1801 {
1802 // How many meshes are we dealing with?
1803 unsigned n_mesh = mesh_geom_obj_pt.size();
1804
1805 // Storage for number of processors, current process and communicator
1806 OomphCommunicator* comm_pt = problem_pt->communicator_pt();
1807 int n_proc = comm_pt->nproc();
1808 int my_rank = comm_pt->my_rank();
1809
1810 // Clear vectors containing data to be sent
1811 Flat_packed_doubles.resize(0);
1812#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1814#endif
1815 Flat_packed_unsigneds.resize(0);
1817
1818 // Flush storage for zetas not found locally (when
1819 // processing the zeta coordinates received from "previous"
1820 // processor)
1822
1823 // Number of zeta tuples to be dealt with (includes padding!)
1825
1826 // Create storage for the processor id (plus one) on which
1827 // the zetas stored in Flat_packed_zetas_not_found_locally[...]
1828 // were located. (Remains zero for padded entries).
1830
1831 // Create storage for the status of the (external halo) element associated
1832 // the zetas stored in Flat_packed_zetas_not_found_locally[...].
1833 // It either hasn't been found, already exists on the processor
1834 // that needs it, or needs to be newly created. (Remains Not_found
1835 // for padded entries).
1837
1838 // Counter for flat-packed array of external zeta coordinates
1839 unsigned count = 0;
1840
1841 // Current mesh
1842 unsigned i_mesh = 0;
1843
1844 // Loop over the zeta tuples that we received from elsewhere and
1845 // are trying to find here for current mesh
1846 for (unsigned i = 0; i < n_zeta; i++)
1847 {
1848 // Storage for global coordinates to be located
1850
1851 // Loop to fill in coordinates
1852 for (unsigned ii = 0; ii < Dim; ii++)
1853 {
1855 count++;
1856 }
1857
1858 // Check if we've reached the end of the mesh
1859 bool reached_end_of_mesh = false;
1860 unsigned dbl_max_count = 0;
1861 for (unsigned ii = 0; ii < Dim; ii++)
1862 {
1863 if (x_global[ii] == DBL_MAX)
1864 {
1865 dbl_max_count++;
1866 reached_end_of_mesh = true;
1867 }
1868 }
1869
1870 // Reached end of mesh
1872 {
1873#ifdef PARANOID
1874 // Check if all coordinates were set to DBX_MAX
1875 if (dbl_max_count != Dim)
1876 {
1877 std::ostringstream error_stream;
1878 error_stream << "Appear to have reached end of mesh " << i_mesh
1879 << " but only " << dbl_max_count << " out of " << Dim
1880 << " zeta coordinates have been set to DBX_MAX\n";
1881 throw OomphLibError(error_stream.str(),
1884 }
1885#endif
1886 // Indicate end of mesh in flat packed data
1887 for (unsigned ii = 0; ii < Dim; ii++)
1888 {
1890 }
1891
1892 // Bump mesh counter
1893 i_mesh++;
1894
1895 // Bail out if we're done
1896 if (i_mesh == n_mesh)
1897 {
1898 return;
1899 }
1900 }
1901
1902 // Perform locate_zeta for these coordinates and current mesh
1906 {
1908
1909 // Did the locate method work?
1910 if (sub_geom_obj_pt != 0)
1911 {
1912 // Get the source element - bulk or not?
1915 {
1916 source_el_pt = dynamic_cast<FiniteElement*>(sub_geom_obj_pt);
1917 }
1918 else
1919 {
1921 dynamic_cast<FaceElement*>(sub_geom_obj_pt);
1922 source_el_pt =
1923 dynamic_cast<FiniteElement*>(face_el_pt->bulk_element_pt());
1924 }
1925
1926 // Check if the returned element is halo
1927 if (!source_el_pt->is_halo()) // cannot accept halo here
1928 {
1929 // The correct non-halo element has been located; this will become
1930 // an external haloed element on the current process, and an
1931 // external halo copy needs to be created on the current process
1932 // minus wherever we are in the "ring-loop"
1934
1935 // If iproc is bigger than my_rank then we've "gone through"
1936 // nproc-1
1937 if (my_rank < iproc)
1938 {
1940 }
1941
1942 // So, we found zeta on the current processor
1944
1945 // This source element is an external halo on process
1946 // halo_copy_proc but it should only be added to the storage if it
1947 // hasn't been added already, and this information also needs to
1948 // be communicated over to the other process
1949
1950 unsigned n_extern_haloed =
1951 external_mesh_pt->nexternal_haloed_element(halo_copy_proc);
1952 unsigned external_haloed_el_index =
1953 external_mesh_pt->add_external_haloed_element_pt(halo_copy_proc,
1954 source_el_pt);
1955
1956 // If it was added to the storage then the returned index
1957 // will be the same as the (old) size of the storage
1959 {
1960 // Set Located_element_status to say it
1961 // should be newly created
1963
1964 // How many continuously interpolated values are there?
1965 int n_cont_inter_values = -1;
1966 if (dynamic_cast<RefineableElement*>(source_el_pt) != 0)
1967 {
1969 dynamic_cast<RefineableElement*>(source_el_pt)
1970 ->ncont_interpolated_values();
1971 }
1972
1973 // Since it is (externally) haloed from the current process,
1974 // the info required to create a new element in the equivalent
1975 // external halo layer on process halo_copy_proc needs to be
1976 // sent there
1977
1978 // If we're using macro elements to update...
1981 if (macro_mesh_pt != 0)
1982 {
1983 Flat_packed_unsigneds.push_back(1);
1984#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1986 "Mesh is macro element mesh[2]");
1987#endif
1988 // Cast to finite element... this must work because it's
1989 // a macroelement no update mesh
1991 dynamic_cast<FiniteElement*>(source_el_pt);
1992
1995 // Send the macro element number across
1996 unsigned macro_el_num = macro_el_pt->macro_element_number();
1998#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2000 "Number of macro element[2]");
2001#endif
2002 // we need to send
2003 // the lower left and upper right coordinates of the macro
2005 dynamic_cast<QElementBase*>(source_el_pt);
2006 if (q_el_pt != 0)
2007 {
2008 // The macro element needs to be set first before
2009 // its lower left and upper right coordinates can be
2010 // accessed Now send the lower left and upper right
2011 // coordinates
2012 unsigned el_dim = q_el_pt->dim();
2013 for (unsigned i_dim = 0; i_dim < el_dim; i_dim++)
2014 {
2015 Flat_packed_doubles.push_back(q_el_pt->s_macro_ll(i_dim));
2016 Flat_packed_doubles.push_back(q_el_pt->s_macro_ur(i_dim));
2017 }
2018 }
2019 else // Throw an error
2020 {
2021 std::ostringstream error_stream;
2023 << "You are using a MacroElement node update\n"
2024 << "in a case with non-QElements. This has not\n"
2025 << "yet been implemented.\n";
2026 throw OomphLibError(error_stream.str(),
2029 }
2030 }
2031 else // Not using macro elements to update
2032 {
2033 Flat_packed_unsigneds.push_back(0);
2034#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2036 "Mesh is not a macro element mesh [2]");
2037#endif
2038 }
2039
2040
2041 // Cast to finite element... this must work because it's
2042 // a macroelement no update mesh
2044 dynamic_cast<FiniteElement*>(source_el_pt);
2045#ifdef PARANOID
2046 if (source_finite_el_pt == 0)
2047 {
2048 throw OomphLibError(
2049 "Unable to cast source function to finite element\n",
2050 "Multi_domain_functions::locate_zeta_for_missing_"
2051 "coordinates()",
2053 }
2054#endif
2055
2056
2057 // Loop over the nodes of the new source element
2058 unsigned n_node = source_finite_el_pt->nnode();
2059 for (unsigned j = 0; j < n_node; j++)
2060 {
2062
2063 // Add the node to the storage; this routine
2064 // also takes care of any master nodes if the
2065 // node is hanging
2067 nod_pt,
2068 problem_pt,
2071 }
2072 }
2073 else // it has already been added, so tell the other process
2074 {
2075 // Set Located_element_status to indicate an element has
2076 // already been added
2079#ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2081 "Index of existing external haloed element[2]");
2082#endif
2083 }
2084
2085 // The coordinates returned by locate_zeta are also needed
2086 // in the setup of the source elements on the other process
2088 {
2089 for (unsigned ii = 0; ii < Dim; ii++)
2090 {
2092 }
2093 }
2094 else // translate the coordinates to the bulk element
2095 {
2096 // The translation is from Lagrangian to Eulerian
2098 dynamic_cast<FaceElement*>(sub_geom_obj_pt);
2099 // Get the dimension of the BulkElement
2100 unsigned bulk_el_dim =
2101 dynamic_cast<FiniteElement*>(source_el_pt)->dim();
2103 face_el_pt->get_local_coordinate_in_bulk(ss, s_trans);
2104 for (unsigned ii = 0; ii < bulk_el_dim; ii++)
2105 {
2107 }
2108 }
2109 }
2110 else // halo, so search again until non-halo equivalent is located
2111 {
2112 // Add required information to arrays (as below)
2113 for (unsigned ii = 0; ii < Dim; ii++)
2114 {
2116 }
2117 // It wasn't found here
2119
2120 // Set Located_element_status to indicate not found
2122 }
2123 }
2124 else // not successful this time (i.e. sub_geom_obj_pt==0), so
2125 // prepare for next process to try
2126 {
2127 // Add this global coordinate to the LOCAL zeta array
2128 for (unsigned ii = 0; ii < Dim; ii++)
2129 {
2131 }
2132 // It wasn't found here
2134
2135 // Set Located_element_status to indicate not found
2137 }
2138
2139 } // end of mesh not reached
2140
2141 } // end of loop over flat-packed zeta tuples
2142 }
2143
2144
2145#endif
2146
2147
2148 //=====================================================================
2149 /// locate zeta for current set of "local" coordinates
2150 /// vector-based version
2151 //=====================================================================
2153 const Vector<Mesh*>& mesh_pt,
2154 Mesh* const& external_mesh_pt,
2156 const unsigned& interaction_index)
2157 {
2158 // Flush storage for zetas not found locally
2160
2161 // Number of meshes
2162 unsigned n_mesh = mesh_pt.size();
2163
2164#ifdef PARANOID
2165 if (mesh_geom_obj_pt.size() != n_mesh)
2166 {
2167 std::ostringstream error_stream;
2168 error_stream << "Sizes of mesh_geom_obj_pt [ "
2169 << mesh_geom_obj_pt.size() << " ] and "
2170 << "mesh_pt [ " << n_mesh << " ] don't match.\n";
2171 throw OomphLibError(
2173 }
2174#endif
2175
2176 // Element counter
2177 unsigned e_count = 0;
2178
2179 // Loop over meshes
2180 for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
2181 {
2182 // Number of local elements
2183 unsigned n_element = mesh_pt[i_mesh]->nelement();
2184
2185 // Loop over this processor's elements
2186 for (unsigned e = 0; e < n_element; e++)
2187 {
2189 dynamic_cast<ElementWithExternalElement*>(
2190 mesh_pt[i_mesh]->element_pt(e));
2191#ifdef OOMPH_HAS_MPI
2192 // Only visit non-halo elements -- we're not setting up external
2193 // elements for on-halos!
2194 if (!el_pt->is_halo())
2195#endif
2196 {
2197 // Find number of Gauss points and element dimension
2198 unsigned n_intpt = el_pt->integral_pt()->nweight();
2199 unsigned el_dim = el_pt->dim();
2200
2201
2202#ifdef PARANOID
2203 if (el_dim != Dim)
2204 {
2205 std::ostringstream error_stream;
2206 error_stream << "Dimension of element " << el_dim
2207 << " is not consitent with dimension assumed \n"
2208 << " in multidomain namespace, " << Dim << std::endl;
2209 throw OomphLibError(error_stream.str(),
2212 }
2213#endif
2214
2215 // Set storage for local and global coordinates
2218
2219 // Loop over integration points
2220 for (unsigned ipt = 0; ipt < n_intpt; ipt++)
2221 {
2222 // Has this integration point been done yet?
2224 {
2225 // Get local coordinates
2226 for (unsigned i = 0; i < el_dim; i++)
2227 {
2228 s_local[i] = el_pt->integral_pt()->knot(ipt, i);
2229 }
2230 // Interpolate to global coordinates
2232
2233 // Storage for geometric object and its local coordinates
2238
2239 // Has the required element been located?
2240 if (sub_geom_obj_pt != 0)
2241 {
2242 // The required element has been located
2243 // The located coordinates have the same dimension as the bulk
2246
2247 // Is the bulk element the actual external element?
2249 {
2250 // Use the object directly (it must be a finite element)
2251 source_el_pt =
2252 dynamic_cast<FiniteElement*>(sub_geom_obj_pt);
2253 s_source = s_ext;
2254 }
2255 else
2256 {
2257 // Cast to a FaceElement and use the bulk element
2259 dynamic_cast<FaceElement*>(sub_geom_obj_pt);
2260 source_el_pt = face_el_pt->bulk_element_pt();
2261
2262 // Need to resize the located coordinates to have the same
2263 // dimension as the bulk element
2264 s_source.resize(
2265 dynamic_cast<FiniteElement*>(source_el_pt)->dim());
2266
2267 // Translate the returned local coords into the bulk element
2268 face_el_pt->get_local_coordinate_in_bulk(s_ext, s_source);
2269 }
2270
2271 // Check if it's a halo; if it is then the non-halo equivalent
2272 // needs to be located from another processor (unless we
2273 // accept halo elements as external elements)
2274#ifdef OOMPH_HAS_MPI
2276 (!source_el_pt->is_halo()))
2277#endif
2278 {
2279 // Need to cast to a FiniteElement
2281 dynamic_cast<FiniteElement*>(source_el_pt);
2282
2283 // Set the external element pointer and local coordinates
2284 el_pt->external_element_pt(interaction_index, ipt) =
2286 el_pt->external_element_local_coord(interaction_index,
2287 ipt) = s_source;
2288
2289 // Set the lookup array to 1/true
2291 }
2292#ifdef OOMPH_HAS_MPI
2293 // located element is halo and we're not accepting haloes
2294 // obviously only makes sense in mpi mode...
2295 else
2296 {
2297 // Add required information to arrays
2298 for (unsigned i = 0; i < el_dim; i++)
2299 {
2301 x_global[i]);
2302 }
2303 }
2304#endif
2305 }
2306 else
2307 {
2308 // Search has failed then add the required information to the
2309 // arrays which need to be sent to the other processors so
2310 // that they can perform the locate_zeta
2311
2312 // Add this global coordinate to the LOCAL zeta array
2313 for (unsigned i = 0; i < el_dim; i++)
2314 {
2316 }
2317 }
2318 }
2319 } // end loop over integration points
2320 } // end for halo
2321
2322 // Bump up counter for all elements
2323 e_count++;
2324
2325 } // end loop over local elements
2326
2327 // Mark end of mesh data in flat packed array
2328 for (unsigned i = 0; i < Dim; i++)
2329 {
2331 }
2332
2333 } // end of loop over meshes
2334 }
2335
2336
2337 //=====================================================================
2338 /// Helper function that computes the dimension of the elements within
2339 /// each of the specified meshes (and checks they are the same).
2340 /// Stores result in Dim.
2341 //=====================================================================
2342 void get_dim_helper(Problem* problem_pt,
2343 Mesh* const& mesh_pt,
2344 Mesh* const& external_mesh_pt)
2345 {
2346#ifdef OOMPH_HAS_MPI
2347 // Storage for number of processors, current process and communicator
2348 OomphCommunicator* comm_pt = problem_pt->communicator_pt();
2349#endif
2350
2351 // Extract the element dimensions from the first element of each mesh
2352 unsigned mesh_dim = 0;
2353 if (mesh_pt->nelement() > 0)
2354 {
2355 mesh_dim = dynamic_cast<FiniteElement*>(mesh_pt->element_pt(0))->dim();
2356 }
2357 unsigned external_mesh_dim = 0;
2358 if (external_mesh_pt->nelement() > 0)
2359 {
2361 dynamic_cast<FiniteElement*>(external_mesh_pt->element_pt(0))->dim();
2362 }
2363
2364 // Need to do an Allreduce
2365#ifdef OOMPH_HAS_MPI
2366 int n_proc = comm_pt->nproc();
2367 if (n_proc > 1)
2368 {
2369 unsigned mesh_dim_reduce;
2372 1,
2374 MPI_MAX,
2375 comm_pt->mpi_comm());
2377
2378 unsigned external_mesh_dim_reduce;
2381 1,
2383 MPI_MAX,
2384 comm_pt->mpi_comm());
2386 }
2387#endif
2388
2389 // Check the dimensions are the same!
2391 {
2392 std::ostringstream error_stream;
2393 error_stream << "The elements within the two meshes do not\n"
2394 << "have the same dimension, so the multi-domain\n"
2395 << "method will not work.\n"
2396 << "For the mesh, dim=" << mesh_dim
2397 << ", and the external mesh, dim=" << external_mesh_dim
2398 << "\n";
2399 throw OomphLibError(
2401 }
2402
2403 // Set dimension
2404 Dim = mesh_dim;
2405 }
2406
2407
2408 //=================================================================
2409 /// Helper function that clears all the information used
2410 /// during the external storage creation
2411 //=================================================================
2423
2424 /// Vector of zeta coordinates that we're currently trying to locate;
2425 /// used in sorting of bin entries in further_away() comparison function
2427
2428 /// Comparison function for sorting entries in bin: Returns true if
2429 /// point identified by p1 (comprising pointer to finite element and
2430 /// vector of local coordinates within that element) is closer to
2431 /// Zeta_coords_for_further_away_comparison than p2
2433 const std::pair<FiniteElement*, Vector<double>>& p1,
2434 const std::pair<FiniteElement*, Vector<double>>& p2)
2435 {
2436 // First point
2437 FiniteElement* el_pt = p1.first;
2438 Vector<double> s(p1.second);
2441 double dist_squared1 = 0.0;
2442 for (unsigned i = 0; i < Dim; i++)
2443 {
2444 dist_squared1 +=
2447 }
2448
2449 // Second point
2450 el_pt = p2.first;
2451 s = p2.second;
2453 double dist_squared2 = 0.0;
2454 for (unsigned i = 0; i < Dim; i++)
2455 {
2456 dist_squared2 +=
2459 }
2460
2461 // Which one is further
2463 {
2464 return true;
2465 }
2466 else
2467 {
2468 return false;
2469 }
2470 }
2471 } // namespace Multi_domain_functions
2472
2473} // 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
Algebraic meshes contain AlgebraicElements and AlgebraicNodes. They implement the node update functio...
Algebraic nodes are nodes with an algebraic positional update function.
A class that contains the information required by Nodes that are located on Mesh boundaries....
Definition nodes.h:1996
This is a base class for all elements that require external sources (e.g. FSI, multi-domain problems ...
FaceElements are elements that coincide with the faces of higher-dimensional "bulk" elements....
Definition elements.h:4342
A general Finite Element class.
Definition elements.h:1317
Integral *const & integral_pt() const
Return the pointer to the integration scheme (const version)
Definition elements.h:1967
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:1846
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:4705
double size() const
Calculate the size of the element (length, area, volume,...) in Eulerian computational coordinates....
Definition elements.cc:4320
void locate_zeta(const Vector< double > &zeta, GeomObject *&geom_object_pt, Vector< double > &s, const bool &use_coordinate_as_initial_guess=false)
For a given value of zeta, the "global" intrinsic coordinate of a mesh of FiniteElements represented ...
Definition elements.cc:4764
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:2513
unsigned dim() const
Return the spatial dimension of the element, i.e. the number of local coordinates required to paramet...
Definition elements.h:2615
unsigned nnode() const
Return the number of nodes.
Definition elements.h:2214
MacroElement * macro_elem_pt()
Access function to pointer to macro element.
Definition elements.h:1882
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:2542
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition elements.h:2179
A Generalised Element class.
Definition elements.h:73
bool is_halo() const
Is this element a halo?
Definition elements.h:1150
A geometric object is an object that provides a parametrised description of its shape via the functio...
unsigned ndim() const
Access function to # of Eulerian coordinates.
TimeStepper *& time_stepper_pt()
Access function for pointer to time stepper: Null if object is not time-dependent.
unsigned nlagrangian() const
Access function to # of Lagrangian coordinates.
Class that contains data for hanging nodes.
Definition nodes.h:742
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...
MacroElementNodeUpdate nodes are nodes with a positional update function, based on their element's Ma...
Base class for MacroElement s that are used during mesh refinement in domains with curvlinear and/or ...
A general mesh class.
Definition mesh.h:67
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
Definition mesh.h:452
unsigned long nelement() const
Return number of elements in the mesh.
Definition mesh.h:598
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition nodes.h:906
An oomph-lib wrapper to the MPI_Comm communicator object. Just contains an MPI_Comm object (which is ...
An OomphLibError object which should be thrown when an run-time error is encountered....
////////////////////////////////////////////////////////////////// //////////////////////////////////...
Definition problem.h:154
OomphCommunicator * communicator_pt()
access function to the oomph-lib communicator
Definition problem.h:1266
TimeStepper *& time_stepper_pt()
Access function for the pointer to the first (presumably only) timestepper.
Definition problem.h:1544
unsigned ntime_stepper() const
Return the number of time steppers.
Definition problem.h:1710
Base class for Qelements.
Definition Qelements.h:91
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
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
Base class for time-stepping schemes. Timestepper provides an approximation of the temporal derivativ...
unsigned ntstorage() const
Return the number of doubles required to represent history (one for steady)
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...
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...
unsigned Dim
Dimension of zeta tuples (set by get_dim_helper) – needed because we store the scalar coordinates in ...
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 ...
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...
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...
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...
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....
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...