multi_domain.template.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// Version 1.0; svn revision $LastChangedRevision$
7 //LIC//
8 //LIC// $LastChangedDate$
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 //Templated multi-domain functions
31 
32 //Include guards to prevent multiple inclusion of the header
33 #ifndef OOMPH_MULTI_DOMAIN_CC
34 #define OOMPH_MULTI_DOMAIN_CC
35 
36 // Config header generated by autoconfig
37 #ifdef HAVE_CONFIG_H
38 #include <oomph-lib-config.h>
39 #endif
40 
41 //Oomph-lib headers
42 #include "geom_objects.h"
43 #include "problem.h"
44 #include "shape.h"
45 
46 #include "mesh.h"
48 #include "algebraic_elements.h"
50 #include "Qelements.h"
52 #include "multi_domain.h"
54 
55 //Needed to check if elements have nonuniformly spaced nodes
56 #include "refineable_elements.h"
57 #include "Qspectral_elements.h"
58 
59 namespace oomph
60 {
61 
62 
63 //// Templated helper functions for multi-domain methods using locate_zeta
64 
65 
66  //============================================================================
67  /// Identify the \c FaceElements (stored in the mesh pointed to by
68  /// \c face_mesh_pt) that are adjacent to the bulk elements next to the
69  /// \c boundary_in_bulk_mesh -th boundary of the mesh pointed to by
70  /// \c bulk_mesh_pt. The \c FaceElements must be derived
71  /// from the \c ElementWithExternalElement base class and the adjacent
72  /// bulk elements are stored as their external elements.
73  ///
74  /// This is the vector-based version which deals with multiple bulk
75  /// mesh boundaries at the same time.
76  //============================================================================
77  template<class BULK_ELEMENT, unsigned DIM>
79  Problem* problem_pt,
80  Vector<unsigned>& boundary_in_bulk_mesh,
81  Mesh* const &bulk_mesh_pt,
82  Vector<Mesh*>& face_mesh_pt,
83  const unsigned& interaction)
84  {
85 
86  unsigned n_mesh=boundary_in_bulk_mesh.size();
87 
88 #ifdef PARANOID
89  // Check sizes match
90  if (boundary_in_bulk_mesh.size()!=face_mesh_pt.size())
91  {
92  std::ostringstream error_message;
93  error_message
94  << "Sizes of vector of boundary ids in bulk mesh ("
95  << boundary_in_bulk_mesh.size() << ") and vector of pointers\n"
96  << "to FaceElements (" << face_mesh_pt.size() << " doesn't match.\n";
97  throw OomphLibError(
98  error_message.str(),
99  OOMPH_CURRENT_FUNCTION,
100  OOMPH_EXCEPTION_LOCATION);
101  }
102 #endif
103 
104  // Create face meshes adjacent to the bulk mesh's b-th boundary.
105  // Each face mesh consists of FaceElements that may also be
106  // interpreted as GeomObjects
107  Vector<Mesh*> bulk_face_mesh_pt(n_mesh);
108 
109  // Loop over all meshes
110  for (unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
111  {
112  bulk_face_mesh_pt[i_mesh] = new Mesh;
113  bulk_mesh_pt->template build_face_mesh
114  <BULK_ELEMENT,FaceElementAsGeomObject>(boundary_in_bulk_mesh[i_mesh],
115  bulk_face_mesh_pt[i_mesh]);
116 
117  // Loop over these new face elements and tell them the boundary number
118  // from the bulk mesh -- this is required to they can
119  // get access to the boundary coordinates!
120  unsigned n_face_element = bulk_face_mesh_pt[i_mesh]->nelement();
121  for(unsigned e=0;e<n_face_element;e++)
122  {
123  //Cast the element pointer to the correct thing!
126  (bulk_face_mesh_pt[i_mesh]->element_pt(e));
127 
128  // Set bulk boundary number
129  el_pt->set_boundary_number_in_bulk_mesh(boundary_in_bulk_mesh[i_mesh]);
130 
131  // Doc?
132  if (Doc_boundary_coordinate_file.is_open())
133  {
134  Vector<double> s(DIM-1);
135  Vector<double> zeta(DIM-1);
136  Vector<double> x(DIM);
137  unsigned n_plot=5;
139 
140  // Loop over plot points
141  unsigned num_plot_points=el_pt->nplot_points(n_plot);
142  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
143  {
144  // Get local coordinates of plot point
145  el_pt->get_s_plot(iplot,n_plot,s);
146  el_pt->interpolated_zeta(s,zeta);
147  el_pt->interpolated_x(s,x);
148  for (unsigned i=0;i<DIM;i++)
149  {
150  Doc_boundary_coordinate_file << x[i] << " ";
151  }
152  for (unsigned i=0;i<DIM-1;i++)
153  {
154  Doc_boundary_coordinate_file << zeta[i] << " ";
155  }
156  Doc_boundary_coordinate_file << std::endl;
157  }
159  }
160  }
161 
162  // Now sort the elements based on the boundary coordinates.
163  // This may allow a faster implementation of the locate_zeta
164  // function for the MeshAsGeomObject representation of this
165  // mesh, but also creates a unique ordering of the elements
166  std::sort(bulk_face_mesh_pt[i_mesh]->element_pt().begin(),
167  bulk_face_mesh_pt[i_mesh]->element_pt().end(),
169  } // end of loop over meshes
170 
171 
172 
173  // Setup the interactions for this problem using the surface mesh
174  // on the fluid mesh. The interaction parameter in this instance is
175  // given by the "face" parameter.
178  (problem_pt,face_mesh_pt,bulk_mesh_pt,
179  bulk_face_mesh_pt,interaction);
180 
181 
182  // Loop over all meshes to clean up
183  for (unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
184  {
185  unsigned n_face_element = bulk_face_mesh_pt[i_mesh]->nelement();
186 
187  //The MeshAsGeomObject has already been deleted (in set_external_storage)
188 
189  //Must be careful with the FaceMesh, because we cannot delete the nodes
190  //Loop over the elements backwards (paranoid!) and delete them
191  for(unsigned e=n_face_element;e>0;e--)
192  {
193  delete bulk_face_mesh_pt[i_mesh]->element_pt(e-1);
194  bulk_face_mesh_pt[i_mesh]->element_pt(e-1) = 0;
195  }
196  //Now clear all element and node storage (should maybe fine-grain this)
197  bulk_face_mesh_pt[i_mesh]->flush_element_and_node_storage();
198 
199  //Finally delete the mesh
200  delete bulk_face_mesh_pt[i_mesh];
201 
202  } // end of loop over meshes
203 
204  }
205 
206 
207 //========================================================================
208  /// Identify the \c FaceElements (stored in the mesh pointed to by
209  /// \c face_mesh_pt) that are adjacent to the bulk elements next to the
210  /// \c boundary_in_bulk_mesh -th boundary of the mesh pointed to by
211  /// \c bulk_mesh_pt. The \c FaceElements must be derived
212  /// from the \c ElementWithExternalElement base class and the adjacent
213  /// bulk elements are stored as their external elements.
214 //========================================================================
215  template<class BULK_ELEMENT,unsigned DIM>
217  Problem* problem_pt,
218  const unsigned& boundary_in_bulk_mesh,
219  Mesh* const& bulk_mesh_pt,
220  Mesh* const& face_mesh_pt,
221  const unsigned& interaction)
222  {
223  // Convert to vector-based storage
224  Vector<unsigned> boundary_in_bulk_mesh_vect(1);
225  boundary_in_bulk_mesh_vect[0]=boundary_in_bulk_mesh;
226  Vector<Mesh*> face_mesh_pt_vect(1);
227  face_mesh_pt_vect[0]=face_mesh_pt;
228 
229  // Call vector-based version
230  setup_bulk_elements_adjacent_to_face_mesh<BULK_ELEMENT,DIM>(
231  problem_pt, boundary_in_bulk_mesh_vect, bulk_mesh_pt,
232  face_mesh_pt_vect,interaction);
233 
234  }
235 
236 
237 //========================================================================
238 /// Set up the two-way multi-domain interactions for the
239 /// problem pointed to by \c problem_pt.
240 /// Use this for cases where first_mesh_pt and second_mesh_pt
241 /// occupy the same physical space and are populated by
242 /// ELEMENT_0 and ELEMENT_1 respectively, and are combined to solve
243 /// a single problem. The elements in two meshes interact both ways
244 /// the elements in each mesh act as "external elements" for the
245 /// elements in the "other" mesh. The interaction indices allow the
246 /// specification of which interaction we're setting up in the two
247 /// meshes. They default to zero, which is appropriate if there's
248 /// only a single interaction.
249 //========================================================================
250  template<class ELEMENT_0,class ELEMENT_1>
252  (Problem* problem_pt,Mesh* const &first_mesh_pt, Mesh* const &second_mesh_pt,
253  const unsigned& first_interaction, const unsigned& second_interaction)
254  {
255  // Delete all the current external halo(ed) element and node storage
256  first_mesh_pt->delete_all_external_storage();
257  second_mesh_pt->delete_all_external_storage();
258 
259  // Call setup_multi_domain_interaction in both directions
260  setup_multi_domain_interaction<ELEMENT_1>
261  (problem_pt,first_mesh_pt,second_mesh_pt,first_interaction);
262 
263  setup_multi_domain_interaction<ELEMENT_0>
264  (problem_pt,second_mesh_pt,first_mesh_pt,second_interaction);
265 
266  }
267 
268 
269 //========================================================================
270  /// Function to set up the one-way multi-domain interaction for
271  /// problems where the meshes pointed to by \c mesh_pt and \c external_mesh_pt
272  /// occupy the same physical space, and the elements in \c external_mesh_pt
273  /// act as "external elements" for the \c ElementWithExternalElements
274  /// in \c mesh_pt (but not vice versa):
275  /// - \c mesh_pt points to the mesh of ElemenWithExternalElements for which
276  /// the interaction is set up.
277  /// - \c external_mesh_pt points to the mesh that contains the elements
278  /// of type EXT_ELEMENT that act as "external elements" for the
279  /// \c ElementWithExternalElements in \c mesh_pt.
280  /// - The interaction_index parameter defaults to zero and must be otherwise
281  /// set by the user if there is more than one mesh that provides sources
282  /// for the Mesh pointed to by mesh_pt.
283 //========================================================================
284  template<class EXT_ELEMENT>
286  (Problem* problem_pt, Mesh* const &mesh_pt, Mesh* const &external_mesh_pt,
287  const unsigned& interaction_index)
288  {
289  // Bulk elements must not be external elements in this case
291 
292  // Call the auxiliary function with GEOM_OBJECT=EXT_ELEMENT
293  // and EL_DIM_EUL=EL_DIM_LAG=dimension returned from helper function
294  get_dim_helper(problem_pt,mesh_pt,external_mesh_pt);
295 
296  if(Dim > 3)
297  {
298  std::ostringstream error_stream;
299  error_stream << "The elements within the two interacting meshes have a\n"
300  << "dimension not equal to 1, 2 or 3.\n"
301  << "The multi-domain method will not work in this case.\n"
302  << "The dimension is: " << Dim << "\n";
303  throw OomphLibError
304  (error_stream.str(),
305  OOMPH_CURRENT_FUNCTION,
306  OOMPH_EXCEPTION_LOCATION);
307  }
308 
309  // Wrapper for each dimension (template parameter)
310  aux_setup_multi_domain_interaction<EXT_ELEMENT,EXT_ELEMENT>
311  (problem_pt,mesh_pt,external_mesh_pt,interaction_index);
312 
313  }
314 
315 
316 //========================================================================
317  /// Function to set up the one-way multi-domain interaction for
318  /// FSI-like problems.
319  /// - \c mesh_pt points to the mesh of \c ElemenWithExternalElements for which
320  /// the interaction is set up. In an FSI example, this mesh would contain
321  /// the \c FSIWallElements (either beam/shell elements or the
322  /// \c FSISolidTractionElements that apply the traction to
323  /// a "bulk" solid mesh that is loaded by the fluid.)
324  /// - \c external_mesh_pt points to the mesh that contains the elements
325  /// of type EXT_ELEMENT that provide the "source" for the
326  /// \c ElementWithExternalElements. In an FSI example, this
327  /// mesh would contain the "bulk" fluid elements.
328  /// - \c external_face_mesh_pt points to the mesh of \c FaceElements
329  /// attached to the \c external_mesh_pt. The mesh pointed to by
330  /// \c external_face_mesh_pt has the same dimension as \c mesh_pt.
331  /// The elements contained in \c external_face_mesh_pt are of type
332  /// FACE_ELEMENT_GEOM_OBJECT. In an FSI example, these elements
333  /// are usually the \c FaceElementAsGeomObjects (templated by the
334  /// type of the "bulk" fluid elements to which they are attached)
335  /// that define the FSI boundary of the fluid domain.
336  /// - The interaction_index parameter defaults to zero and must otherwise be
337  /// set by the user if there is more than one mesh that provides "external
338  /// elements" for the Mesh pointed to by mesh_pt (e.g. in the case
339  /// when a beam or shell structure is loaded by fluid from both sides.)
340 //========================================================================
341  template<class EXT_ELEMENT,class FACE_ELEMENT_GEOM_OBJECT>
343  (Problem* problem_pt, Mesh* const &mesh_pt, Mesh* const &external_mesh_pt,
344  Mesh* const &external_face_mesh_pt, const unsigned& interaction_index)
345  {
346  // Bulk elements must be external elements in this case
348 
349  // Call the auxiliary routine with GEOM_OBJECT=FACE_ELEMENT_GEOM_OBJECT
350  // and EL_DIM_LAG=Dim, EL_DIM_EUL=Dim+1
351  get_dim_helper(problem_pt,mesh_pt,external_face_mesh_pt);
352 
353  if(Dim > 2)
354  {
355  std::ostringstream error_stream;
356  error_stream << "The elements within the two interacting meshes have a\n"
357  << "dimension not equal to 1 or 2.\n"
358  << "The multi-domain method will not work in this case.\n"
359  << "The dimension is: " << Dim << "\n";
360  throw OomphLibError
361  (error_stream.str(),
362  OOMPH_CURRENT_FUNCTION,
363  OOMPH_EXCEPTION_LOCATION);
364  }
365 
366  // Call the function that actually does the work
368  <EXT_ELEMENT,FACE_ELEMENT_GEOM_OBJECT>
369  (problem_pt,mesh_pt,external_mesh_pt,
370  interaction_index,external_face_mesh_pt);
371  }
372 
373 
374 //========================================================================
375  /// Function to set up the one-way multi-domain interaction for
376  /// FSI-like problems.
377  /// - \c mesh_pt points to the mesh of \c ElemenWithExternalElements for which
378  /// the interaction is set up. In an FSI example, this mesh would contain
379  /// the \c FSIWallElements (either beam/shell elements or the
380  /// \c FSISolidTractionElements that apply the traction to
381  /// a "bulk" solid mesh that is loaded by the fluid.)
382  /// - \c external_mesh_pt points to the mesh that contains the elements
383  /// of type EXT_ELEMENT that provide the "source" for the
384  /// \c ElementWithExternalElements. In an FSI example, this
385  /// mesh would contain the "bulk" fluid elements.
386  /// - \c external_face_mesh_pt points to the mesh of \c FaceElements
387  /// attached to the \c external_mesh_pt. The mesh pointed to by
388  /// \c external_face_mesh_pt has the same dimension as \c mesh_pt.
389  /// The elements contained in \c external_face_mesh_pt are of type
390  /// FACE_ELEMENT_GEOM_OBJECT. In an FSI example, these elements
391  /// are usually the \c FaceElementAsGeomObjects (templated by the
392  /// type of the "bulk" fluid elements to which they are attached)
393  /// that define the FSI boundary of the fluid domain.
394  /// - The interaction_index parameter defaults to zero and must otherwise be
395  /// set by the user if there is more than one mesh that provides "external
396  /// elements" for the Mesh pointed to by mesh_pt (e.g. in the case
397  /// when a beam or shell structure is loaded by fluid from both sides.)
398  /// .
399  /// Vector-based version operates simultaneously on the meshes contained
400  /// in the vectors.
401 //========================================================================
402  template<class EXT_ELEMENT,class FACE_ELEMENT_GEOM_OBJECT>
404  (Problem* problem_pt, const Vector<Mesh*>& mesh_pt,
405  Mesh* const &external_mesh_pt, const Vector<Mesh*>& external_face_mesh_pt,
406  const unsigned& interaction_index)
407  {
408 
409  // How many meshes do we have?
410  unsigned n_mesh=mesh_pt.size();
411 
412 #ifdef PARANOID
413  if (external_face_mesh_pt.size()!=n_mesh)
414  {
415  std::ostringstream error_stream;
416  error_stream << "Sizes of external_face_mesh_pt [ "
417  << external_face_mesh_pt.size() << " ] and "
418  << "mesh_pt [ " << n_mesh << " ] don't match.\n";
419  throw OomphLibError
420  (error_stream.str(),
421  OOMPH_CURRENT_FUNCTION,
422  OOMPH_EXCEPTION_LOCATION);
423  }
424 #endif
425 
426  // Bail out?
427  if (n_mesh==0) return;
428 
429  // Bulk elements must be external elements in this case
431 
432  // Call the auxiliary routine with GEOM_OBJECT=FACE_ELEMENT_GEOM_OBJECT
433  // and EL_DIM_LAG=Dim, EL_DIM_EUL=Dim+1. Use first mesh only.
434  get_dim_helper(problem_pt,mesh_pt[0],external_face_mesh_pt[0]);
435 
436 
437 #ifdef PARANOID
438  // Check consitency
439  unsigned old_dim=Dim;
440  for (unsigned i=1;i<n_mesh;i++)
441  {
442  // Set up Dim again
443  get_dim_helper(problem_pt,mesh_pt[i],external_face_mesh_pt[i]);
444 
445  if (Dim!=old_dim)
446  {
447  std::ostringstream error_stream;
448  error_stream
449  << "Inconsistency: Mesh " << i << " has Dim=" << Dim
450  << "while mesh 0 has Dim="<< old_dim << std::endl;
451  throw OomphLibError
452  (error_stream.str(),
453  OOMPH_CURRENT_FUNCTION,
454  OOMPH_EXCEPTION_LOCATION);
455  }
456  }
457 #endif
458 
459  if(Dim > 2)
460  {
461  std::ostringstream error_stream;
462  error_stream << "The elements within the two interacting meshes have a\n"
463  << "dimension not equal to 1 or 2.\n"
464  << "The multi-domain method will not work in this case.\n"
465  << "The dimension is: " << Dim << "\n";
466  throw OomphLibError
467  (error_stream.str(),
468  OOMPH_CURRENT_FUNCTION,
469  OOMPH_EXCEPTION_LOCATION);
470  }
471 
472  // Now do the actual work for all meshes simultaneously
474  <EXT_ELEMENT,FACE_ELEMENT_GEOM_OBJECT>
475  (problem_pt,mesh_pt,external_mesh_pt,
476  interaction_index,external_face_mesh_pt);
477 
478  }
479 
480 
481 
482 
483 //========================================================================
484 /// This routine calls the locate_zeta routine (simultaneously on each
485 /// processor for each individual processor's element set if necessary)
486 /// and sets up the external (halo) element and node storage as
487 /// necessary. The locate_zeta procedure here works for all multi-domain
488 /// problems where either two meshes occupy the same physical space but have
489 /// differing element types (e.g. a Boussinesq convection problem where
490 /// AdvectionDiffusion elements interact with Navier-Stokes type elements)
491 /// or two meshes interact along some boundary of the external mesh,
492 /// represented by a "face mesh", such as an FSI problem.
493 //========================================================================
494  template<class EXT_ELEMENT,class GEOM_OBJECT>
496  (Problem* problem_pt, Mesh* const &mesh_pt, Mesh* const &external_mesh_pt,
497  const unsigned& interaction_index, Mesh* const &external_face_mesh_pt)
498  {
499  // Convert to vector-based storage
500  Vector<Mesh*> mesh_pt_vector(1);
501  mesh_pt_vector[0]=mesh_pt;
502  Vector<Mesh*> external_face_mesh_pt_vector(1);
503  external_face_mesh_pt_vector[0]=external_face_mesh_pt;
504 
505  // Call vector-based version
506  aux_setup_multi_domain_interaction<EXT_ELEMENT,GEOM_OBJECT>
507  (problem_pt, mesh_pt_vector,
508  external_mesh_pt, interaction_index,
509  external_face_mesh_pt_vector);
510 
511  } // end of aux_setup_multi_domain_interaction
512 
513 
514 
515 
516 
517 //========================================================================
518 /// This routine calls the locate_zeta routine (simultaneously on each
519 /// processor for each individual processor's element set if necessary)
520 /// and sets up the external (halo) element and node storage as
521 /// necessary. The locate_zeta procedure here works for all multi-domain
522 /// problems where either two meshes occupy the same physical space but have
523 /// differing element types (e.g. a Boussinesq convection problem where
524 /// AdvectionDiffusion elements interact with Navier-Stokes type elements)
525 /// or two meshes interact along some boundary of the external mesh,
526 /// represented by a "face mesh", such as an FSI problem.
527 ///
528 /// Vector-based version operates simultaneously on the meshes contained
529 /// in the vectors.
530 //========================================================================
531  template<class EXT_ELEMENT,class GEOM_OBJECT>
533  (Problem* problem_pt, const Vector<Mesh*>& mesh_pt,
534  Mesh* const &external_mesh_pt, const unsigned& interaction_index,
535  const Vector<Mesh*>& external_face_mesh_pt)
536  {
537  // How many meshes do we have?
538  unsigned n_mesh=mesh_pt.size();
539 
540 #ifdef PARANOID
541  if (external_face_mesh_pt.size()!=n_mesh)
542  {
543  std::ostringstream error_stream;
544  error_stream << "Sizes of external_face_mesh_pt [ "
545  << external_face_mesh_pt.size() << " ] and "
546  << "mesh_pt [ " << n_mesh << " ] don't match.\n";
547  throw OomphLibError
548  (error_stream.str(),
549  OOMPH_CURRENT_FUNCTION,
550  OOMPH_EXCEPTION_LOCATION);
551  }
552 #endif
553 
554  // Bail out?
555  if (n_mesh==0) return;
556 
557  //Multi-domain setup will not work for elements with
558  //nonuniformly spaced nodes
559  //Must check type of elements in the mesh and in the external mesh
560  //(assume element type is the same for all elements in each mesh)
561 
562 #ifdef PARANOID
563 
564  // Pointer to first element in external mesh
565  GeneralisedElement* ext_el_pt_0=0;
566  if (external_mesh_pt->nelement()!=0)
567  {
568  ext_el_pt_0 = external_mesh_pt->element_pt(0);
569  }
570 
571  // Loop over all meshes
572  for (unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
573  {
574  //Get pointer to first element in each mesh
575  GeneralisedElement* el_pt_0=0;
576  if (mesh_pt[i_mesh]->nelement()!=0)
577  {
578  el_pt_0 = mesh_pt[i_mesh]->element_pt(0);
579  }
580 
581  //Check they are not spectral elements
582  if(dynamic_cast<SpectralElement*>(el_pt_0)!=0
583  || dynamic_cast<SpectralElement*>(ext_el_pt_0)!=0)
584  {
585  throw OomphLibError(
586  "Multi-domain setup does not work with spectral elements.",
587  OOMPH_CURRENT_FUNCTION,
588  OOMPH_EXCEPTION_LOCATION);
589  }
590 
591  //Check they are not hp-refineable elements
592  if(dynamic_cast<PRefineableElement*>(el_pt_0)!=0
593  || dynamic_cast<PRefineableElement*>(ext_el_pt_0)!=0)
594  {
595  throw OomphLibError(
596  "Multi-domain setup does not work with hp-refineable elements.",
597  OOMPH_CURRENT_FUNCTION,
598  OOMPH_EXCEPTION_LOCATION);
599  }
600  } // end over initial loop over meshes
601 
602 #endif
603 
604 
605 
606 #ifdef OOMPH_HAS_MPI
607  // Storage for number of processors and my rank
608  int n_proc=problem_pt->communicator_pt()->nproc();
609  int my_rank=problem_pt->communicator_pt()->my_rank();
610 #endif
611 
612  // Timing
613  double t_start=0.0; double t_end=0.0; double t_local=0.0;
614  double t_set=0.0; double t_locate=0.0; double t_spiral_start=0.0;
615 #ifdef OOMPH_HAS_MPI
616  double t_loop_start=0.0;
617  double t_sendrecv=0.0;
618  double t_missing=0.0;
619  double t_send_info=0.0; double t_create_halo=0.0;
620 #endif
621 
622  if (Doc_timings)
623  {
624  t_start=TimingHelpers::timer();
625  }
626 
627  // Initialize number of zeta coordinates not found yet
628  unsigned n_zeta_not_found=0;
629 
630  // Geometric objects used to represent the external (face) meshes
631  Vector<MeshAsGeomObject*> mesh_geom_obj_pt(n_mesh,0);
632 
633 #ifdef PARANOID
634 
635  // Initialise lagrangian dimension of element (test only)
636  unsigned el_dim_lag = 0;
637 
638 #endif
639 
640  // Create mesh as geom objects for all meshes
641  for (unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
642  {
643  // Are bulk elements used as external elements?
645  {
646  // Fix this when required
647  if (n_mesh!=1)
648  {
649  std::ostringstream error_stream;
650  error_stream
651  << "Sorry I currently can't deal with non-bulk external elements\n"
652  << "in multi-domain setup for multiple meshes.\n"
653  << "The functionality should be easy to implement now that you\n"
654  << "have a test case. If you're not willinig to do this, call\n"
655  << "the multi-domain setup mesh-by-mesh instead (though this can\n"
656  << "be costly in parallel because of global comms. \n";
657  throw OomphLibError
658  (error_stream.str(),
659  OOMPH_CURRENT_FUNCTION,
660  OOMPH_EXCEPTION_LOCATION);
661  }
662 
663  // Set the geometric object from the external mesh
664  mesh_geom_obj_pt[0]=new MeshAsGeomObject(external_mesh_pt);
665  }
666  else
667  {
668  // Set the geometric object from the external face mesh argument
669  mesh_geom_obj_pt[i_mesh]=
670  new MeshAsGeomObject(external_face_mesh_pt[i_mesh]);
671  }
672 
673 #ifdef PARANOID
674  unsigned old_el_dim_lag=el_dim_lag;
675 
676  // Set lagrangian dimension of element
677  el_dim_lag = mesh_geom_obj_pt[i_mesh]->nlagrangian();
678 
679  // Check consistency
680  if (i_mesh>0)
681  {
682  if (el_dim_lag!=old_el_dim_lag)
683  {
684  std::ostringstream error_stream;
685  error_stream << "Lagrangian dimensions of elements don't match \n "
686  << "between meshes: " << el_dim_lag << " "
687  << old_el_dim_lag << "\n";
688  throw OomphLibError
689  (error_stream.str(),
690  OOMPH_CURRENT_FUNCTION,
691  OOMPH_EXCEPTION_LOCATION);
692  }
693  }
694 #endif
695 
696 
697  }// end of loop over meshes
698 
699  double t_setup_lookups=0.0;
700  if (Doc_timings)
701  {
702  t_set=TimingHelpers::timer();
703  oomph_info << "CPU for creation of MeshAsGeomObjects and bin structure: "
704  << t_set-t_start << std::endl;
705  t_setup_lookups=TimingHelpers::timer();
706  }
707 
708  // Total number of integration points
709  unsigned tot_int=0;
710 
711  // Counter for total number of elements (in flat packed order)
712  unsigned e_count=0;
713 
714  // Loop over all meshes to get total number of elements
715  for (unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
716  {
717  e_count+=mesh_pt[i_mesh]->nelement();
718  }
719  External_element_located.resize(e_count);
720 
721  // Reset counter for elements in flat packed storage
722  e_count=0;
723 
724  // Loop over all meshes
725  for (unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
726  {
727  // Loop over (this processor's) elements and set lookup array
728  unsigned n_element=mesh_pt[i_mesh]->nelement();
729  for (unsigned e=0;e<n_element;e++)
730  {
731  // Zero-sized vector means its a halo
732  External_element_located[e_count].resize(0);
734  dynamic_cast<ElementWithExternalElement*>(
735  mesh_pt[i_mesh]->element_pt(e));
736 
737 #ifdef OOMPH_HAS_MPI
738  // We're not setting up external elements for halo elements
739  if (!el_pt->is_halo())
740 #endif
741  {
742  //We need to allocate storage for the external elements
743  //within the element. Memory will actually only be
744  //allocated the first time this function is called for
745  //each element, or if the number of interactions or integration
746  //points within the element has changed.
748 
749  // Clear any previous allocation
750  unsigned n_intpt=el_pt->integral_pt()->nweight();
751  for (unsigned ipt=0;ipt<n_intpt;ipt++)
752  {
753  el_pt->external_element_pt(interaction_index,ipt)=0;
754  }
755 
756  External_element_located[e_count].resize(n_intpt);
757  for (unsigned ipt=0;ipt<n_intpt;ipt++)
758  {
759  External_element_located[e_count][ipt]=0;
760  tot_int++;
761  }
762  }
763  // next element
764  e_count++;
765  }
766  } // end of loop over meshes
767 
768  if (Doc_timings)
769  {
770  double t=TimingHelpers::timer();
771  oomph_info
772  << "CPU for setup of lookup schemes for located elements/coords: "
773  << t-t_setup_lookups << std::endl;
774  }
775 
776  // Initialise maximum spiral level within the cartesian bin structure
777  // Used to terminate spiraling for non-refineable bin
778  unsigned n_max_level=0;
779 
780 #ifdef OOMPH_HAS_MPI
781  unsigned max_level_reached=1;
782 #endif
783 
784  // Max. number of sample points -- used to decide on termination of
785  // "spiraling"
786  unsigned max_n_sample_points_of_sample_point_containers = 0;
787 
788  // Loop over all meshes
789  for (unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
790  {
791 
792  if (mesh_geom_obj_pt[i_mesh]->sample_point_container_version()==
794  {
795  RefineableBinArray* bin_array_pt=
796  dynamic_cast<RefineableBinArray*>(mesh_geom_obj_pt[i_mesh]->
797  sample_point_container_pt());
798 
799  bin_array_pt->
800  last_sample_point_to_actually_lookup_during_locate_zeta() =
801  bin_array_pt->
802  initial_last_sample_point_to_actually_lookup_during_locate_zeta();
803  bin_array_pt->
804  first_sample_point_to_actually_lookup_during_locate_zeta() = 0;
805 
806  unsigned nsp=bin_array_pt->
807  total_number_of_sample_points_computed_recursively();
808  if (nsp>max_n_sample_points_of_sample_point_containers)
809  {
810  max_n_sample_points_of_sample_point_containers=nsp;
811  }
812 
813 
814 #ifdef OOMPH_HAS_MPI
815  // If the mesh has been distributed we want the max. number
816  // of sample points across all processors
817  if (problem_pt->communicator_pt()->nproc() > 1)
818  {
819  unsigned local_max_n_sample_points_of_sample_point_containers=
820  max_n_sample_points_of_sample_point_containers;
821 
822  //Get maximum over all processors
823  MPI_Allreduce(&local_max_n_sample_points_of_sample_point_containers,
824  &max_n_sample_points_of_sample_point_containers,1,
825  MPI_UNSIGNED,MPI_MAX,
826  problem_pt->communicator_pt()->mpi_comm());
827  }
828 #endif
829 
830  }
831  else if (mesh_geom_obj_pt[i_mesh]->sample_point_container_version()==
833  {
834  NonRefineableBinArray* bin_array_pt=
835  dynamic_cast<NonRefineableBinArray*>(mesh_geom_obj_pt[i_mesh]->
836  sample_point_container_pt());
837 
838  // Initialise spiral levels
839  bin_array_pt->current_min_spiral_level()=0;
840  bin_array_pt->current_max_spiral_level()=
841  bin_array_pt->n_spiral_chunk()-1;
842 
843  // Find maximum spiral level within the cartesian bin structure
844  n_max_level=bin_array_pt->max_bin_dimension();
845 
846  // Limit it
847  if (bin_array_pt->current_max_spiral_level()>n_max_level)
848  {
849  bin_array_pt->current_max_spiral_level()=n_max_level-1;
850  }
851  }
852 #ifdef OOMPH_HAS_CGAL
853  // CGAL
854  else if (mesh_geom_obj_pt[i_mesh]->sample_point_container_version()==
856  {
857  CGALSamplePointContainer* bin_array_pt=
858  dynamic_cast<CGALSamplePointContainer*>(mesh_geom_obj_pt[i_mesh]->
859  sample_point_container_pt());
860  bin_array_pt->
861  last_sample_point_to_actually_lookup_during_locate_zeta() =
862  bin_array_pt->
863  initial_last_sample_point_to_actually_lookup_during_locate_zeta();
864  bin_array_pt->
865  first_sample_point_to_actually_lookup_during_locate_zeta() = 0;
866 
867  unsigned nsp=bin_array_pt->
868  total_number_of_sample_points_computed_recursively();
869  if (nsp>max_n_sample_points_of_sample_point_containers)
870  {
871  max_n_sample_points_of_sample_point_containers=nsp;
872  }
873 
874 
875 #ifdef OOMPH_HAS_MPI
876  // If the mesh has been distributed we want the max. number
877  // of sample points across all processors
878  if (problem_pt->communicator_pt()->nproc() > 1)
879  {
880  unsigned local_max_n_sample_points_of_sample_point_containers=
881  max_n_sample_points_of_sample_point_containers;
882 
883  //Get maximum over all processors
884  MPI_Allreduce(&local_max_n_sample_points_of_sample_point_containers,
885  &max_n_sample_points_of_sample_point_containers,1,
886  MPI_UNSIGNED,MPI_MAX,
887  problem_pt->communicator_pt()->mpi_comm());
888  }
889 #endif
890  }
891 #endif // cgal
892  }
893 
894 
895  // Storage for info about coordinate location
896  Vector<double> percentage_coords_located_locally;
897  Vector<double> percentage_coords_located_elsewhere;
898 
899  // Loop over "spirals/levels" away from the current position
900  // Note: All meshes go through their spirals simultaneously;
901  // read out spiral level from first one
902  unsigned i_level = 0;
903  bool has_not_reached_max_level_of_search=true;
904  while (has_not_reached_max_level_of_search)
905  {
906 
907  // Record time at start of spiral loop
908  if (Doc_timings)
909  {
910  t_spiral_start = TimingHelpers::timer();
911  }
912 
913  // Perform locate_zeta locally first! This looks locally for
914  // all not-yet-located zetas within the current spiral range.
915  locate_zeta_for_local_coordinates(mesh_pt, external_mesh_pt,
916  mesh_geom_obj_pt,
917  interaction_index);
918 
919  // Store stats about successful locates for reporting later
920  if (Doc_stats)
921  {
922  unsigned count_locates = 0;
923  unsigned n_ext_loc = External_element_located.size();
924  for (unsigned e=0;e<n_ext_loc;e++)
925  {
926  unsigned n_intpt = External_element_located[e].size();
927  for (unsigned ipt=0;ipt<n_intpt;ipt++)
928  {
929  count_locates += External_element_located[e][ipt];
930  }
931  }
932 
933  // Store percentage of integration points successfully located.
934  // Only assign if we had anything to allocte, otherwise 100%
935  // (default assignment; see above) is correct
936  if (tot_int != 0)
937  {
938  percentage_coords_located_locally.push_back(
939  100.0 * double(count_locates) / double(tot_int));
940  }
941  else
942  {
943  // Had none to find so we found them all!
944  percentage_coords_located_locally.push_back(100.0);
945  }
946 
947  }
948 
949 
950  // Now test whether anything needs to be broadcast elsewhere
951  // (i.e. were there any failures in the locate method above?)
952  // If there are, then the zetas for these failures need to be
953  // broadcast...
954 
955  // How many zetas have we failed to find? [Note: Array is padded
956  // by Dim padded entries (DBL_MAX) for each mesh]
957  n_zeta_not_found=Flat_packed_zetas_not_found_locally.size()-
958  Dim*n_mesh;
959 
960  if (Doc_timings)
961  {
962  t_local = TimingHelpers::timer();
963  oomph_info
964  << "CPU for local location of zeta coordinate [spiral level "
965  << i_level << "]: "
966  << t_local - t_spiral_start << std::endl
967  << "Number of missing zetas: " << n_zeta_not_found
968  << std::endl;
969  }
970 
971 
972 #ifdef OOMPH_HAS_MPI
973  // Only perform the reduction operation if there's more than one process
974  if (problem_pt->communicator_pt()->nproc() > 1)
975  {
976  unsigned count_local_zetas=n_zeta_not_found;
977  MPI_Allreduce(&count_local_zetas,&n_zeta_not_found,1,
978  MPI_UNSIGNED,MPI_SUM,
979  problem_pt->communicator_pt()->mpi_comm());
980  }
981 
982  // If we have missing zetas on any process
983  // and the problem is distributed, we need to locate elsewhere
984  if ((n_zeta_not_found!=0) && (problem_pt->problem_has_been_distributed()))
985  {
986  // Timings
987  double t_sendrecv_min= DBL_MAX;
988  double t_sendrecv_max=-DBL_MAX;
989  double t_sendrecv_tot=0.0;
990 
991  double t_missing_min= DBL_MAX;
992  double t_missing_max=-DBL_MAX;
993  double t_missing_tot=0.0;
994 
995  double t_send_info_min= DBL_MAX;
996  double t_send_info_max=-DBL_MAX;
997  double t_send_info_tot=0.0;
998 
999  double t_create_halo_min= DBL_MAX;
1000  double t_create_halo_max=-DBL_MAX;
1001  double t_create_halo_tot=0.0;
1002 
1003  // Start ring communication: Loop (number of processes - 1)
1004  // starting from 1. The variable iproc represents the "distance" from
1005  // the current process to the process for which it is attempting
1006  // to locate an element for the current set of not-yet-located
1007  // zeta coordinates
1008  unsigned ring_count=0;
1009  for (int iproc=1;iproc<n_proc;iproc++)
1010  {
1011  // Record time at start of loop
1012  if (Doc_timings)
1013  {
1014  t_loop_start=TimingHelpers::timer();
1015  }
1016 
1017  // Send the zeta values you haven't found to the
1018  // next process, receive from the previous process:
1019  // (Padded) Flat_packed_zetas_not_found_locally are sent
1020  // to next processor where they are received as
1021  // (padded) Received_flat_packed_zetas_to_be_found.
1022  send_and_receive_missing_zetas(problem_pt);
1023 
1024  if (Doc_timings)
1025  {
1026  ring_count++;
1027  t_sendrecv=TimingHelpers::timer();
1028  t_sendrecv_max=std::max(t_sendrecv_max,t_sendrecv-t_loop_start);
1029  t_sendrecv_min=std::min(t_sendrecv_min,t_sendrecv-t_loop_start);
1030  t_sendrecv_tot+=(t_sendrecv-t_loop_start);
1031  }
1032 
1033  // Perform the locate_zeta for the new set of zetas on this process
1035  (iproc,external_mesh_pt,problem_pt,mesh_geom_obj_pt);
1036 
1037  if (Doc_timings)
1038  {
1039  t_missing=TimingHelpers::timer();
1040  t_missing_max=std::max(t_missing_max,t_missing-t_sendrecv);
1041  t_missing_min=std::min(t_missing_min,t_missing-t_sendrecv);
1042  t_missing_tot+=(t_missing-t_sendrecv);
1043  }
1044 
1045  // Send any located coordinates back to the correct process, and
1046  // prepare to send on to the next process if necessary
1047  send_and_receive_located_info(iproc,external_mesh_pt,problem_pt);
1048 
1049  if (Doc_timings)
1050  {
1051  t_send_info=TimingHelpers::timer();
1052  t_send_info_max=std::max(t_send_info_max,t_send_info-t_missing);
1053  t_send_info_min=std::min(t_send_info_min,t_send_info-t_missing);
1054  t_send_info_tot+=(t_send_info-t_missing);
1055  }
1056 
1057  // Create any located external halo elements on the current process
1058  create_external_halo_elements<EXT_ELEMENT>
1059  (iproc,mesh_pt,external_mesh_pt,problem_pt,interaction_index);
1060 
1061  if (Doc_timings)
1062  {
1063  t_create_halo=TimingHelpers::timer();
1064  t_create_halo_max=std::max(t_create_halo_max,
1065  t_create_halo-t_send_info);
1066  t_create_halo_min=std::min(t_create_halo_min,
1067  t_create_halo-t_send_info);
1068  t_create_halo_tot+=(t_create_halo-t_send_info);
1069  }
1070 
1071  // Do we have any further locating to do or have we found
1072  // everything at this level of the ring communication?
1073  // Only perform the reduction operation if there's more than
1074  // one process [Note: Array is padded
1075  // by DIM times DBL_MAX entries for each mesh]
1076  n_zeta_not_found=Flat_packed_zetas_not_found_locally.size()-
1077  Dim*n_mesh;
1078 
1079 
1080 #ifdef OOMPH_HAS_MPI
1081  if (problem_pt->communicator_pt()->nproc() > 1)
1082  {
1083  unsigned count_local_zetas=n_zeta_not_found;
1084  MPI_Allreduce(&count_local_zetas,&n_zeta_not_found,1,
1085  MPI_UNSIGNED,MPI_SUM,
1086  problem_pt->communicator_pt()->mpi_comm());
1087  }
1088 #endif
1089 
1090  // If its is now zero then break out of the ring comms loop
1091  if (n_zeta_not_found==0)
1092  {
1093  if (Doc_timings)
1094  {
1095  t_local=TimingHelpers::timer();
1096  oomph_info
1097  << "BREAK N-1: CPU for entrire spiral [spiral level "
1098  << i_level << "]: "
1099  << t_local-t_spiral_start << std::endl;
1100  }
1101  break;
1102  }
1103  }
1104 
1105 
1106  // Doc timings
1107  if (Doc_timings)
1108  {
1109  oomph_info
1110  << "Ring-based search continued until iteration "
1111  << ring_count << " out of a maximum of "
1112  << problem_pt->communicator_pt()->nproc()-1 << "\n";
1113  oomph_info
1114  << "Total, av, max, min CPU for send/recv of remaining zeta coordinates: "
1115  << t_sendrecv_tot << " "
1116  << t_sendrecv_tot/double(ring_count) << " "
1117  << t_sendrecv_max << " "
1118  << t_sendrecv_min << "\n";
1119  oomph_info
1120  << "Total, av, max, min CPU for location of missing zeta coordinates : "
1121  << t_missing_tot << " "
1122  << t_missing_tot/double(ring_count) << " "
1123  << t_missing_max << " "
1124  << t_missing_min << "\n";
1125  oomph_info
1126  << "Total, av, max, min CPU for send/recv of new element info : "
1127  << t_send_info_tot << " "
1128  << t_send_info_tot/double(ring_count) << " "
1129  << t_send_info_max << " "
1130  << t_send_info_min << "\n";
1131  oomph_info
1132  << "Total, av, max, min CPU for local creation of external halo objects: "
1133  << t_create_halo_tot << " "
1134  << t_create_halo_tot/double(ring_count) << " "
1135  << t_create_halo_max << " "
1136  << t_create_halo_min << "\n";
1137  }
1138 
1139  } // end if for missing zetas on any process
1140 #endif
1141 
1142 
1143  // Store information about location of elements for integration points
1144  if (Doc_stats)
1145  {
1146  unsigned count_locates=0;
1147  unsigned n_ext_loc=External_element_located.size();
1148  for (unsigned e=0;e<n_ext_loc;e++)
1149  {
1150  unsigned n_intpt=External_element_located[e].size();
1151  for (unsigned ipt=0;ipt<n_intpt;ipt++)
1152  {
1153  count_locates+=External_element_located[e][ipt];
1154  }
1155  }
1156 
1157 
1158  // Store total percentage of locates so far.
1159  // Only assign if we had anything to allocte, otherwise 100%
1160  // (default assignment) is correct
1161  if (tot_int!=0)
1162  {
1163  percentage_coords_located_elsewhere.push_back(
1164  100.0*double(count_locates)/double(tot_int));
1165  }
1166  else
1167  {
1168  // Had none to find so we found them all!
1169  percentage_coords_located_locally.push_back(100.0);
1170  }
1171 
1172 
1173  }
1174 
1175  // Do we have any further locating to do? If so, the remaining
1176  // zetas will (hopefully) be found at the next spiral level.
1177  // Only perform the reduction operation if there's more than one process
1178  // [Note: Array is padded
1179  // by DIM times DBL_MAX entries for each mesh]
1180  n_zeta_not_found=Flat_packed_zetas_not_found_locally.size()-
1181  Dim*n_mesh;
1182 
1183 
1184 #ifdef OOMPH_HAS_MPI
1185  if (problem_pt->communicator_pt()->nproc() > 1)
1186  {
1187  unsigned count_local_zetas=n_zeta_not_found;
1188  MPI_Allreduce(&count_local_zetas,&n_zeta_not_found,1,
1189  MPI_UNSIGNED,MPI_SUM,
1190  problem_pt->communicator_pt()->mpi_comm());
1191  }
1192 
1193  // Specify max level reached for later loop
1194  max_level_reached=i_level+1;
1195 #endif
1196 
1197  /// If it's is now zero then break out of the spirals loop
1198  if (n_zeta_not_found==0)
1199  {
1200  if (Doc_timings)
1201  {
1202  t_local=TimingHelpers::timer();
1203  oomph_info
1204  << "BREAK N: CPU for entrire spiral [spiral level "
1205  << i_level << "]: "
1206  << t_local-t_spiral_start << std::endl;
1207  }
1208  break;
1209  }
1210 
1211  if (Doc_timings)
1212  {
1213  t_local=TimingHelpers::timer();
1214  oomph_info
1215  << "CPU for entrire spiral [spiral level "
1216  << i_level << "]: "
1217  << t_local-t_spiral_start << std::endl;
1218  }
1219 
1220  // Bump up spiral levels for all meshes
1221  i_level++;
1222  for (unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
1223  {
1224  if (mesh_geom_obj_pt[i_mesh]->sample_point_container_version()==
1226  {
1227 
1228  RefineableBinArray* bin_array_pt=
1229  dynamic_cast<RefineableBinArray*>(mesh_geom_obj_pt[i_mesh]->
1230  sample_point_container_pt());
1231  bin_array_pt->
1232  first_sample_point_to_actually_lookup_during_locate_zeta() =
1233  bin_array_pt->
1234  last_sample_point_to_actually_lookup_during_locate_zeta();
1235  bin_array_pt->
1236  last_sample_point_to_actually_lookup_during_locate_zeta() *=
1237  bin_array_pt->
1238  multiplier_for_max_sample_point_to_actually_lookup_during_locate_zeta();
1239  }
1240  else if (mesh_geom_obj_pt[i_mesh]->sample_point_container_version()==
1242  {
1243  NonRefineableBinArray* bin_array_pt=
1244  dynamic_cast<NonRefineableBinArray*>(mesh_geom_obj_pt[i_mesh]->
1245  sample_point_container_pt());
1246 
1247  bin_array_pt->current_min_spiral_level()+=bin_array_pt->n_spiral_chunk();
1248  bin_array_pt->current_max_spiral_level()+=bin_array_pt->n_spiral_chunk();
1249  }
1250 #ifdef OOMPH_HAS_CGAL
1251  else if (mesh_geom_obj_pt[i_mesh]->sample_point_container_version()==
1253  {
1254  CGALSamplePointContainer* bin_array_pt=
1255  dynamic_cast<CGALSamplePointContainer*>(mesh_geom_obj_pt[i_mesh]->
1256  sample_point_container_pt());
1257  bin_array_pt->
1258  first_sample_point_to_actually_lookup_during_locate_zeta() =
1259  bin_array_pt->
1260  last_sample_point_to_actually_lookup_during_locate_zeta();
1261  bin_array_pt->
1262  last_sample_point_to_actually_lookup_during_locate_zeta() *=
1263  bin_array_pt->
1264  multiplier_for_max_sample_point_to_actually_lookup_during_locate_zeta();
1265  }
1266 #endif // cgal
1267  }
1268 
1269  // Check termination criterion for while loop
1270  if (mesh_geom_obj_pt[0]->sample_point_container_version()==
1272  {
1273  RefineableBinArray* bin_array_pt=
1274  dynamic_cast<RefineableBinArray*>(mesh_geom_obj_pt[0]->
1275  sample_point_container_pt());
1276 
1277  if (bin_array_pt->
1278  first_sample_point_to_actually_lookup_during_locate_zeta()
1279  <= max_n_sample_points_of_sample_point_containers)
1280  {
1281  has_not_reached_max_level_of_search=true;
1282  }
1283  else
1284  {
1285  has_not_reached_max_level_of_search=false;
1286  }
1287  }
1288  else if (mesh_geom_obj_pt[0]->sample_point_container_version()==
1290  {
1291  NonRefineableBinArray* bin_array_pt=
1292  dynamic_cast<NonRefineableBinArray*>(mesh_geom_obj_pt[0]->
1293  sample_point_container_pt());
1294 
1295  if (bin_array_pt->current_max_spiral_level() < n_max_level)
1296  {
1297  has_not_reached_max_level_of_search=true;
1298  }
1299  else
1300  {
1301  has_not_reached_max_level_of_search=false;
1302  }
1303  }
1304 #ifdef OOMPH_HAS_CGAL
1305  else if (mesh_geom_obj_pt[0]->sample_point_container_version()==
1307  {
1308  CGALSamplePointContainer* bin_array_pt=
1309  dynamic_cast<CGALSamplePointContainer*>(mesh_geom_obj_pt[0]->
1310  sample_point_container_pt());
1311 
1312  if (bin_array_pt->
1313  first_sample_point_to_actually_lookup_during_locate_zeta()
1314  <= max_n_sample_points_of_sample_point_containers)
1315  {
1316  has_not_reached_max_level_of_search=true;
1317  }
1318  else
1319  {
1320  has_not_reached_max_level_of_search=false;
1321  }
1322  }
1323 #endif // cgal
1324  } // end of "spirals" loop
1325 
1326 
1327  // If we haven't found all zetas we're dead now...
1328  //-------------------------------------------------
1329  if (n_zeta_not_found!=0)
1330  {
1331  // Shout?
1333  {
1334 
1335  std::ostringstream error_stream;
1336  error_stream
1337  << "Multi_domain_functions::locate_zeta_for_local_coordinates()"
1338  << "\nhas failed ";
1339 
1340 #ifdef OOMPH_HAS_MPI
1341  if (problem_pt->communicator_pt()->nproc() > 1)
1342  {
1343  error_stream << " on proc: "
1344  << problem_pt->communicator_pt()->my_rank()
1345  << std::endl;
1346  }
1347 #endif
1348  error_stream
1349  << "\n\n\nThis is most likely to arise because the two meshes\n"
1350  << "that are to be matched don't overlap perfectly or\n"
1351  << "because the elements are distorted and too small a \n"
1352  << "number of sampling points has been used when setting\n"
1353  << "up the bin structure.\n\n"
1354  << "You should try to increase the value of \n"
1355  << "the number of sample points defined in \n\n"
1356  << " SamplePointContainerParameters::Default_nsample_points_generated_per_element"
1357  << "\n\n from its current value of "
1359  << "\n\n"
1360  << "NOTE: You can suppress this error and \"accept failure\""
1361  << " by setting the public boolean \n\n"
1362  << " Multi_domain_functions::Accept_failed_locate_zeta_in_setup_multi_domain_interaction\n\n"
1363  << " to true. In this case, the pointers to external elements\n"
1364  << " that couldn't be located will remain null\n";
1365 
1366  std::ostringstream modifier;
1367 #ifdef OOMPH_HAS_MPI
1368  if (problem_pt->communicator_pt()->nproc() > 1)
1369  {
1370  modifier << "_proc" << problem_pt->communicator_pt()->my_rank();
1371  }
1372 #endif
1373 
1374  // Loop over all meshes
1375  for (unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
1376  {
1377 
1378  // Add yet another modifier to distinguish meshes if reqd
1379  if (n_mesh>1)
1380  {
1381  modifier << "_mesh" << i_mesh;
1382  }
1383 
1384  std::ofstream outfile;
1385  char filename[100];
1386  sprintf(filename,"missing_coords_mesh%s.dat",modifier.str().c_str());
1387  outfile.open(filename);
1388  unsigned nel=mesh_pt[i_mesh]->nelement();
1389  for (unsigned e=0;e<nel;e++)
1390  {
1391  mesh_pt[i_mesh]->finite_element_pt(e)->
1392  FiniteElement::output(outfile);
1393  }
1394  outfile.close();
1395 
1396  sprintf(filename,"missing_coords_ext_mesh%s.dat",
1397  modifier.str().c_str());
1398  outfile.open(filename);
1399  nel=external_mesh_pt->nelement();
1400  for (unsigned e=0;e<nel;e++)
1401  {
1402  external_mesh_pt->finite_element_pt(e)->
1403  FiniteElement::output(outfile);
1404  }
1405  outfile.close();
1406 
1407  BinArray* bin_array_pt=dynamic_cast<BinArray*>(
1408  mesh_geom_obj_pt[i_mesh]->sample_point_container_pt());
1409  if (bin_array_pt!=0)
1410  {
1411  sprintf(filename,"missing_coords_bin%s.dat",modifier.str().c_str());
1412  outfile.open(filename);
1413  bin_array_pt->output_bins(outfile);
1414  outfile.close();
1415  }
1416 
1417  sprintf(filename,"missing_coords%s.dat",modifier.str().c_str());
1418  outfile.open(filename);
1419  unsigned n=External_element_located.size();
1420  error_stream << "Number of unlocated elements " << n << std::endl;
1421  for (unsigned e=0;e<n;e++)
1422  {
1423  unsigned n_intpt=External_element_located[e].size();
1424  if (n_intpt==0)
1425  {
1426  error_stream
1427  << "Failure to locate in halo element! "
1428  << "Why are we searching there?"
1429  << std::endl;
1430  }
1431  for (unsigned ipt=0;ipt<n_intpt;ipt++)
1432  {
1433  if (External_element_located[e][ipt]==0)
1434  {
1435  error_stream << "Failure at element/intpt: "
1436  << e << " " << ipt << std::endl;
1437 
1438  // Cast
1440  dynamic_cast<ElementWithExternalElement*>(
1441  mesh_pt[i_mesh]->element_pt(e));
1442 
1443  unsigned n_dim_el=el_pt->dim();
1444  Vector<double> s(n_dim_el);
1445  for (unsigned i=0;i<n_dim_el;i++)
1446  {
1447  s[i]=el_pt->integral_pt()->knot(ipt,i);
1448  }
1449  unsigned n_dim=el_pt->node_pt(0)->ndim();
1450  Vector<double> x(n_dim);
1451  el_pt->interpolated_x(s,x);
1452  for (unsigned i=0;i<n_dim;i++)
1453  {
1454  error_stream << x[i] << " ";
1455  outfile<< x[i] << " ";
1456  }
1457  error_stream << std::endl;
1458  outfile << std::endl;
1459  }
1460  }
1461  }
1462  outfile.close();
1463  }
1464 
1465  error_stream
1466  << "Mesh and external mesh documented in missing_coords_mesh*.dat\n"
1467  << "and missing_coords_ext_mesh*.dat, respectively. Missing \n"
1468  << "coordinates in missing_coords*.dat\n";
1469  throw OomphLibError
1470  (error_stream.str(),
1471  OOMPH_CURRENT_FUNCTION,
1472  OOMPH_EXCEPTION_LOCATION);
1473  }
1474  // Failure is deeemed to be acceptable
1475  else
1476  {
1477  oomph_info
1478  << "NOTE: Haven't found " << n_zeta_not_found
1479  << " external elements in \n"
1480  << "Multi_domain_functions::aux_setup_multi_domain_interaction(...)\n"
1481  << "but this deemed to be acceptable because \n"
1482  << "Multi_domain_functions::Accept_failed_locate_zeta_in_setup_multi_domain_interaction\n"
1483  << "is true.\n";
1484  }
1485  }
1486 
1487 
1488  // Doc timings if required
1489  if (Doc_timings)
1490  {
1491  t_locate=TimingHelpers::timer();
1492  oomph_info
1493  << "Total CPU for location and creation of all external elements: "
1494  << t_locate-t_start << std::endl;
1495  }
1496 
1497  // Delete the geometric object representing the mesh
1498  for (unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
1499  {
1500  delete mesh_geom_obj_pt[i_mesh];
1501  }
1502 
1503  // Clean up all the (extern) Vectors associated with creating the
1504  // external storage information
1505  clean_up();
1506 
1507 #ifdef OOMPH_HAS_MPI
1508 
1509  // Output information about external storage if required
1510  if (Doc_stats)
1511  {
1512  // Report stats regarding location method
1513  bool comm_was_required=false;
1514  oomph_info << "-------------------------------------------" << std::endl;
1515  oomph_info << "- Cumulative percentage of locate success -" << std::endl;
1516  oomph_info << "--- Spiral -- Found local -- Found else ---" << std::endl;
1517  for (unsigned level=0; level<max_level_reached; level++)
1518  {
1519  oomph_info << "--- " << level << " -- "
1520  << percentage_coords_located_locally[level] << " -- "
1521  << percentage_coords_located_elsewhere[level] << " ---"
1522  << std::endl;
1523  // Has communication with other processors at this level actually
1524  // produced any results?
1525  if (percentage_coords_located_elsewhere[level]>
1526  percentage_coords_located_locally[level])
1527  {
1528  comm_was_required=true;
1529  }
1530  }
1531  oomph_info << "-------------------------------------------" << std::endl;
1532 
1533 
1534  // No need for any of this malaki if we're not running in parallel
1535  if (problem_pt->communicator_pt()->nproc() > 1)
1536  {
1537 
1538  // Initialise to indicate that none of the zetas required
1539  // on this processor were located through parallel ring search,
1540  // i.e. comm was not required and we could have done some
1541  // more local searching first
1542  oomph_info << std::endl;
1543  oomph_info <<"ASSESSMENT OF NEED FOR PARALLEL SEARCH: \n";
1544  oomph_info <<"=======================================\n";
1545  unsigned status=0;
1546  if (comm_was_required)
1547  {
1548  oomph_info
1549  <<"- Ring-based parallel search did successfully locate zetas on proc "
1550  << my_rank << std::endl;
1551  status=1;
1552  }
1553  else
1554  {
1555  if (max_level_reached>1)
1556  {
1557  oomph_info
1558  << "- Ring-based parallel search did NOT locate zetas on proc"
1559  << my_rank << std::endl;
1560  }
1561  else
1562  {
1563  oomph_info
1564  << "- No ring-based parallel search was performed on proc"
1565  << my_rank << std::endl;
1566  }
1567  }
1568 
1569  // Allreduce to check if anyone has benefitted from parallel ring
1570  // search
1571  unsigned overall_status=0;
1572  MPI_Allreduce(&status,&overall_status,1,
1573  MPI_UNSIGNED,MPI_MAX,
1574  problem_pt->communicator_pt()->mpi_comm());
1575 
1576  // Report of mpi was useful to anyone
1577  if (overall_status==1)
1578  {
1579  oomph_info << "- Ring-based, parallel search did succesfully\n";
1580  oomph_info << " locate zetas on at least one other proc, so it\n";
1581  oomph_info << " was worthwhile.\n";
1582  oomph_info << std::endl;
1583  }
1584  else
1585  {
1586  if (max_level_reached>1)
1587  {
1588  oomph_info << "- Ring-based, parallel search did NOT locate zetas\n";
1589  oomph_info << " on ANY other procs, i.e it was useless.\n";
1590  oomph_info << " --> We should really have done more local search\n";
1591  oomph_info << " by reducing number of bins, or doing more spirals\n";
1592  oomph_info << " in one go before initiating parallel search.\n";
1593  oomph_info << std::endl;
1594  }
1595  else
1596  {
1597  oomph_info << "- No ring-based, parallel search was performed\n";
1598  oomph_info << " or necessary. Perfect!\n";
1599  oomph_info << std::endl;
1600  }
1601  }
1602 
1603  }
1604 
1605  // How many external elements does the external mesh have now?
1606  oomph_info << "------------------------------------------" << std::endl;
1607  oomph_info << "External mesh: I have " << external_mesh_pt->nelement()
1608  << " elements, and " << std::endl
1609  << external_mesh_pt->nexternal_halo_element()
1610  << " external halo elements, "
1611  << external_mesh_pt->nexternal_haloed_element()
1612  << " external haloed elements"
1613  << std::endl;
1614 
1615  // How many external nodes does each submesh have now?
1616  oomph_info << "------------------------------------------" << std::endl;
1617  oomph_info << "External mesh: I have " << external_mesh_pt->nnode()
1618  << " nodes, and " << std::endl
1619  << external_mesh_pt->nexternal_halo_node()
1620  << " external halo nodes, "
1621  << external_mesh_pt->nexternal_haloed_node()
1622  << " external haloed nodes"
1623  << std::endl;
1624  oomph_info << "------------------------------------------" << std::endl;
1625  }
1626 
1627  // Output further information about (external) halo(ed)
1628  // elements and nodes if required
1629  if (Doc_full_stats)
1630  {
1631  // How many elements does this submesh have for each of the processors?
1632  for (int iproc=0;iproc<n_proc;iproc++)
1633  {
1634  oomph_info << "----------------------------------------" << std::endl;
1635  oomph_info << "With process " << iproc << " there are "
1636  << external_mesh_pt->nroot_halo_element(iproc)
1637  << " root halo elements, and "
1638  << external_mesh_pt->nroot_haloed_element(iproc)
1639  << " root haloed elements" << std::endl
1640  << "and there are "
1641  << external_mesh_pt->nexternal_halo_element(iproc)
1642  << " external halo elements, and "
1643  << external_mesh_pt->nexternal_haloed_element(iproc)
1644  << " external haloed elements." << std::endl;
1645 
1646  oomph_info << "----------------------------------------" << std::endl;
1647  oomph_info << "With process " << iproc << " there are "
1648  << external_mesh_pt->nhalo_node(iproc)
1649  << " halo nodes, and "
1650  << external_mesh_pt->nhaloed_node(iproc)
1651  << " haloed nodes" << std::endl
1652  << "and there are "
1653  << external_mesh_pt->nexternal_halo_node(iproc)
1654  << " external halo nodes, and "
1655  << external_mesh_pt->nexternal_haloed_node(iproc)
1656  << " external haloed nodes." << std::endl;
1657  }
1658  oomph_info << "-----------------------------------------" << std::endl
1659  << std::endl;
1660  }
1661 
1662  #endif
1663 
1664  // Doc timings if required
1665  if (Doc_timings)
1666  {
1667  t_end=TimingHelpers::timer();
1668  oomph_info << "CPU for (one way) aux_setup_multi_domain_interaction: "
1669  << t_end-t_start << std::endl;
1670  }
1671 
1672  } // end of aux_setup_multi_domain_interaction
1673 
1674 #ifdef OOMPH_HAS_MPI
1675 
1676 //=====================================================================
1677 /// Creates external (halo) elements on the loop process based on the
1678 /// information received from each locate_zeta call on other processes.
1679 /// vector based version
1680 //=====================================================================
1681  template<class EXT_ELEMENT>
1683  (int& iproc, const Vector<Mesh*>& mesh_pt, Mesh* const &external_mesh_pt,
1684  Problem* problem_pt, const unsigned& interaction_index)
1685  {
1686  OomphCommunicator* comm_pt=problem_pt->communicator_pt();
1687  int my_rank=comm_pt->my_rank();
1688 
1689  // Reset counters for flat packed unsigneds (namespace data because
1690  // it's also accessed by helper functions)
1693 
1694  // Initialise counter for stepping through zetas
1695  unsigned zeta_counter=0;
1696 
1697  // Initialise counter for stepping through flat-packed located
1698  // coordinates
1699  unsigned counter_for_located_coord=0;
1700 
1701  // Counter for elements in flag packed storage
1702  unsigned e_count=0;
1703 
1704  // Loop over all meshes
1705  unsigned n_mesh=mesh_pt.size();
1706  for (unsigned i_mesh=0;i_mesh<n_mesh;i_mesh++)
1707  {
1708 
1709  // The creation all happens on the current processor
1710  // Loop over this processors elements
1711  unsigned n_element=mesh_pt[i_mesh]->nelement();
1712  for (unsigned e=0;e<n_element;e++)
1713  {
1714  // Cast to ElementWithExternalElement to set external element
1715  // (if located)
1717  dynamic_cast<ElementWithExternalElement*>(mesh_pt[i_mesh]
1718  ->element_pt(e));
1719 
1720  // We're not setting up external elements for halo elements
1721  // (Note: this is consistent with padding introduced when
1722  // External_element_located was first assigned)
1723  if (!el_pt->is_halo())
1724  {
1725  // Loop over integration points
1726  unsigned n_intpt=el_pt->integral_pt()->nweight();
1727  for (unsigned ipt=0;ipt<n_intpt;ipt++)
1728  {
1729  // Has an external element been assigned to this integration point?
1730  if (External_element_located[e_count][ipt]==0)
1731  {
1732  // Was a (non-halo) element located for this integration point
1733  if (((Proc_id_plus_one_of_external_element[zeta_counter]-1)==
1734  my_rank) ||
1735  (Proc_id_plus_one_of_external_element[zeta_counter]==0))
1736  {
1737  // Either it was already found, or not found on the current proc.
1738  // In either case, we don't need to do anything for this
1739  // integration point
1740  }
1741  else
1742  {
1743  // Get the process number on which the element was located
1744  unsigned loc_p=
1745  Proc_id_plus_one_of_external_element[zeta_counter]-1;
1746 
1747  // Is it a new external halo element or not?
1748  // If so, then create it, populate it, and add it as a
1749  // source; if not, then find the right one which
1750  // has already been created and use it as the source
1751  // element.
1752 
1753  // FiniteElement stored at this integration point
1754  FiniteElement* f_el_pt=0;
1755 
1756  // Is it a new element?
1757  if (Located_element_status[zeta_counter]==New)
1758  {
1759  // Create a new element from the communicated values
1760  // and coords from the process that located zeta
1761  GeneralisedElement *new_el_pt= new EXT_ELEMENT;
1762 
1763  // Add external halo element to this mesh
1764  external_mesh_pt->
1765  add_external_halo_element_pt(loc_p, new_el_pt);
1766 
1767  // Cast to the FE pointer
1768  f_el_pt=dynamic_cast<FiniteElement*>(new_el_pt);
1769 
1770  // We need the number of interpolated values if Refineable
1771  int n_cont_inter_values=-1;
1772  if (dynamic_cast<RefineableElement*>(new_el_pt)!=0)
1773  {
1774  n_cont_inter_values=dynamic_cast<RefineableElement*>
1775  (new_el_pt)->ncont_interpolated_values();
1776  }
1777 
1778  // If we're using macro elements to update
1779 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1780  oomph_info
1781  << "Rec:" << Counter_for_flat_packed_unsigneds
1782  << " Using macro element node update "
1784  << std::endl;
1785 #endif
1787  ==1)
1788  {
1789  // Set the macro element
1790  MacroElementNodeUpdateMesh* macro_mesh_pt=
1791  dynamic_cast<MacroElementNodeUpdateMesh*>
1792  (external_mesh_pt);
1793 
1794 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1795  oomph_info
1796  << "Rec:" << Counter_for_flat_packed_unsigneds
1797  << " Number of macro element "
1799  << std::endl;
1800 #endif
1801  unsigned macro_el_num=
1803  f_el_pt->set_macro_elem_pt
1804  (macro_mesh_pt->macro_domain_pt()->
1805  macro_element_pt(macro_el_num));
1806 
1807 
1808  // We need to receive the lower left
1809  // and upper right coordinates of the macro element
1810  QElementBase* q_el_pt=
1811  dynamic_cast<QElementBase*>(new_el_pt);
1812  if (q_el_pt!=0)
1813  {
1814  unsigned el_dim=q_el_pt->dim();
1815  for (unsigned i_dim=0;i_dim<el_dim;i_dim++)
1816  {
1817  q_el_pt->s_macro_ll(i_dim)=
1819  q_el_pt->s_macro_ur(i_dim)=
1821  }
1822  }
1823  else // Throw an error, since this is only implemented for Q
1824  {
1825  std::ostringstream error_stream;
1826  error_stream << "Using MacroElement node update\n"
1827  << "in a case with non-QElements\n"
1828  << "has not yet been implemented.\n";
1829  throw OomphLibError
1830  (error_stream.str(),
1831  OOMPH_CURRENT_FUNCTION,
1832  OOMPH_EXCEPTION_LOCATION);
1833 
1834  }
1835  }
1836 
1837  // Now we add nodes to the new element
1838  unsigned n_node=f_el_pt->nnode();
1839  for (unsigned j=0;j<n_node;j++)
1840  {
1841  Node* new_nod_pt=0;
1842 
1843  // Call the add external halo node helper function
1844  add_external_halo_node_to_storage<EXT_ELEMENT>
1845  (new_nod_pt,external_mesh_pt,loc_p,j,f_el_pt,
1846  n_cont_inter_values,problem_pt);
1847  }
1848  }
1849  else // the element already exists as an external_halo
1850  {
1851 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1852  oomph_info
1853  << "Rec:" << Counter_for_flat_packed_unsigneds
1854  << " Index of existing external halo element "
1856  << std::endl;
1857 #endif
1858  // The index itself is in Flat_packed_unsigneds[...]
1859  unsigned external_halo_el_index=
1861 
1862  // Use this index to get the element
1863  f_el_pt=dynamic_cast<FiniteElement*>(external_mesh_pt->
1864  external_halo_element_pt
1865  (loc_p,
1866  external_halo_el_index));
1867 
1868  //If it's not a finite element die
1869  if(f_el_pt==0)
1870  {
1871  throw OomphLibError(
1872  "External halo element is not a FiniteElement\n",
1873  OOMPH_CURRENT_FUNCTION,
1874  OOMPH_EXCEPTION_LOCATION);
1875  }
1876  }
1877 
1878  // The source element storage was initialised but
1879  // not filled earlier, so do it now
1880  // The located coordinates are required
1881  // (which could be a different dimension to zeta, e.g. in FSI)
1882  unsigned el_dim=f_el_pt->dim();
1883  Vector<double> s_located(el_dim);
1884  for (unsigned i=0;i<el_dim;i++)
1885  {
1886  s_located[i]=
1887  Flat_packed_located_coordinates[counter_for_located_coord];
1888  counter_for_located_coord++;
1889  }
1890 
1891  // Set the element for this integration point
1892  el_pt->external_element_pt(interaction_index,ipt)=f_el_pt;
1893  el_pt->
1894  external_element_local_coord(interaction_index,ipt)=s_located;
1895 
1896  // Set the lookup array to true
1897  External_element_located[e_count][ipt]=1;
1898  }
1899 
1900  // Increment the integration point counter
1901  zeta_counter++;
1902  }
1903  } // end loop over integration points
1904  } // end of is halo
1905 
1906  // Bump flat-packed element counter
1907  e_count++;
1908 
1909  } // end of loop over elements
1910 
1911  // Bump up zeta counter to skip over padding entry at end of
1912  // mesh
1913  zeta_counter++;
1914 
1915  } // end loop over meshes
1916  }
1917 
1918 
1919 //============start of add_external_halo_node_to_storage===============
1920 /// Helper function to add external halo nodes, including any masters,
1921 /// based on information received from the haloed process
1922 //=========================================================================
1923  template<class EXT_ELEMENT>
1925  (Node* &new_nod_pt, Mesh* const &external_mesh_pt, unsigned& loc_p,
1926  unsigned& node_index, FiniteElement* const &new_el_pt,
1927  int& n_cont_inter_values,
1928  Problem* problem_pt)
1929  {
1930  // Add the external halo node if required
1931  add_external_halo_node_helper(new_nod_pt,external_mesh_pt,loc_p,
1932  node_index,new_el_pt,
1933  n_cont_inter_values,problem_pt);
1934 
1935  // Recursively add masters
1936  recursively_add_masters_of_external_halo_node_to_storage<EXT_ELEMENT>
1937  (new_nod_pt, external_mesh_pt, loc_p,
1938  node_index, new_el_pt,
1939  n_cont_inter_values,
1940  problem_pt);
1941  }
1942 
1943 
1944 //========================================================================
1945 /// Recursively add masters of external halo nodes (and their masters, etc)
1946 /// based on information received from the haloed process
1947 //=========================================================================
1948  template<class EXT_ELEMENT>
1951  (Node* &new_nod_pt, Mesh* const &external_mesh_pt, unsigned& loc_p,
1952  unsigned& node_index, FiniteElement* const &new_el_pt,
1953  int& n_cont_inter_values,
1954  Problem* problem_pt)
1955  {
1956  for (int i_cont=-1;i_cont<n_cont_inter_values;i_cont++)
1957  {
1958 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1959  oomph_info
1960  << "Rec:" << Counter_for_flat_packed_unsigneds
1961  << " Boolean to indicate that continuously interpolated variable i_cont "
1962  << i_cont << " is hanging "
1964  << std::endl;
1965 #endif
1967  {
1968 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
1969  oomph_info
1970  << "Rec:" << Counter_for_flat_packed_unsigneds
1971  << " Number of master nodes "
1973  << std::endl;
1974 #endif
1975  unsigned n_master=Flat_packed_unsigneds
1977 
1978  // Setup new HangInfo
1979  HangInfo* hang_pt=new HangInfo(n_master);
1980  for (unsigned m=0;m<n_master;m++)
1981  {
1982  Node* master_nod_pt=0;
1983  // Get the master node (creating and adding it if required)
1984  add_external_halo_master_node_helper<EXT_ELEMENT>
1985  (master_nod_pt,new_nod_pt,external_mesh_pt,loc_p,
1986  n_cont_inter_values,problem_pt);
1987 
1988  // Get the weight and set the HangInfo
1989  double master_weight=Flat_packed_doubles
1991  hang_pt->set_master_node_pt(m,master_nod_pt,master_weight);
1992 
1993  // Recursively add masters of master
1994  recursively_add_masters_of_external_halo_node_to_storage<EXT_ELEMENT>
1995  (master_nod_pt, external_mesh_pt, loc_p,
1996  node_index, new_el_pt,
1997  n_cont_inter_values,
1998  problem_pt);
1999  }
2000  new_nod_pt->set_hanging_pt(hang_pt,i_cont);
2001  }
2002  } // end loop over continous interpolated values
2003 
2004  }
2005 
2006 //========================================================================
2007 /// Helper function to add external halo node that is a master
2008 //========================================================================
2009 template<class EXT_ELEMENT>
2011  (Node* &new_master_nod_pt, Node* &new_nod_pt, Mesh* const &external_mesh_pt,
2012  unsigned& loc_p, int& ncont_inter_values,Problem* problem_pt)
2013  {
2014  // Given the node and the external mesh, and received information
2015  // about them from process loc_p, construct them on the current process
2016 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2017  oomph_info
2018  << "Rec:" << Counter_for_flat_packed_unsigneds
2019  << " Boolean to trigger construction of new external halo master node "
2021  << std::endl;
2022 #endif
2024  {
2025  // Construct a new node based upon sent information
2026  construct_new_external_halo_master_node_helper<EXT_ELEMENT>
2027  (new_master_nod_pt,new_nod_pt,loc_p,external_mesh_pt,problem_pt);
2028  }
2029  else
2030  {
2031 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2032  oomph_info
2033  << "Rec:" << Counter_for_flat_packed_unsigneds
2034  << " index of existing external halo master node "
2036  << std::endl;
2037 #endif
2038  // Copy node from received location
2039  new_master_nod_pt=external_mesh_pt->external_halo_node_pt
2041  }
2042  }
2043 
2044 //======start of construct_new_external_halo_master_node_helper===========
2045 /// Helper function which constructs a new external halo master node
2046 /// with the required information sent from the haloed process
2047 //========================================================================
2048 template<class EXT_ELEMENT>
2050  (Node* &new_master_nod_pt, Node* &nod_pt, unsigned& loc_p,
2051  Mesh* const &external_mesh_pt, Problem* problem_pt)
2052  {
2053  // First three sent numbers are dimension, position type and nvalue
2054  // (to be used in Node constructors)
2055 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2056  oomph_info
2057  << "Rec:" << Counter_for_flat_packed_unsigneds
2058  << " ndim for external halo master node "
2060  << std::endl;
2061 #endif
2063 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2064  oomph_info
2065  << "Rec:" << Counter_for_flat_packed_unsigneds
2066  << " nposition type for external halo master node "
2068  << std::endl;
2069 #endif
2070  unsigned n_position_type=Flat_packed_unsigneds
2072 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2073  oomph_info
2074  << "Rec:" << Counter_for_flat_packed_unsigneds
2075  << " nvalue for external halo master node "
2077  << std::endl;
2078 #endif
2079  unsigned n_value=Flat_packed_unsigneds
2081 
2082  // If it's a solid node also receive the lagrangian dimension and pos type
2083  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(nod_pt);
2084  unsigned n_lag_dim;
2085  unsigned n_lag_type;
2086  if (solid_nod_pt!=0)
2087  {
2088 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2089  oomph_info
2090  << "Rec:" << Counter_for_flat_packed_unsigneds
2091  << " nlagrdim for external halo master solid node "
2093  << std::endl;
2094 #endif
2096 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2097  oomph_info
2098  << "Rec:" << Counter_for_flat_packed_unsigneds
2099  << " nlagrtype for external halo master solid node "
2101  << std::endl;
2102 #endif
2104  }
2105 
2106  // Null TimeStepper for now
2107  TimeStepper* time_stepper_pt=0;
2108  // Default number of previous values to 1
2109  unsigned n_prev=1;
2110 
2111  // The first entry in nodal_info indicates
2112  // the timestepper required for this halo node
2113 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2114  oomph_info
2115  << "Rec:" << Counter_for_flat_packed_unsigneds
2116  << " Boolean: need timestepper "
2118  << std::endl;
2119 #endif
2121  {
2122 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2123  oomph_info
2124  << "Rec:" << Counter_for_flat_packed_unsigneds
2125  << " Index minus one of timestepper "
2127  << std::endl;
2128 #endif
2129  // Index minus one!
2130  time_stepper_pt=problem_pt->time_stepper_pt
2132 
2133  // Check whether number of prev values is "sent" across
2134  n_prev=time_stepper_pt->ntstorage();
2135  }
2136 
2137  // Is the node for which the master is required Algebraic, Macro or Solid?
2138  AlgebraicNode* alg_nod_pt=dynamic_cast<AlgebraicNode*>(nod_pt);
2139  MacroElementNodeUpdateNode* macro_nod_pt=
2140  dynamic_cast<MacroElementNodeUpdateNode*>(nod_pt);
2141 
2142  // What type of node was the node for which we are constructing a master?
2143  if (alg_nod_pt!=0)
2144  {
2145  // The master node should also be algebraic
2146 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2147  oomph_info
2148  << "Rec:" << Counter_for_flat_packed_unsigneds
2149  << " Boolean for algebraic boundary node "
2151  << std::endl;
2152 #endif
2153  // If this master node's haloed copy is on a boundary then
2154  // it needs to be on the same boundary here
2156  {
2157  // Create a new BoundaryNode (not attached to an element)
2158  if (time_stepper_pt!=0)
2159  {
2160  new_master_nod_pt = new BoundaryNode<AlgebraicNode>
2161  (time_stepper_pt,n_dim,n_position_type,n_value);
2162  }
2163  else
2164  {
2165  new_master_nod_pt = new BoundaryNode<AlgebraicNode>
2166  (n_dim,n_position_type,n_value);
2167  }
2168 
2169  // How many boundaries does the algebraic master node live on?
2170 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2172  << " Number of boundaries the algebraic master node is on: "
2174  << std::endl;
2175 #endif
2177  for (unsigned i=0;i<nb;i++)
2178  {
2179  // Boundary number
2180 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2182  << " Algebraic master node is on boundary "
2184  << std::endl;
2185 #endif
2186  unsigned i_bnd=
2188  external_mesh_pt->add_boundary_node(i_bnd,new_master_nod_pt);
2189  }
2190 
2191 
2192  // Do we have additional values created by face elements?
2193 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2194  oomph_info
2195  << "Rec:" << Counter_for_flat_packed_unsigneds << " "
2196  << "Number of additional values created by face element "
2197  << "for master node "
2199  << std::endl;
2200 #endif
2201  unsigned n_entry=Flat_packed_unsigneds[
2203  if (n_entry>0)
2204  {
2205  // Create storage, if it doesn't already exist, for the map
2206  // that will contain the position of the first entry of
2207  // this face element's additional values,
2208  BoundaryNodeBase* bnew_master_nod_pt=
2209  dynamic_cast<BoundaryNodeBase*>(new_master_nod_pt);
2210 #ifdef PARANOID
2211  if (bnew_master_nod_pt==0)
2212  {
2213  throw OomphLibError(
2214  "Failed to cast new node to boundary node\n",
2215  OOMPH_CURRENT_FUNCTION,
2216  OOMPH_EXCEPTION_LOCATION);
2217  }
2218 #endif
2219  if(bnew_master_nod_pt->
2220  index_of_first_value_assigned_by_face_element_pt()==0)
2221  {
2222  bnew_master_nod_pt->
2223  index_of_first_value_assigned_by_face_element_pt()=
2224  new std::map<unsigned, unsigned>;
2225  }
2226 
2227  // Get pointer to the map of indices associated with
2228  // additional values created by face elements
2229  std::map<unsigned, unsigned>* map_pt=
2231 
2232  // Loop over number of entries in map
2233  for (unsigned i=0;i<n_entry;i++)
2234  {
2235  // Read out pairs...
2236 
2237 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2239  << " Key of map entry for master node"
2241  << std::endl;
2242 #endif
2243  unsigned first=Flat_packed_unsigneds[
2245 
2246 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2248  << " Value of map entry for master node"
2250  << std::endl;
2251 #endif
2252  unsigned second=Flat_packed_unsigneds[
2254 
2255  // ...and assign
2256  (*map_pt)[first]=second;
2257  }
2258  }
2259 
2260  }
2261  else
2262  {
2263  // Create node (not attached to any element)
2264  if (time_stepper_pt!=0)
2265  {
2266  new_master_nod_pt = new AlgebraicNode
2267  (time_stepper_pt,n_dim,n_position_type,n_value);
2268  }
2269  else
2270  {
2271  new_master_nod_pt = new AlgebraicNode
2272  (n_dim,n_position_type,n_value);
2273  }
2274  }
2275 
2276  // Add this as an external halo node BEFORE considering node update!
2277  external_mesh_pt->add_external_halo_node_pt(loc_p,new_master_nod_pt);
2278 
2279  // The external mesh is itself Algebraic...
2280  AlgebraicMesh* alg_mesh_pt=dynamic_cast<AlgebraicMesh*>
2281  (external_mesh_pt);
2282 
2283 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2284  oomph_info
2285  << "Rec:" << Counter_for_flat_packed_unsigneds
2286  << " algebraic node update id for master node "
2288  << std::endl;
2289 #endif
2290  /// The first entry of All_unsigned_values is the default node update id
2291  unsigned update_id=Flat_packed_unsigneds
2293 
2294  // Setup algebraic node update info for this new node
2295  Vector<double> ref_value;
2296 
2297 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2298  oomph_info
2299  << "Rec:" << Counter_for_flat_packed_unsigneds
2300  << " algebraic node number of ref values for master node "
2302  << std::endl;
2303 #endif
2304  // The size of this vector is in the next entry
2305  unsigned n_ref_val=Flat_packed_unsigneds
2307 
2308  // The reference values are in the subsequent entries of All_double_values
2309  ref_value.resize(n_ref_val);
2310  for (unsigned i_ref=0;i_ref<n_ref_val;i_ref++)
2311  {
2312  ref_value[i_ref]=Flat_packed_doubles
2314  }
2315 
2316  // Also require a Vector of geometric objects
2317  Vector<GeomObject*> geom_object_pt;
2318 
2319 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2320  oomph_info
2321  << "Rec:" << Counter_for_flat_packed_unsigneds
2322  << " algebraic node number of geom objects for master node "
2324  << std::endl;
2325 #endif
2326 
2327  // The size of this vector is in the next entry of All_unsigned_values
2328  unsigned n_geom_obj=Flat_packed_unsigneds
2330 
2331  // The remaining indices are in the rest of
2332  // All_alg_nodal_info
2333  geom_object_pt.resize(n_geom_obj);
2334  for (unsigned i_geom=0;i_geom<n_geom_obj;i_geom++)
2335  {
2336 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2337  oomph_info
2338  << "Rec:" << Counter_for_flat_packed_unsigneds
2339  << " algebraic node: " << i_geom << "-th out of "
2340  << n_geom_obj << "-th geom index "
2342  << std::endl;
2343 #endif
2344  unsigned geom_index=Flat_packed_unsigneds
2346 
2347  // This index indicates which (if any) of the AlgebraicMesh's
2348  // stored geometric objects should be used
2349  geom_object_pt[i_geom]=alg_mesh_pt->geom_object_list_pt(geom_index);
2350  }
2351 
2352  AlgebraicNode* alg_master_nod_pt=
2353  dynamic_cast<AlgebraicNode*>(new_master_nod_pt);
2354 
2355  /// ... so for the specified update_id, call
2356  /// add_node_update_info
2357  alg_master_nod_pt->add_node_update_info
2358  (update_id,alg_mesh_pt,geom_object_pt,ref_value);
2359 
2360  /// Now call update_node_update
2361  alg_mesh_pt->update_node_update(alg_master_nod_pt);
2362  }
2363  else if (macro_nod_pt!=0)
2364  {
2365  // The master node should also be a macro node
2366  // If this master node's haloed copy is on a boundary then
2367  // it needs to be on the same boundary here
2368 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2370  << " Boolean for master algebraic node is boundary node "
2372  << std::endl;
2373 #endif
2375  {
2376  // Create a new BoundaryNode (not attached to an element)
2377  if (time_stepper_pt!=0)
2378  {
2379  new_master_nod_pt = new BoundaryNode<MacroElementNodeUpdateNode>
2380  (time_stepper_pt,n_dim,n_position_type,n_value);
2381  }
2382  else
2383  {
2384  new_master_nod_pt = new BoundaryNode<MacroElementNodeUpdateNode>
2385  (n_dim,n_position_type,n_value);
2386  }
2387 
2388 
2389  // How many boundaries does the macro element master node live on?
2390 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2391  oomph_info
2392  << "Rec:" << Counter_for_flat_packed_unsigneds
2393  << " Number of boundaries the macro element master node is on: "
2395  << std::endl;
2396 #endif
2398  for (unsigned i=0;i<nb;i++)
2399  {
2400  // Boundary number
2401 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2403  << " Macro element master node is on boundary "
2405  << std::endl;
2406 #endif
2407  unsigned i_bnd=
2409  external_mesh_pt->add_boundary_node(i_bnd,new_master_nod_pt);
2410  }
2411 
2412  // Do we have additional values created by face elements?
2413 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2414  oomph_info
2415  << "Rec:" << Counter_for_flat_packed_unsigneds
2416  << " Number of additional values created by face element "
2417  << "for macro element master node "
2419  << std::endl;
2420 #endif
2421  unsigned n_entry=Flat_packed_unsigneds[
2423  if (n_entry>0)
2424  {
2425  // Create storage, if it doesn't already exist, for the map
2426  // that will contain the position of the first entry of
2427  // this face element's additional values,
2428  BoundaryNodeBase* bnew_master_nod_pt=
2429  dynamic_cast<BoundaryNodeBase*>(new_master_nod_pt);
2430 #ifdef PARANOID
2431  if (bnew_master_nod_pt==0)
2432  {
2433  throw OomphLibError(
2434  "Failed to cast new node to boundary node\n",
2435  OOMPH_CURRENT_FUNCTION,
2436  OOMPH_EXCEPTION_LOCATION);
2437  }
2438 #endif
2439  if(bnew_master_nod_pt->
2440  index_of_first_value_assigned_by_face_element_pt()==0)
2441  {
2442  bnew_master_nod_pt->
2443  index_of_first_value_assigned_by_face_element_pt()=
2444  new std::map<unsigned, unsigned>;
2445  }
2446 
2447  // Get pointer to the map of indices associated with
2448  // additional values created by face elements
2449  std::map<unsigned, unsigned>* map_pt=
2451 
2452  // Loop over number of entries in map
2453  for (unsigned i=0;i<n_entry;i++)
2454  {
2455  // Read out pairs...
2456 
2457 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2459  << " Key of map entry for macro element master node"
2461  << std::endl;
2462 #endif
2463  unsigned first=Flat_packed_unsigneds[
2465 
2466 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2468  << " Value of map entry for macro element master node"
2470  << std::endl;
2471 #endif
2472  unsigned second=Flat_packed_unsigneds[
2474 
2475  // ...and assign
2476  (*map_pt)[first]=second;
2477  }
2478  }
2479 
2480  }
2481  else
2482  {
2483  // Create node (not attached to any element)
2484  if (time_stepper_pt!=0)
2485  {
2486  new_master_nod_pt = new MacroElementNodeUpdateNode
2487  (time_stepper_pt,n_dim,n_position_type,n_value);
2488  }
2489  else
2490  {
2491  new_master_nod_pt = new MacroElementNodeUpdateNode
2492  (n_dim,n_position_type,n_value);
2493  }
2494  }
2495 
2496  // Add this as an external halo node
2497  external_mesh_pt->add_external_halo_node_pt(loc_p,new_master_nod_pt);
2498 
2499  // Create a new node update element for this master node if required
2500  FiniteElement *new_node_update_f_el_pt=0;
2501 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2503  << " Bool: need new external halo element "
2505  << std::endl;
2506 #endif
2508  {
2509  GeneralisedElement* new_node_update_el_pt = new EXT_ELEMENT;
2510 
2511  //Add external hal element to this mesh
2512  external_mesh_pt->add_external_halo_element_pt(
2513  loc_p,new_node_update_el_pt);
2514 
2515  //Cast to finite element
2516  new_node_update_f_el_pt =
2517  dynamic_cast<FiniteElement*>(new_node_update_el_pt);
2518 
2519  // Need number of interpolated values if Refineable
2520  int n_cont_inter_values;
2521  if (dynamic_cast<RefineableElement*>(new_node_update_f_el_pt)!=0)
2522  {
2523  n_cont_inter_values=dynamic_cast<RefineableElement*>
2524  (new_node_update_f_el_pt)->ncont_interpolated_values();
2525  }
2526  else
2527  {
2528  n_cont_inter_values=-1;
2529  }
2530 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2532  << " Bool: we have a macro element mesh "
2534  << std::endl;
2535 #endif
2536  // If we're using macro elements to update,
2538  {
2539  // Set the macro element
2540  MacroElementNodeUpdateMesh* macro_mesh_pt=
2541  dynamic_cast<MacroElementNodeUpdateMesh*>
2542  (external_mesh_pt);
2543 
2544 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2546  << " Number of macro element "
2548  << std::endl;
2549 #endif
2550  unsigned macro_el_num=
2552  new_node_update_f_el_pt->set_macro_elem_pt
2553  (macro_mesh_pt->macro_domain_pt()->macro_element_pt(macro_el_num));
2554 
2555  // we need to receive
2556  // the lower left and upper right coordinates of the macro
2557  QElementBase* q_el_pt=
2558  dynamic_cast<QElementBase*>(new_node_update_f_el_pt);
2559  if (q_el_pt!=0)
2560  {
2561  unsigned el_dim=q_el_pt->dim();
2562  for (unsigned i_dim=0;i_dim<el_dim;i_dim++)
2563  {
2564  q_el_pt->s_macro_ll(i_dim)=Flat_packed_doubles
2566  q_el_pt->s_macro_ur(i_dim)=Flat_packed_doubles
2568  }
2569  }
2570  else // Throw an error
2571  {
2572  std::ostringstream error_stream;
2573  error_stream << "You are using a MacroElement node update\n"
2574  << "in a case with non-QElements. This has not\n"
2575  << "yet been implemented.\n";
2576  throw OomphLibError
2577  (error_stream.str(),
2578  OOMPH_CURRENT_FUNCTION,
2579  OOMPH_EXCEPTION_LOCATION);
2580  }
2581  }
2582 
2583  unsigned n_node=new_node_update_f_el_pt->nnode();
2584  for (unsigned j=0;j<n_node;j++)
2585  {
2586  Node* new_nod_pt=0;
2587  add_external_halo_node_to_storage<EXT_ELEMENT>
2588  (new_nod_pt,external_mesh_pt,loc_p,j,new_node_update_f_el_pt,
2589  n_cont_inter_values,problem_pt);
2590  }
2591 
2592  }
2593  else // The node update element exists already
2594  {
2595 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2597  << " Number of already existing external halo element "
2599  << std::endl;
2600 #endif
2601  new_node_update_f_el_pt=dynamic_cast<FiniteElement*>(
2602  external_mesh_pt->external_halo_element_pt
2604  }
2605 
2606  // Remaining required information to create functioning
2607  // MacroElementNodeUpdateNode...
2608 
2609  // Get the required geom objects for the node update
2610  // from the mesh
2611  Vector<GeomObject*> geom_object_vector_pt;
2612  MacroElementNodeUpdateMesh* macro_mesh_pt=
2613  dynamic_cast<MacroElementNodeUpdateMesh*>
2614  (external_mesh_pt);
2615  geom_object_vector_pt=macro_mesh_pt->geom_object_vector_pt();
2616 
2617  // Cast to MacroElementNodeUpdateNode
2618  MacroElementNodeUpdateNode* macro_master_nod_pt=
2619  dynamic_cast<MacroElementNodeUpdateNode*>(new_master_nod_pt);
2620 
2621  // Set all required information - node update element,
2622  // local coordinate in this element, and then set node update info
2623  macro_master_nod_pt->node_update_element_pt()=
2624  new_node_update_f_el_pt;
2625 
2626  // Need to get the local node index of the macro_master_nod_pt
2627  unsigned local_node_index;
2628  unsigned n_node=new_node_update_f_el_pt->nnode();
2629  for (unsigned j=0;j<n_node;j++)
2630  {
2631  if (macro_master_nod_pt==new_node_update_f_el_pt->node_pt(j))
2632  {
2633  local_node_index=j;
2634  break;
2635  }
2636  }
2637 
2638  Vector<double> s_in_macro_node_update_element;
2639  new_node_update_f_el_pt->local_coordinate_of_node
2640  (local_node_index,s_in_macro_node_update_element);
2641 
2642  macro_master_nod_pt->set_node_update_info
2643  (new_node_update_f_el_pt,s_in_macro_node_update_element,
2644  geom_object_vector_pt);
2645  }
2646  else if (solid_nod_pt!=0)
2647  {
2648  // The master node should also be a SolidNode
2649  // If this node was on a boundary then it needs to
2650  // be on the same boundary here
2651 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2653  << " Bool master is a boundary (solid) node "
2655  << std::endl;
2656 #endif
2658  {
2659  // Construct a new boundary node
2660  if (time_stepper_pt!=0)
2661  {
2662  new_master_nod_pt=new BoundaryNode<SolidNode>
2663  (time_stepper_pt,n_lag_dim,n_lag_type,n_dim,n_position_type,n_value);
2664  }
2665  else
2666  {
2667  new_master_nod_pt=new BoundaryNode<SolidNode>
2668  (n_lag_dim,n_lag_type,n_dim,n_position_type,n_value);
2669  }
2670 
2671 
2672  // How many boundaries does the macro element master node live on?
2673 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2674  oomph_info
2675  << "Rec:" << Counter_for_flat_packed_unsigneds
2676  << " Number of boundaries the solid master node is on: "
2678  << std::endl;
2679 #endif
2681  for (unsigned i=0;i<nb;i++)
2682  {
2683  // Boundary number
2684 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2686  << " Solid master node is on boundary "
2688  << std::endl;
2689 #endif
2690  unsigned i_bnd=
2692  external_mesh_pt->add_boundary_node(i_bnd,new_master_nod_pt);
2693  }
2694 
2695  // Do we have additional values created by face elements?
2696 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2697  oomph_info
2698  << "Rec:" << Counter_for_flat_packed_unsigneds
2699  << " Number of additional values created by face element "
2700  << "for solid master node "
2702  << std::endl;
2703 #endif
2704  unsigned n_entry=Flat_packed_unsigneds[
2706  if (n_entry>0)
2707  {
2708  // Create storage, if it doesn't already exist, for the map
2709  // that will contain the position of the first entry of
2710  // this face element's additional values,
2711  BoundaryNodeBase* bnew_master_nod_pt=
2712  dynamic_cast<BoundaryNodeBase*>(new_master_nod_pt);
2713 #ifdef PARANOID
2714  if (bnew_master_nod_pt==0)
2715  {
2716  throw OomphLibError(
2717  "Failed to cast new node to boundary node\n",
2718  OOMPH_CURRENT_FUNCTION,
2719  OOMPH_EXCEPTION_LOCATION);
2720  }
2721 #endif
2722  if(bnew_master_nod_pt->
2723  index_of_first_value_assigned_by_face_element_pt()==0)
2724  {
2725  bnew_master_nod_pt->
2726  index_of_first_value_assigned_by_face_element_pt()=
2727  new std::map<unsigned, unsigned>;
2728  }
2729 
2730  // Get pointer to the map of indices associated with
2731  // additional values created by face elements
2732  std::map<unsigned, unsigned>* map_pt=
2734 
2735  // Loop over number of entries in map
2736  for (unsigned i=0;i<n_entry;i++)
2737  {
2738  // Read out pairs...
2739 
2740 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2742  << " Key of map entry for solid master node"
2744  << std::endl;
2745 #endif
2746  unsigned first=Flat_packed_unsigneds[
2748 
2749 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2751  << " Value of map entry for solid master node"
2753  << std::endl;
2754 #endif
2755  unsigned second=Flat_packed_unsigneds[
2757 
2758  // ...and assign
2759  (*map_pt)[first]=second;
2760  }
2761  }
2762 
2763  }
2764  else
2765  {
2766  // Construct an ordinary (non-boundary) node
2767  if (time_stepper_pt!=0)
2768  {
2769  new_master_nod_pt=new SolidNode
2770  (time_stepper_pt,n_lag_dim,n_lag_type,n_dim,n_position_type,n_value);
2771  }
2772  else
2773  {
2774  new_master_nod_pt=new SolidNode
2775  (n_lag_dim,n_lag_type,n_dim,n_position_type,n_value);
2776  }
2777  }
2778 
2779  // Add this as an external halo node
2780  external_mesh_pt->add_external_halo_node_pt(loc_p,new_master_nod_pt);
2781 
2782  // Copy across particular info required for SolidNode
2783  // NOTE: Are there any problems with additional values for SolidNodes?
2784  SolidNode* solid_master_nod_pt=dynamic_cast<SolidNode*>(new_master_nod_pt);
2785  unsigned n_solid_val=solid_master_nod_pt->variable_position_pt()->nvalue();
2786  for (unsigned i_val=0;i_val<n_solid_val;i_val++)
2787  {
2788  for (unsigned t=0;t<n_prev;t++)
2789  {
2790  solid_master_nod_pt->variable_position_pt()->
2791  set_value(t,i_val,
2793  }
2794  }
2795  }
2796  else // Just an ordinary node!
2797  {
2798 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2800  << " Bool node is on boundary "
2802  << std::endl;
2803 #endif
2804 
2805  // If this node was on a boundary then it needs to
2806  // be on the same boundary here
2808  {
2809  // Construct a new boundary node
2810  if (time_stepper_pt!=0)
2811  {
2812  new_master_nod_pt=new BoundaryNode<Node>
2813  (time_stepper_pt,n_dim,n_position_type,n_value);
2814  }
2815  else
2816  {
2817  new_master_nod_pt=new BoundaryNode<Node>
2818  (n_dim,n_position_type,n_value);
2819  }
2820 
2821  // How many boundaries does the master node live on?
2822 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2824  << " Number of boundaries the master node is on: "
2826  << std::endl;
2827 #endif
2829  for (unsigned i=0;i<nb;i++)
2830  {
2831  // Boundary number
2832 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2834  << " Master node is on boundary "
2836  << std::endl;
2837 #endif
2838  unsigned i_bnd=
2840  external_mesh_pt->add_boundary_node(i_bnd,new_master_nod_pt);
2841  }
2842 
2843 
2844  // Do we have additional values created by face elements?
2845 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2846  oomph_info
2847  << "Rec:" << Counter_for_flat_packed_unsigneds
2848  << " Number of additional values created by face element "
2849  << "for master node "
2851  << std::endl;
2852 #endif
2853  unsigned n_entry=Flat_packed_unsigneds[
2855  if (n_entry>0)
2856  {
2857  // Create storage, if it doesn't already exist, for the map
2858  // that will contain the position of the first entry of
2859  // this face element's additional values,
2860  BoundaryNodeBase* bnew_master_nod_pt=
2861  dynamic_cast<BoundaryNodeBase*>(new_master_nod_pt);
2862 #ifdef PARANOID
2863  if (bnew_master_nod_pt==0)
2864  {
2865  throw OomphLibError(
2866  "Failed to cast new node to boundary node\n",
2867  OOMPH_CURRENT_FUNCTION,
2868  OOMPH_EXCEPTION_LOCATION);
2869  }
2870 #endif
2871  if(bnew_master_nod_pt->
2872  index_of_first_value_assigned_by_face_element_pt()==0)
2873  {
2874  bnew_master_nod_pt->
2875  index_of_first_value_assigned_by_face_element_pt()=
2876  new std::map<unsigned, unsigned>;
2877  }
2878 
2879  // Get pointer to the map of indices associated with
2880  // additional values created by face elements
2881  std::map<unsigned, unsigned>* map_pt=
2883 
2884  // Loop over number of entries in map
2885  for (unsigned i=0;i<n_entry;i++)
2886  {
2887  // Read out pairs...
2888 
2889 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2891  << " Key of map entry for master node"
2893  << std::endl;
2894 #endif
2895  unsigned first=Flat_packed_unsigneds[
2897 
2898 #ifdef ANNOTATE_MULTI_DOMAIN_COMMUNICATION
2900  << " Value of map entry for master node"
2902  << std::endl;
2903 #endif
2904  unsigned second=Flat_packed_unsigneds[
2906 
2907  // ...and assign
2908  (*map_pt)[first]=second;
2909  }
2910  }
2911  }
2912  else
2913  {
2914  // Construct an ordinary (non-boundary) node
2915  if (time_stepper_pt!=0)
2916  {
2917  new_master_nod_pt=new Node
2918  (time_stepper_pt,n_dim,n_position_type,n_value);
2919  }
2920  else
2921  {
2922  new_master_nod_pt=new Node(n_dim,n_position_type,n_value);
2923  }
2924  }
2925 
2926  // Add this as an external halo node
2927  external_mesh_pt->add_external_halo_node_pt(loc_p,new_master_nod_pt);
2928  }
2929 
2930  // Remaining info received for all node types
2931  // Get copied history values
2932  // unsigned n_val=new_master_nod_pt->nvalue();
2933  for (unsigned i_val=0;i_val<n_value;i_val++)
2934  {
2935  for (unsigned t=0;t<n_prev;t++)
2936  {
2937  new_master_nod_pt->set_value(t,i_val,Flat_packed_doubles
2939  }
2940  }
2941 
2942  // Get copied history values for positions
2943  unsigned n_nod_dim=new_master_nod_pt->ndim();
2944  for (unsigned idim=0;idim<n_nod_dim;idim++)
2945  {
2946  for (unsigned t=0;t<n_prev;t++)
2947  {
2948  // Copy to coordinate
2949  new_master_nod_pt->x(t,idim)=Flat_packed_doubles
2951  }
2952  }
2953 
2954  }
2955 
2956 
2957 #endif
2958 
2959 
2960 }
2961 
2962 #endif
2963 
2964 
2965 
2966 
2967 
void initialise_external_element_storage()
Initialise storage for pointers to external elements and their local coordinates. This must be called...
virtual std::string tecplot_zone_string(const unsigned &nplot) const
Return string for tecplot zone header (when plotting nplot points in each "coordinate direction") ...
Definition: elements.h:2990
A Generalised Element class.
Definition: elements.h:76
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:1803
void setup_bulk_elements_adjacent_to_face_mesh(Problem *problem_pt, Vector< unsigned > &boundary_in_bulk_mesh, Mesh *const &bulk_mesh_pt, Vector< Mesh *> &face_mesh_pt, const unsigned &interaction=0)
Identify the FaceElements (stored in the mesh pointed to by face_mesh_pt) that are adjacent to the bu...
unsigned nexternal_halo_element()
Total number of external halo elements in this Mesh.
Definition: mesh.h:1874
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:246
void setup_multi_domain_interaction(Problem *problem_pt, Mesh *const &mesh_pt, Mesh *const &external_mesh_pt, const unsigned &interaction_index=0)
Function to set up the one-way multi-domain interaction for problems where the meshes pointed to by m...
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:2016
void aux_setup_multi_domain_interaction(Problem *problem_pt, Mesh *const &mesh_pt, Mesh *const &external_mesh_pt, const unsigned &interaction_index, Mesh *const &external_face_mesh_pt=0)
Auxiliary helper function.
virtual void get_s_plot(const unsigned &i, const unsigned &nplot, Vector< double > &s, const bool &shifted_to_interior=false) const
Get cector of local coordinates of plot point i (when plotting nplot points in each "coordinate direc...
Definition: elements.h:2978
virtual void output(std::ostream &outfile)
Output the element data — typically the values at the nodes in a format suitable for post-processing...
Definition: elements.h:2884
static unsigned Default_nsample_points_generated_per_element
Default for "measure of" number of sample points per element.
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 ...
void send_and_receive_located_info(int &iproc, Mesh *const &external_mesh_pt, Problem *problem_pt)
Helper function to send back any located information.
cstr elem_len * i
Definition: cfortran.h:607
unsigned Counter_for_flat_packed_unsigneds
Counter used when processing vector of flat-packed unsigneds – this is really "private" data...
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&#39;s the ID of the mesh update function (typically used ...
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 ...
GeneralisedElement *& external_halo_element_pt(const unsigned &p, const unsigned &e)
Access fct to the e-th external halo element in this Mesh whose non-halo counterpart is held on proce...
Definition: mesh.h:1902
The Problem class.
Definition: problem.h:152
void recursively_add_masters_of_external_halo_node_to_storage(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)
Recursively add masters of external halo nodes (and their masters, etc) based on information received...
unsigned nexternal_halo_node()
Total number of external halo nodes in this Mesh.
Definition: mesh.h:1958
A general Finite Element class.
Definition: elements.h:1274
RefineableBinArray class.
char t
Definition: cfortran.h:572
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:62
bool Doc_full_stats
Boolean to indicate whether to output further info during setup_multi_domain_interaction() routines...
double interpolated_x(const Vector< double > &s, const unsigned &i) const
Return FE interpolated coordinate x[i] at local coordinate s. Overloaded to get information from bulk...
Definition: elements.h:4322
CGAL-based SamplePointContainer.
MacroElement * macro_element_pt(const unsigned &i)
Access to i-th macro element.
Definition: domain.h:100
bool is_halo() const
Is this element a halo?
Definition: elements.h:1141
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:852
OomphInfo oomph_info
unsigned nvalue() const
Return number of values stored in data object (incl pinned ones).
Definition: nodes.h:448
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:53
unsigned nroot_haloed_element()
Total number of root haloed elements in this Mesh.
Definition: mesh.h:1584
void set_master_node_pt(const unsigned &i, Node *const &master_node_pt, const double &weight)
Set the pointer to the i-th master node and its weight.
Definition: nodes.cc:1417
e
Definition: cfortran.h:575
void set_boundary_number_in_bulk_mesh(const unsigned &b)
Set function for the boundary number in bulk mesh.
Definition: elements.h:4277
OomphCommunicator * communicator_pt()
access function to the oomph-lib communicator
Definition: problem.h:1221
Vector< unsigned > Flat_packed_unsigneds
Vector of flat-packed unsigneds to be communicated with other processors – this is really "private" ...
GeomObject * geom_object_list_pt(const unsigned &i)
Access function to the ith GeomObject.
virtual unsigned nplot_points(const unsigned &nplot) const
Return total number of plot points (when plotting nplot points in each "coordinate direction") ...
Definition: elements.h:3017
unsigned Dim
Dimension of zeta tuples (set by get_dim_helper) – needed because we store the scalar coordinates in...
Definition: multi_domain.cc:66
unsigned long nelement() const
Return number of elements in the mesh.
Definition: mesh.h:587
bool Doc_timings
Boolean to indicate whether to doc timings or not.
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
Definition: nodes.h:992
Base class for Qelements.
Definition: Qelements.h:106
virtual void set_macro_elem_pt(MacroElement *macro_elem_pt)
Set pointer to macro element – can be overloaded in derived elements to perform additional tasks...
Definition: elements.h:1833
double & s_macro_ur(const unsigned &i)
Access fct to the i-th coordinate of the element&#39;s "upper right" vertex in the associated MacroElemen...
Definition: Qelements.h:228
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition: nodes.h:995
A class that contains the information required by Nodes that are located on Mesh boundaries. A BoundaryNode of a particular type is obtained by combining a given Node with this class. By differentiating between Nodes and BoundaryNodes we avoid a lot of un-necessary storage in the bulk Nodes.
Definition: nodes.h:1855
virtual double interpolated_x(const Vector< double > &s, const unsigned &i) const
Return FE interpolated coordinate x[i] at local coordinate s.
Definition: elements.cc:3881
void add_external_halo_node_helper(Node *&new_nod_pt, Mesh *const &mesh_pt, unsigned &loc_p, unsigned &node_index, FiniteElement *const &new_el_pt, int &n_cont_inter_values, unsigned &counter_for_recv_unsigneds, Vector< unsigned > &recv_unsigneds, unsigned &counter_for_recv_doubles, Vector< double > &recv_doubles)
Helper functiono to add external halo node that is not a master.
unsigned nhalo_node()
Total number of halo nodes in this Mesh.
Definition: mesh.h:1542
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
Definition: mesh.h:462
Vector< double > Flat_packed_located_coordinates
Vector of flat-packed local coordinates for zeta tuples that have been located.
unsigned & current_max_spiral_level()
Access function to current max. spiral level.
void construct_new_external_halo_master_node_helper(Node *&new_master_nod_pt, Node *&nod_pt, unsigned &loc_p, Mesh *const &external_mesh_pt, Problem *problem_pt)
Helper function which constructs a new external halo master node with the information sent from the h...
Base class for all bin arrays.
unsigned max_bin_dimension() const
Max. bin dimension (number of bins in coordinate directions)
Integral *const & integral_pt() const
Return the pointer to the integration scheme (const version)
Definition: elements.h:1908
A template Class for BoundaryNodes; that is Nodes that MAY live on the boundary of a Mesh...
Definition: nodes.h:67
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:4564
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:2025
unsigned nexternal_haloed_element()
Total number of external haloed elements in this Mesh.
Definition: mesh.h:1918
static char t char * s
Definition: cfortran.h:572
unsigned nexternal_haloed_node()
Total number of external haloed nodes in this Mesh.
Definition: mesh.h:2060
virtual double knot(const unsigned &i, const unsigned &j) const =0
Return local coordinate s[j] of i-th integration point.
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:267
Domain *& macro_domain_pt()
Broken assignment operator.
void clean_up()
Helper function that clears all the intermediate information used during the external storage creatio...
virtual void write_tecplot_zone_footer(std::ostream &outfile, const unsigned &nplot) const
Add tecplot zone "footer" to output stream (when plotting nplot points in each "coordinate direction"...
Definition: elements.h:3003
Data *const & variable_position_pt() const
Pointer to variable_position data (const version)
Definition: nodes.h:1655
unsigned n_spiral_chunk() const
Number of spirals to be searched in one go const version.
TimeStepper *& time_stepper_pt()
Access function for the pointer to the first (presumably only) timestepper.
Definition: problem.h:1460
void send_and_receive_missing_zetas(Problem *problem_pt)
Helper function to send any "missing" zeta coordinates to the next process and receive any coordinate...
FiniteElement *& node_update_element_pt()
Pointer to finite element that performs the update by referring to its macro-element representation (...
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2109
double timer()
returns the time in seconds after some point in past
unsigned nhaloed_node()
Total number of haloed nodes in this Mesh.
Definition: mesh.h:1645
Vector< double > Flat_packed_doubles
Vector of flat-packed doubles to be communicated with other processors.
Class that contains data for hanging nodes.
Definition: nodes.h:684
unsigned ntstorage() const
Return the number of doubles required to represent history (one for steady)
Definition: timesteppers.h:562
unsigned long nnode() const
Return number of nodes in the mesh.
Definition: mesh.h:590
bool Use_bulk_element_as_external
Boolean to indicate when to use the bulk element as the external element. Defaults to false...
FiniteElement * finite_element_pt(const unsigned &e) const
Upcast (downcast?) to FiniteElement (needed to access FiniteElement member functions).
Definition: mesh.h:477
void add_external_halo_master_node_helper(Node *&new_master_nod_pt, Node *&new_nod_pt, Mesh *const &external_mesh_pt, unsigned &loc_p, int &n_cont_inter_values, Problem *problem_pt)
Helper function to add external halo node that is a master.
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...
void set_hanging_pt(HangInfo *const &hang_pt, const int &i)
Set the hanging data for the i-th value. (hang_pt=0 to make non-hanging)
Definition: nodes.cc:1997
unsigned dim() const
Return the spatial dimension of the element, i.e. the number of local coordinates required to paramet...
Definition: elements.h:2482
double & s_macro_ll(const unsigned &i)
Access fct to the i-th coordinate of the element&#39;s "lower left" vertex in the associated MacroElement...
Definition: Qelements.h:211
A Class for nodes that deform elastically (i.e. position is an unknown in the problem). The idea is that the Eulerian positions are stored in a Data object and the Lagrangian coordinates are stored in addition. The pointer that addresses the Eulerian positions is set to the pointer to Value in the Data object. Hence, SolidNode uses knowledge of the internal structure of Data and must be a friend of the Data class. In order to allow a mesh to deform via an elastic-style equation in deforming-domain problems, the positions are stored separately from the values, so that elastic problems may be combined with any other type of problem.
Definition: nodes.h:1569
unsigned nroot_halo_element()
Total number of root halo elements in this Mesh.
Definition: mesh.h:1496
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:97
NonRefineableBinArray class.
virtual unsigned nweight() const =0
Return the number of integration points of the scheme.
Vector< Vector< unsigned > > External_element_located
Lookup scheme for whether a local element&#39;s integration point has had an external element assigned to...
Definition: multi_domain.cc:74
FiniteElement *& external_element_pt(const unsigned &interaction_index, const unsigned &ipt)
Access function to source element for specified interaction index at specified integration point...
bool Doc_stats
Boolean to indicate whether to output basic info during setup_multi_domain_interaction() routines...
A class to do comparison of the elements by lexicographic ordering, based on the boundary coordinates...
bool problem_has_been_distributed()
Access to Problem_has_been_distributed flag.
Definition: problem.h:2056
void create_external_halo_elements(int &iproc, const Vector< Mesh *> &mesh_pt, Mesh *const &external_mesh_pt, Problem *problem_pt, const unsigned &interaction_index)
Create external (halo) elements on the loop process based on the information received from each locat...
virtual void output_bins(std::ofstream &outfile)=0
Output bins (boundaries and number of sample points in them)
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:1910
unsigned & current_min_spiral_level()
Access function to current min. spiral level.
void add_external_halo_element_pt(const unsigned &p, GeneralisedElement *&el_pt)
Add external halo element whose non-halo counterpart is held on processor p to this Mesh...
Definition: mesh.h:1910
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:80
unsigned nnode() const
Return the number of nodes.
Definition: elements.h:2146
Base class for time-stepping schemes. Timestepper provides an approximation of the temporal derivativ...
Definition: timesteppers.h:219
void delete_all_external_storage()
Wipe the storage for all externally-based elements.
Definition: mesh.cc:8816
void add_external_halo_node_to_storage(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 function to add external halo nodes, including any masters, based on information received from...
Vector< unsigned > Located_element_status
Vector to indicate (to another processor) whether a located element (that will have to represented as...
Vector< GeomObject * > geom_object_vector_pt()
Access function to the vector of GeomObject.
A general mesh class.
Definition: mesh.h:74
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.
unsigned Counter_for_flat_packed_doubles
Counter used when processing vector of flat-packed doubles – this is really "private" data...
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)
Helper function to locate "local" zeta coordinates This is the vector-based version which operates si...
An oomph-lib wrapper to the MPI_Comm communicator object. Just contains an MPI_Comm object (which is ...
Definition: communicator.h:57
void setup_multi_domain_interactions(Problem *problem_pt, Mesh *const &first_mesh_pt, Mesh *const &second_mesh_pt, const unsigned &first_interaction=0, const unsigned &second_interaction=0)
Set up the two-way multi-domain interactions for the problem pointed to by problem_pt. Use this for cases where first_mesh_pt and second_mesh_pt occupy the same physical space and are populated by ELEMENT_0 and ELEMENT_1 respectively, and are combined to solve a single problem. The elements in two meshes interact both ways the elements in each mesh act as "external elements" for the elements in the "other" mesh. The interaction indices allow the specification of which interaction we&#39;re setting up in the two meshes. They default to zero, which is appropriate if there&#39;s only a single interaction.