oomph::Multi_domain_functions Namespace Reference

Enumerations

enum  { New , Exists , Not_found }
 Enumerators for element status in location procedure. More...
 

Functions

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)
 
void get_dim_helper (Problem *problem_pt, Mesh *const &mesh_pt, Mesh *const &external_mesh_pt)
 
void clean_up ()
 
bool first_closer_than_second (const std::pair< FiniteElement *, Vector< double >> &p1, const std::pair< FiniteElement *, Vector< double >> &p2)
 
template<class BULK_ELEMENT , unsigned DIM>
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)
 / Templated helper functions for multi-domain methods using locate_zeta More...
 
template<class BULK_ELEMENT , unsigned DIM>
void setup_bulk_elements_adjacent_to_face_mesh (Problem *problem_pt, const unsigned &boundary_in_bulk_mesh, Mesh *const &bulk_mesh_pt, Mesh *const &face_mesh_pt, const unsigned &interaction=0)
 
template<class ELEMENT_0 , class ELEMENT_1 >
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)
 
template<class EXT_ELEMENT >
void setup_multi_domain_interaction (Problem *problem_pt, Mesh *const &mesh_pt, Mesh *const &external_mesh_pt, const unsigned &interaction_index=0)
 
template<class EXT_ELEMENT , class FACE_ELEMENT_GEOM_OBJECT >
void setup_multi_domain_interaction (Problem *problem_pt, Mesh *const &mesh_pt, Mesh *const &external_mesh_pt, Mesh *const &external_face_mesh_pt, const unsigned &interaction_index=0)
 
template<class EXT_ELEMENT , class FACE_ELEMENT_GEOM_OBJECT >
void setup_multi_domain_interaction (Problem *problem_pt, const Vector< Mesh * > &mesh_pt, Mesh *const &external_mesh_pt, const Vector< Mesh * > &external_face_mesh_pt, const unsigned &interaction_index=0)
 
template<class EXT_ELEMENT , class GEOM_OBJECT >
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. More...
 
template<class EXT_ELEMENT , class GEOM_OBJECT >
void aux_setup_multi_domain_interaction (Problem *problem_pt, const Vector< Mesh * > &mesh_pt, Mesh *const &external_mesh_pt, const unsigned &interaction_index, const Vector< Mesh * > &external_face_mesh_pt)
 Auxiliary helper function. More...
 

Variables

std::ofstream Doc_boundary_coordinate_file
 
bool Accept_failed_locate_zeta_in_setup_multi_domain_interaction = false
 
unsigned Dim
 
Vector< Vector< unsigned > > External_element_located
 
Vector< doubleFlat_packed_zetas_not_found_locally
 
Vector< doubleReceived_flat_packed_zetas_to_be_found
 
Vector< intProc_id_plus_one_of_external_element
 
Vector< unsignedLocated_element_status
 
Vector< doubleFlat_packed_located_coordinates
 
Vector< doubleFlat_packed_doubles
 
unsigned Counter_for_flat_packed_doubles
 
Vector< unsignedFlat_packed_unsigneds
 
unsigned Counter_for_flat_packed_unsigneds
 
bool Use_bulk_element_as_external = false
 
bool Allow_use_of_halo_elements_as_external_elements = true
 
bool Allow_use_of_halo_elements_as_external_elements_for_projection = true
 
bool Doc_timings = false
 Boolean to indicate whether to doc timings or not. More...
 
bool Doc_stats = false
 
bool Doc_full_stats = false
 
Vector< doubleZeta_coords_for_further_away_comparison
 

Enumeration Type Documentation

◆ anonymous enum

anonymous enum

Enumerators for element status in location procedure.

Enumerator
New 
Exists 
Not_found 
148  {
149  New,
150  Exists,
151  Not_found
152  };
@ New
Definition: multi_domain.h:149
@ Not_found
Definition: multi_domain.h:151
@ Exists
Definition: multi_domain.h:150

Function Documentation

◆ aux_setup_multi_domain_interaction() [1/2]

template<class EXT_ELEMENT , class GEOM_OBJECT >
void oomph::Multi_domain_functions::aux_setup_multi_domain_interaction ( Problem problem_pt,
const Vector< Mesh * > &  mesh_pt,
Mesh *const &  external_mesh_pt,
const unsigned interaction_index,
const Vector< Mesh * > &  external_face_mesh_pt 
)

Auxiliary helper function.

This routine calls the locate_zeta routine (simultaneously on each processor for each individual processor's element set if necessary) and sets up the external (halo) element and node storage as necessary. The locate_zeta procedure here works for all multi-domain problems where either two meshes occupy the same physical space but have differing element types (e.g. a Boussinesq convection problem where AdvectionDiffusion elements interact with Navier-Stokes type elements) or two meshes interact along some boundary of the external mesh, represented by a "face mesh", such as an FSI problem.

Vector-based version operates simultaneously on the meshes contained in the vectors.

If it's is now zero then break out of the spirals loop

530  {
531  // How many meshes do we have?
532  unsigned n_mesh = mesh_pt.size();
533 
534 #ifdef PARANOID
535  if (external_face_mesh_pt.size() != n_mesh)
536  {
537  std::ostringstream error_stream;
538  error_stream << "Sizes of external_face_mesh_pt [ "
539  << external_face_mesh_pt.size() << " ] and "
540  << "mesh_pt [ " << n_mesh << " ] don't match.\n";
541  throw OomphLibError(
542  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
543  }
544 #endif
545 
546  // Bail out?
547  if (n_mesh == 0) return;
548 
549  // Multi-domain setup will not work for elements with
550  // nonuniformly spaced nodes
551  // Must check type of elements in the mesh and in the external mesh
552  //(assume element type is the same for all elements in each mesh)
553 
554 #ifdef PARANOID
555 
556  // Pointer to first element in external mesh
557  GeneralisedElement* ext_el_pt_0 = 0;
558  if (external_mesh_pt->nelement() != 0)
559  {
560  ext_el_pt_0 = external_mesh_pt->element_pt(0);
561  }
562 
563  // Loop over all meshes
564  for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
565  {
566  // Get pointer to first element in each mesh
567  GeneralisedElement* el_pt_0 = 0;
568  if (mesh_pt[i_mesh]->nelement() != 0)
569  {
570  el_pt_0 = mesh_pt[i_mesh]->element_pt(0);
571  }
572 
573  // Check they are not spectral elements
574  if (dynamic_cast<SpectralElement*>(el_pt_0) != 0 ||
575  dynamic_cast<SpectralElement*>(ext_el_pt_0) != 0)
576  {
577  throw OomphLibError(
578  "Multi-domain setup does not work with spectral elements.",
581  }
582 
583  // Check they are not hp-refineable elements
584  if (dynamic_cast<PRefineableElement*>(el_pt_0) != 0 ||
585  dynamic_cast<PRefineableElement*>(ext_el_pt_0) != 0)
586  {
587  throw OomphLibError(
588  "Multi-domain setup does not work with hp-refineable elements.",
591  }
592  } // end over initial loop over meshes
593 
594 #endif
595 
596 
597 #ifdef OOMPH_HAS_MPI
598  // Storage for number of processors and my rank
599  int n_proc = problem_pt->communicator_pt()->nproc();
600  int my_rank = problem_pt->communicator_pt()->my_rank();
601 #endif
602 
603  // Timing
604  double t_start = 0.0;
605  double t_end = 0.0;
606  double t_local = 0.0;
607  double t_set = 0.0;
608  double t_locate = 0.0;
609  double t_spiral_start = 0.0;
610 #ifdef OOMPH_HAS_MPI
611  double t_loop_start = 0.0;
612  double t_sendrecv = 0.0;
613  double t_missing = 0.0;
614  double t_send_info = 0.0;
615  double t_create_halo = 0.0;
616 #endif
617 
618  if (Doc_timings)
619  {
620  t_start = TimingHelpers::timer();
621  }
622 
623  // Initialize number of zeta coordinates not found yet
624  unsigned n_zeta_not_found = 0;
625 
626  // Geometric objects used to represent the external (face) meshes
627  Vector<MeshAsGeomObject*> mesh_geom_obj_pt(n_mesh, 0);
628 
629 #ifdef PARANOID
630 
631  // Initialise lagrangian dimension of element (test only)
632  unsigned el_dim_lag = 0;
633 
634 #endif
635 
636  // Create mesh as geom objects for all meshes
637  for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
638  {
639  // Are bulk elements used as external elements?
641  {
642  // Fix this when required
643  if (n_mesh != 1)
644  {
645  std::ostringstream error_stream;
646  error_stream
647  << "Sorry I currently can't deal with non-bulk external elements\n"
648  << "in multi-domain setup for multiple meshes.\n"
649  << "The functionality should be easy to implement now that you\n"
650  << "have a test case. If you're not willinig to do this, call\n"
651  << "the multi-domain setup mesh-by-mesh instead (though this can\n"
652  << "be costly in parallel because of global comms. \n";
653  throw OomphLibError(error_stream.str(),
656  }
657 
658  // Set the geometric object from the external mesh
659  mesh_geom_obj_pt[0] = new MeshAsGeomObject(external_mesh_pt);
660  }
661  else
662  {
663  // Set the geometric object from the external face mesh argument
664  mesh_geom_obj_pt[i_mesh] =
665  new MeshAsGeomObject(external_face_mesh_pt[i_mesh]);
666  }
667 
668 #ifdef PARANOID
669  unsigned old_el_dim_lag = el_dim_lag;
670 
671  // Set lagrangian dimension of element
672  el_dim_lag = mesh_geom_obj_pt[i_mesh]->nlagrangian();
673 
674  // Check consistency
675  if (i_mesh > 0)
676  {
677  if (el_dim_lag != old_el_dim_lag)
678  {
679  std::ostringstream error_stream;
680  error_stream << "Lagrangian dimensions of elements don't match \n "
681  << "between meshes: " << el_dim_lag << " "
682  << old_el_dim_lag << "\n";
683  throw OomphLibError(error_stream.str(),
686  }
687  }
688 #endif
689 
690 
691  } // end of loop over meshes
692 
693  double t_setup_lookups = 0.0;
694  if (Doc_timings)
695  {
696  t_set = TimingHelpers::timer();
697  oomph_info << "CPU for creation of MeshAsGeomObjects and bin structure: "
698  << t_set - t_start << std::endl;
699  t_setup_lookups = TimingHelpers::timer();
700  }
701 
702  // Total number of integration points
703  unsigned tot_int = 0;
704 
705  // Counter for total number of elements (in flat packed order)
706  unsigned e_count = 0;
707 
708  // Loop over all meshes to get total number of elements
709  for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
710  {
711  e_count += mesh_pt[i_mesh]->nelement();
712  }
713  External_element_located.resize(e_count);
714 
715  // Reset counter for elements in flat packed storage
716  e_count = 0;
717 
718  // Loop over all meshes
719  for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
720  {
721  // Loop over (this processor's) elements and set lookup array
722  unsigned n_element = mesh_pt[i_mesh]->nelement();
723  for (unsigned e = 0; e < n_element; e++)
724  {
725  // Zero-sized vector means its a halo
726  External_element_located[e_count].resize(0);
727  ElementWithExternalElement* el_pt =
728  dynamic_cast<ElementWithExternalElement*>(
729  mesh_pt[i_mesh]->element_pt(e));
730 
731 #ifdef OOMPH_HAS_MPI
732  // We're not setting up external elements for halo elements
733  if (!el_pt->is_halo())
734 #endif
735  {
736  // We need to allocate storage for the external elements
737  // within the element. Memory will actually only be
738  // allocated the first time this function is called for
739  // each element, or if the number of interactions or integration
740  // points within the element has changed.
741  el_pt->initialise_external_element_storage();
742 
743  // Clear any previous allocation
744  unsigned n_intpt = el_pt->integral_pt()->nweight();
745  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
746  {
747  el_pt->external_element_pt(interaction_index, ipt) = 0;
748  }
749 
750  External_element_located[e_count].resize(n_intpt);
751  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
752  {
753  External_element_located[e_count][ipt] = 0;
754  tot_int++;
755  }
756  }
757  // next element
758  e_count++;
759  }
760  } // end of loop over meshes
761 
762  if (Doc_timings)
763  {
764  double t = TimingHelpers::timer();
765  oomph_info
766  << "CPU for setup of lookup schemes for located elements/coords: "
767  << t - t_setup_lookups << std::endl;
768  }
769 
770  // Initialise maximum spiral level within the cartesian bin structure
771  // Used to terminate spiraling for non-refineable bin
772  unsigned n_max_level = 0;
773 
774 #ifdef OOMPH_HAS_MPI
775  unsigned max_level_reached = 1;
776 #endif
777 
778  // Max. number of sample points -- used to decide on termination of
779  // "spiraling"
780  unsigned max_n_sample_points_of_sample_point_containers = 0;
781 
782  // Loop over all meshes
783  for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
784  {
785  if (mesh_geom_obj_pt[i_mesh]->sample_point_container_version() ==
787  {
788  RefineableBinArray* bin_array_pt = dynamic_cast<RefineableBinArray*>(
789  mesh_geom_obj_pt[i_mesh]->sample_point_container_pt());
790 
791  bin_array_pt
793  bin_array_pt
795  bin_array_pt
797 
798  unsigned nsp =
800  if (nsp > max_n_sample_points_of_sample_point_containers)
801  {
802  max_n_sample_points_of_sample_point_containers = nsp;
803  }
804 
805 
806 #ifdef OOMPH_HAS_MPI
807  // If the mesh has been distributed we want the max. number
808  // of sample points across all processors
809  if (problem_pt->communicator_pt()->nproc() > 1)
810  {
811  unsigned local_max_n_sample_points_of_sample_point_containers =
812  max_n_sample_points_of_sample_point_containers;
813 
814  // Get maximum over all processors
815  MPI_Allreduce(&local_max_n_sample_points_of_sample_point_containers,
816  &max_n_sample_points_of_sample_point_containers,
817  1,
818  MPI_UNSIGNED,
819  MPI_MAX,
820  problem_pt->communicator_pt()->mpi_comm());
821  }
822 #endif
823  }
824  else if (mesh_geom_obj_pt[i_mesh]->sample_point_container_version() ==
826  {
827  NonRefineableBinArray* bin_array_pt =
828  dynamic_cast<NonRefineableBinArray*>(
829  mesh_geom_obj_pt[i_mesh]->sample_point_container_pt());
830 
831  // Initialise spiral levels
832  bin_array_pt->current_min_spiral_level() = 0;
833  bin_array_pt->current_max_spiral_level() =
834  bin_array_pt->n_spiral_chunk() - 1;
835 
836  // Find maximum spiral level within the cartesian bin structure
837  n_max_level = bin_array_pt->max_bin_dimension();
838 
839  // Limit it
840  if (bin_array_pt->current_max_spiral_level() > n_max_level)
841  {
842  bin_array_pt->current_max_spiral_level() = n_max_level - 1;
843  }
844  }
845 #ifdef OOMPH_HAS_CGAL
846  // CGAL
847  else if (mesh_geom_obj_pt[i_mesh]->sample_point_container_version() ==
848  UseCGALSamplePointContainer)
849  {
850  CGALSamplePointContainer* bin_array_pt =
851  dynamic_cast<CGALSamplePointContainer*>(
852  mesh_geom_obj_pt[i_mesh]->sample_point_container_pt());
853  bin_array_pt
854  ->last_sample_point_to_actually_lookup_during_locate_zeta() =
855  bin_array_pt
856  ->initial_last_sample_point_to_actually_lookup_during_locate_zeta();
857  bin_array_pt
858  ->first_sample_point_to_actually_lookup_during_locate_zeta() = 0;
859 
860  unsigned nsp =
861  bin_array_pt->total_number_of_sample_points_computed_recursively();
862  if (nsp > max_n_sample_points_of_sample_point_containers)
863  {
864  max_n_sample_points_of_sample_point_containers = nsp;
865  }
866 
867 
868 #ifdef OOMPH_HAS_MPI
869  // If the mesh has been distributed we want the max. number
870  // of sample points across all processors
871  if (problem_pt->communicator_pt()->nproc() > 1)
872  {
873  unsigned local_max_n_sample_points_of_sample_point_containers =
874  max_n_sample_points_of_sample_point_containers;
875 
876  // Get maximum over all processors
877  MPI_Allreduce(&local_max_n_sample_points_of_sample_point_containers,
878  &max_n_sample_points_of_sample_point_containers,
879  1,
880  MPI_UNSIGNED,
881  MPI_MAX,
882  problem_pt->communicator_pt()->mpi_comm());
883  }
884 #endif
885  }
886 #endif // cgal
887  }
888 
889 
890  // Storage for info about coordinate location
891  Vector<double> percentage_coords_located_locally;
892  Vector<double> percentage_coords_located_elsewhere;
893 
894  // Loop over "spirals/levels" away from the current position
895  // Note: All meshes go through their spirals simultaneously;
896  // read out spiral level from first one
897  unsigned i_level = 0;
898  bool has_not_reached_max_level_of_search = true;
899  while (has_not_reached_max_level_of_search)
900  {
901  // Record time at start of spiral loop
902  if (Doc_timings)
903  {
904  t_spiral_start = TimingHelpers::timer();
905  }
906 
907  // Perform locate_zeta locally first! This looks locally for
908  // all not-yet-located zetas within the current spiral range.
910  mesh_pt, external_mesh_pt, mesh_geom_obj_pt, interaction_index);
911 
912  // Store stats about successful locates for reporting later
913  if (Doc_stats)
914  {
915  unsigned count_locates = 0;
916  unsigned n_ext_loc = External_element_located.size();
917  for (unsigned e = 0; e < n_ext_loc; e++)
918  {
919  unsigned n_intpt = External_element_located[e].size();
920  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
921  {
922  count_locates += External_element_located[e][ipt];
923  }
924  }
925 
926  // Store percentage of integration points successfully located.
927  // Only assign if we had anything to allocte, otherwise 100%
928  // (default assignment; see above) is correct
929  if (tot_int != 0)
930  {
931  percentage_coords_located_locally.push_back(
932  100.0 * double(count_locates) / double(tot_int));
933  }
934  else
935  {
936  // Had none to find so we found them all!
937  percentage_coords_located_locally.push_back(100.0);
938  }
939  }
940 
941 
942  // Now test whether anything needs to be broadcast elsewhere
943  // (i.e. were there any failures in the locate method above?)
944  // If there are, then the zetas for these failures need to be
945  // broadcast...
946 
947  // How many zetas have we failed to find? [Note: Array is padded
948  // by Dim padded entries (DBL_MAX) for each mesh]
949  n_zeta_not_found =
950  Flat_packed_zetas_not_found_locally.size() - Dim * n_mesh;
951 
952  if (Doc_timings)
953  {
954  t_local = TimingHelpers::timer();
955  oomph_info << "CPU for local location of zeta coordinate [spiral level "
956  << i_level << "]: " << t_local - t_spiral_start << std::endl
957  << "Number of missing zetas: " << n_zeta_not_found
958  << std::endl;
959  }
960 
961 
962 #ifdef OOMPH_HAS_MPI
963  // Only perform the reduction operation if there's more than one process
964  if (problem_pt->communicator_pt()->nproc() > 1)
965  {
966  unsigned count_local_zetas = n_zeta_not_found;
967  MPI_Allreduce(&count_local_zetas,
968  &n_zeta_not_found,
969  1,
970  MPI_UNSIGNED,
971  MPI_SUM,
972  problem_pt->communicator_pt()->mpi_comm());
973  }
974 
975  // If we have missing zetas on any process
976  // and the problem is distributed, we need to locate elsewhere
977  if ((n_zeta_not_found != 0) &&
978  (problem_pt->problem_has_been_distributed()))
979  {
980  // Timings
981  double t_sendrecv_min = DBL_MAX;
982  double t_sendrecv_max = -DBL_MAX;
983  double t_sendrecv_tot = 0.0;
984 
985  double t_missing_min = DBL_MAX;
986  double t_missing_max = -DBL_MAX;
987  double t_missing_tot = 0.0;
988 
989  double t_send_info_min = DBL_MAX;
990  double t_send_info_max = -DBL_MAX;
991  double t_send_info_tot = 0.0;
992 
993  double t_create_halo_min = DBL_MAX;
994  double t_create_halo_max = -DBL_MAX;
995  double t_create_halo_tot = 0.0;
996 
997  // Start ring communication: Loop (number of processes - 1)
998  // starting from 1. The variable iproc represents the "distance" from
999  // the current process to the process for which it is attempting
1000  // to locate an element for the current set of not-yet-located
1001  // zeta coordinates
1002  unsigned ring_count = 0;
1003  for (int iproc = 1; iproc < n_proc; iproc++)
1004  {
1005  // Record time at start of loop
1006  if (Doc_timings)
1007  {
1008  t_loop_start = TimingHelpers::timer();
1009  }
1010 
1011  // Send the zeta values you haven't found to the
1012  // next process, receive from the previous process:
1013  // (Padded) Flat_packed_zetas_not_found_locally are sent
1014  // to next processor where they are received as
1015  // (padded) Received_flat_packed_zetas_to_be_found.
1016  send_and_receive_missing_zetas(problem_pt);
1017 
1018  if (Doc_timings)
1019  {
1020  ring_count++;
1021  t_sendrecv = TimingHelpers::timer();
1022  t_sendrecv_max =
1023  std::max(t_sendrecv_max, t_sendrecv - t_loop_start);
1024  t_sendrecv_min =
1025  std::min(t_sendrecv_min, t_sendrecv - t_loop_start);
1026  t_sendrecv_tot += (t_sendrecv - t_loop_start);
1027  }
1028 
1029  // Perform the locate_zeta for the new set of zetas on this process
1030  locate_zeta_for_missing_coordinates(
1031  iproc, external_mesh_pt, problem_pt, mesh_geom_obj_pt);
1032 
1033  if (Doc_timings)
1034  {
1035  t_missing = TimingHelpers::timer();
1036  t_missing_max = std::max(t_missing_max, t_missing - t_sendrecv);
1037  t_missing_min = std::min(t_missing_min, t_missing - t_sendrecv);
1038  t_missing_tot += (t_missing - t_sendrecv);
1039  }
1040 
1041  // Send any located coordinates back to the correct process, and
1042  // prepare to send on to the next process if necessary
1043  send_and_receive_located_info(iproc, external_mesh_pt, problem_pt);
1044 
1045  if (Doc_timings)
1046  {
1047  t_send_info = TimingHelpers::timer();
1048  t_send_info_max =
1049  std::max(t_send_info_max, t_send_info - t_missing);
1050  t_send_info_min =
1051  std::min(t_send_info_min, t_send_info - t_missing);
1052  t_send_info_tot += (t_send_info - t_missing);
1053  }
1054 
1055  // Create any located external halo elements on the current process
1056  create_external_halo_elements<EXT_ELEMENT>(
1057  iproc, mesh_pt, external_mesh_pt, problem_pt, interaction_index);
1058 
1059  if (Doc_timings)
1060  {
1061  t_create_halo = TimingHelpers::timer();
1062  t_create_halo_max =
1063  std::max(t_create_halo_max, t_create_halo - t_send_info);
1064  t_create_halo_min =
1065  std::min(t_create_halo_min, t_create_halo - t_send_info);
1066  t_create_halo_tot += (t_create_halo - t_send_info);
1067  }
1068 
1069  // Do we have any further locating to do or have we found
1070  // everything at this level of the ring communication?
1071  // Only perform the reduction operation if there's more than
1072  // one process [Note: Array is padded
1073  // by DIM times DBL_MAX entries for each mesh]
1074  n_zeta_not_found =
1075  Flat_packed_zetas_not_found_locally.size() - Dim * n_mesh;
1076 
1077 
1078 #ifdef OOMPH_HAS_MPI
1079  if (problem_pt->communicator_pt()->nproc() > 1)
1080  {
1081  unsigned count_local_zetas = n_zeta_not_found;
1082  MPI_Allreduce(&count_local_zetas,
1083  &n_zeta_not_found,
1084  1,
1085  MPI_UNSIGNED,
1086  MPI_SUM,
1087  problem_pt->communicator_pt()->mpi_comm());
1088  }
1089 #endif
1090 
1091  // If its is now zero then break out of the ring comms loop
1092  if (n_zeta_not_found == 0)
1093  {
1094  if (Doc_timings)
1095  {
1096  t_local = TimingHelpers::timer();
1097  oomph_info << "BREAK N-1: CPU for entrire spiral [spiral level "
1098  << i_level << "]: " << t_local - t_spiral_start
1099  << std::endl;
1100  }
1101  break;
1102  }
1103  }
1104 
1105 
1106  // Doc timings
1107  if (Doc_timings)
1108  {
1109  oomph_info << "Ring-based search continued until iteration "
1110  << ring_count << " out of a maximum of "
1111  << problem_pt->communicator_pt()->nproc() - 1 << "\n";
1112  oomph_info << "Total, av, max, min CPU for send/recv of remaining "
1113  "zeta coordinates: "
1114  << t_sendrecv_tot << " "
1115  << t_sendrecv_tot / double(ring_count) << " "
1116  << t_sendrecv_max << " " << t_sendrecv_min << "\n";
1117  oomph_info << "Total, av, max, min CPU for location of missing zeta "
1118  "coordinates : "
1119  << t_missing_tot << " "
1120  << t_missing_tot / double(ring_count) << " "
1121  << t_missing_max << " " << t_missing_min << "\n";
1122  oomph_info << "Total, av, max, min CPU for send/recv of new element "
1123  "info : "
1124  << t_send_info_tot << " "
1125  << t_send_info_tot / double(ring_count) << " "
1126  << t_send_info_max << " " << t_send_info_min << "\n";
1127  oomph_info << "Total, av, max, min CPU for local creation of "
1128  "external halo objects: "
1129  << t_create_halo_tot << " "
1130  << t_create_halo_tot / double(ring_count) << " "
1131  << t_create_halo_max << " " << t_create_halo_min << "\n";
1132  }
1133 
1134  } // end if for missing zetas on any process
1135 #endif
1136 
1137 
1138  // Store information about location of elements for integration points
1139  if (Doc_stats)
1140  {
1141  unsigned count_locates = 0;
1142  unsigned n_ext_loc = External_element_located.size();
1143  for (unsigned e = 0; e < n_ext_loc; e++)
1144  {
1145  unsigned n_intpt = External_element_located[e].size();
1146  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
1147  {
1148  count_locates += External_element_located[e][ipt];
1149  }
1150  }
1151 
1152 
1153  // Store total percentage of locates so far.
1154  // Only assign if we had anything to allocte, otherwise 100%
1155  // (default assignment) is correct
1156  if (tot_int != 0)
1157  {
1158  percentage_coords_located_elsewhere.push_back(
1159  100.0 * double(count_locates) / double(tot_int));
1160  }
1161  else
1162  {
1163  // Had none to find so we found them all!
1164  percentage_coords_located_locally.push_back(100.0);
1165  }
1166  }
1167 
1168  // Do we have any further locating to do? If so, the remaining
1169  // zetas will (hopefully) be found at the next spiral level.
1170  // Only perform the reduction operation if there's more than one process
1171  // [Note: Array is padded
1172  // by DIM times DBL_MAX entries for each mesh]
1173  n_zeta_not_found =
1174  Flat_packed_zetas_not_found_locally.size() - Dim * n_mesh;
1175 
1176 
1177 #ifdef OOMPH_HAS_MPI
1178  if (problem_pt->communicator_pt()->nproc() > 1)
1179  {
1180  unsigned count_local_zetas = n_zeta_not_found;
1181  MPI_Allreduce(&count_local_zetas,
1182  &n_zeta_not_found,
1183  1,
1184  MPI_UNSIGNED,
1185  MPI_SUM,
1186  problem_pt->communicator_pt()->mpi_comm());
1187  }
1188 
1189  // Specify max level reached for later loop
1190  max_level_reached = i_level + 1;
1191 #endif
1192 
1194  if (n_zeta_not_found == 0)
1195  {
1196  if (Doc_timings)
1197  {
1198  t_local = TimingHelpers::timer();
1199  oomph_info << "BREAK N: CPU for entrire spiral [spiral level "
1200  << i_level << "]: " << t_local - t_spiral_start
1201  << std::endl;
1202  }
1203  break;
1204  }
1205 
1206  if (Doc_timings)
1207  {
1208  t_local = TimingHelpers::timer();
1209  oomph_info << "CPU for entrire spiral [spiral level " << i_level
1210  << "]: " << t_local - t_spiral_start << std::endl;
1211  }
1212 
1213  // Bump up spiral levels for all meshes
1214  i_level++;
1215  for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
1216  {
1217  if (mesh_geom_obj_pt[i_mesh]->sample_point_container_version() ==
1219  {
1220  RefineableBinArray* bin_array_pt = dynamic_cast<RefineableBinArray*>(
1221  mesh_geom_obj_pt[i_mesh]->sample_point_container_pt());
1222  bin_array_pt
1224  bin_array_pt
1226  bin_array_pt
1228  bin_array_pt
1230  }
1231  else if (mesh_geom_obj_pt[i_mesh]->sample_point_container_version() ==
1233  {
1234  NonRefineableBinArray* bin_array_pt =
1235  dynamic_cast<NonRefineableBinArray*>(
1236  mesh_geom_obj_pt[i_mesh]->sample_point_container_pt());
1237 
1238  bin_array_pt->current_min_spiral_level() +=
1239  bin_array_pt->n_spiral_chunk();
1240  bin_array_pt->current_max_spiral_level() +=
1241  bin_array_pt->n_spiral_chunk();
1242  }
1243 #ifdef OOMPH_HAS_CGAL
1244  else if (mesh_geom_obj_pt[i_mesh]->sample_point_container_version() ==
1245  UseCGALSamplePointContainer)
1246  {
1247  CGALSamplePointContainer* bin_array_pt =
1248  dynamic_cast<CGALSamplePointContainer*>(
1249  mesh_geom_obj_pt[i_mesh]->sample_point_container_pt());
1250  bin_array_pt
1251  ->first_sample_point_to_actually_lookup_during_locate_zeta() =
1252  bin_array_pt
1253  ->last_sample_point_to_actually_lookup_during_locate_zeta();
1254  bin_array_pt
1255  ->last_sample_point_to_actually_lookup_during_locate_zeta() *=
1256  bin_array_pt
1257  ->multiplier_for_max_sample_point_to_actually_lookup_during_locate_zeta();
1258  }
1259 #endif // cgal
1260  }
1261 
1262  // Check termination criterion for while loop
1263  if (mesh_geom_obj_pt[0]->sample_point_container_version() ==
1265  {
1266  RefineableBinArray* bin_array_pt = dynamic_cast<RefineableBinArray*>(
1267  mesh_geom_obj_pt[0]->sample_point_container_pt());
1268 
1269  if (bin_array_pt
1270  ->first_sample_point_to_actually_lookup_during_locate_zeta() <=
1271  max_n_sample_points_of_sample_point_containers)
1272  {
1273  has_not_reached_max_level_of_search = true;
1274  }
1275  else
1276  {
1277  has_not_reached_max_level_of_search = false;
1278  }
1279  }
1280  else if (mesh_geom_obj_pt[0]->sample_point_container_version() ==
1282  {
1283  NonRefineableBinArray* bin_array_pt =
1284  dynamic_cast<NonRefineableBinArray*>(
1285  mesh_geom_obj_pt[0]->sample_point_container_pt());
1286 
1287  if (bin_array_pt->current_max_spiral_level() < n_max_level)
1288  {
1289  has_not_reached_max_level_of_search = true;
1290  }
1291  else
1292  {
1293  has_not_reached_max_level_of_search = false;
1294  }
1295  }
1296 #ifdef OOMPH_HAS_CGAL
1297  else if (mesh_geom_obj_pt[0]->sample_point_container_version() ==
1298  UseCGALSamplePointContainer)
1299  {
1300  CGALSamplePointContainer* bin_array_pt =
1301  dynamic_cast<CGALSamplePointContainer*>(
1302  mesh_geom_obj_pt[0]->sample_point_container_pt());
1303 
1304  if (bin_array_pt
1305  ->first_sample_point_to_actually_lookup_during_locate_zeta() <=
1306  max_n_sample_points_of_sample_point_containers)
1307  {
1308  has_not_reached_max_level_of_search = true;
1309  }
1310  else
1311  {
1312  has_not_reached_max_level_of_search = false;
1313  }
1314  }
1315 #endif // cgal
1316  } // end of "spirals" loop
1317 
1318 
1319  // If we haven't found all zetas we're dead now...
1320  //-------------------------------------------------
1321  if (n_zeta_not_found != 0)
1322  {
1323  // Shout?
1325  {
1326  std::ostringstream error_stream;
1327  error_stream
1328  << "Multi_domain_functions::locate_zeta_for_local_coordinates()"
1329  << "\nhas failed ";
1330 
1331 #ifdef OOMPH_HAS_MPI
1332  if (problem_pt->communicator_pt()->nproc() > 1)
1333  {
1334  error_stream << " on proc: "
1335  << problem_pt->communicator_pt()->my_rank() << std::endl;
1336  }
1337 #endif
1338  error_stream
1339  << "\n\n\nThis is most likely to arise because the two meshes\n"
1340  << "that are to be matched don't overlap perfectly or\n"
1341  << "because the elements are distorted and too small a \n"
1342  << "number of sampling points has been used when setting\n"
1343  << "up the bin structure.\n\n"
1344  << "You should try to increase the value of \n"
1345  << "the number of sample points defined in \n\n"
1346  << " "
1347  "SamplePointContainerParameters::Default_nsample_points_generated_"
1348  "per_element"
1349  << "\n\n from its current value of "
1350  << SamplePointContainerParameters::
1351  Default_nsample_points_generated_per_element
1352  << "\n"
1353  << "\n\n"
1354  << "NOTE: You can suppress this error and \"accept failure\""
1355  << " by setting the public boolean \n\n"
1356  << " "
1357  "Multi_domain_functions::Accept_failed_locate_zeta_in_setup_multi_"
1358  "domain_interaction\n\n"
1359  << " to true. In this case, the pointers to external elements\n"
1360  << " that couldn't be located will remain null\n";
1361 
1362  std::ostringstream modifier;
1363 #ifdef OOMPH_HAS_MPI
1364  if (problem_pt->communicator_pt()->nproc() > 1)
1365  {
1366  modifier << "_proc" << problem_pt->communicator_pt()->my_rank();
1367  }
1368 #endif
1369 
1370  // Loop over all meshes
1371  for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
1372  {
1373  // Add yet another modifier to distinguish meshes if reqd
1374  if (n_mesh > 1)
1375  {
1376  modifier << "_mesh" << i_mesh;
1377  }
1378 
1379  std::ofstream outfile;
1380  char filename[100];
1381  sprintf(
1382  filename, "missing_coords_mesh%s.dat", modifier.str().c_str());
1383  outfile.open(filename);
1384  unsigned nel = mesh_pt[i_mesh]->nelement();
1385  for (unsigned e = 0; e < nel; e++)
1386  {
1387  mesh_pt[i_mesh]->finite_element_pt(e)->output(outfile);
1388  // FiniteElement::output(outfile);
1389  }
1390  outfile.close();
1391 
1392  sprintf(
1393  filename, "missing_coords_ext_mesh%s.dat", modifier.str().c_str());
1394  outfile.open(filename);
1395  nel = external_mesh_pt->nelement();
1396  for (unsigned e = 0; e < nel; e++)
1397  {
1398  external_mesh_pt->finite_element_pt(e)->output(outfile);
1399  // FiniteElement::output(outfile);
1400  }
1401  outfile.close();
1402 
1403  BinArray* bin_array_pt = dynamic_cast<BinArray*>(
1404  mesh_geom_obj_pt[i_mesh]->sample_point_container_pt());
1405  if (bin_array_pt != 0)
1406  {
1407  sprintf(
1408  filename, "missing_coords_bin%s.dat", modifier.str().c_str());
1409  outfile.open(filename);
1410  bin_array_pt->output_bins(outfile);
1411  outfile.close();
1412  }
1413 
1414  sprintf(filename, "missing_coords%s.dat", modifier.str().c_str());
1415  outfile.open(filename);
1416  unsigned n = External_element_located.size();
1417  error_stream << "Number of unlocated elements " << n << std::endl;
1418  for (unsigned e = 0; e < n; e++)
1419  {
1420  unsigned n_intpt = External_element_located[e].size();
1421  if (n_intpt == 0)
1422  {
1423  error_stream << "Failure to locate in halo element! "
1424  << "Why are we searching there?" << std::endl;
1425  }
1426  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
1427  {
1428  if (External_element_located[e][ipt] == 0)
1429  {
1430  error_stream << "Failure at element/intpt: " << e << " " << ipt
1431  << std::endl;
1432 
1433  // Cast
1434  ElementWithExternalElement* el_pt =
1435  dynamic_cast<ElementWithExternalElement*>(
1436  mesh_pt[i_mesh]->element_pt(e));
1437 
1438  unsigned n_dim_el = el_pt->dim();
1439  Vector<double> s(n_dim_el);
1440  for (unsigned i = 0; i < n_dim_el; i++)
1441  {
1442  s[i] = el_pt->integral_pt()->knot(ipt, i);
1443  }
1444  unsigned n_dim = el_pt->node_pt(0)->ndim();
1445  Vector<double> x(n_dim);
1446  el_pt->interpolated_x(s, x);
1447  for (unsigned i = 0; i < n_dim; i++)
1448  {
1449  error_stream << x[i] << " ";
1450  outfile << x[i] << " ";
1451  }
1452  error_stream << std::endl;
1453  outfile << std::endl;
1454  }
1455  }
1456  }
1457  outfile.close();
1458  }
1459 
1460  error_stream
1461  << "Mesh and external mesh documented in missing_coords_mesh*.dat\n"
1462  << "and missing_coords_ext_mesh*.dat, respectively. Missing \n"
1463  << "coordinates in missing_coords*.dat\n";
1464  throw OomphLibError(
1465  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1466  }
1467  // Failure is deeemed to be acceptable
1468  else
1469  {
1470  oomph_info
1471  << "NOTE: Haven't found " << n_zeta_not_found
1472  << " external elements in \n"
1473  << "Multi_domain_functions::aux_setup_multi_domain_interaction(...)\n"
1474  << "but this deemed to be acceptable because \n"
1475  << "Multi_domain_functions::Accept_failed_locate_zeta_in_setup_multi_"
1476  "domain_interaction\n"
1477  << "is true.\n";
1478  }
1479  }
1480 
1481 
1482  // Doc timings if required
1483  if (Doc_timings)
1484  {
1485  t_locate = TimingHelpers::timer();
1486  oomph_info
1487  << "Total CPU for location and creation of all external elements: "
1488  << t_locate - t_start << std::endl;
1489  }
1490 
1491  // Delete the geometric object representing the mesh
1492  for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
1493  {
1494  delete mesh_geom_obj_pt[i_mesh];
1495  }
1496 
1497  // Clean up all the (extern) Vectors associated with creating the
1498  // external storage information
1499  clean_up();
1500 
1501 #ifdef OOMPH_HAS_MPI
1502 
1503  // Output information about external storage if required
1504  if (Doc_stats)
1505  {
1506  // Report stats regarding location method
1507  bool comm_was_required = false;
1508  oomph_info << "-------------------------------------------" << std::endl;
1509  oomph_info << "- Cumulative percentage of locate success -" << std::endl;
1510  oomph_info << "--- Spiral -- Found local -- Found else ---" << std::endl;
1511  for (unsigned level = 0; level < max_level_reached; level++)
1512  {
1513  oomph_info << "--- " << level << " -- "
1514  << percentage_coords_located_locally[level] << " -- "
1515  << percentage_coords_located_elsewhere[level] << " ---"
1516  << std::endl;
1517  // Has communication with other processors at this level actually
1518  // produced any results?
1519  if (percentage_coords_located_elsewhere[level] >
1520  percentage_coords_located_locally[level])
1521  {
1522  comm_was_required = true;
1523  }
1524  }
1525  oomph_info << "-------------------------------------------" << std::endl;
1526 
1527 
1528  // No need for any of this malaki if we're not running in parallel
1529  if (problem_pt->communicator_pt()->nproc() > 1)
1530  {
1531  // Initialise to indicate that none of the zetas required
1532  // on this processor were located through parallel ring search,
1533  // i.e. comm was not required and we could have done some
1534  // more local searching first
1535  oomph_info << std::endl;
1536  oomph_info << "ASSESSMENT OF NEED FOR PARALLEL SEARCH: \n";
1537  oomph_info << "=======================================\n";
1538  unsigned status = 0;
1539  if (comm_was_required)
1540  {
1541  oomph_info << "- Ring-based parallel search did successfully locate "
1542  "zetas on proc "
1543  << my_rank << std::endl;
1544  status = 1;
1545  }
1546  else
1547  {
1548  if (max_level_reached > 1)
1549  {
1550  oomph_info
1551  << "- Ring-based parallel search did NOT locate zetas on proc"
1552  << my_rank << std::endl;
1553  }
1554  else
1555  {
1556  oomph_info
1557  << "- No ring-based parallel search was performed on proc"
1558  << my_rank << std::endl;
1559  }
1560  }
1561 
1562  // Allreduce to check if anyone has benefitted from parallel ring
1563  // search
1564  unsigned overall_status = 0;
1565  MPI_Allreduce(&status,
1566  &overall_status,
1567  1,
1568  MPI_UNSIGNED,
1569  MPI_MAX,
1570  problem_pt->communicator_pt()->mpi_comm());
1571 
1572  // Report of mpi was useful to anyone
1573  if (overall_status == 1)
1574  {
1575  oomph_info << "- Ring-based, parallel search did succesfully\n";
1576  oomph_info << " locate zetas on at least one other proc, so it\n";
1577  oomph_info << " was worthwhile.\n";
1578  oomph_info << std::endl;
1579  }
1580  else
1581  {
1582  if (max_level_reached > 1)
1583  {
1584  oomph_info
1585  << "- Ring-based, parallel search did NOT locate zetas\n";
1586  oomph_info << " on ANY other procs, i.e it was useless.\n";
1587  oomph_info
1588  << " --> We should really have done more local search\n";
1589  oomph_info
1590  << " by reducing number of bins, or doing more spirals\n";
1591  oomph_info << " in one go before initiating parallel search.\n";
1592  oomph_info << std::endl;
1593  }
1594  else
1595  {
1596  oomph_info << "- No ring-based, parallel search was performed\n";
1597  oomph_info << " or necessary. Perfect!\n";
1598  oomph_info << std::endl;
1599  }
1600  }
1601  }
1602 
1603  // How many external elements does the external mesh have now?
1604  oomph_info << "------------------------------------------" << std::endl;
1605  oomph_info << "External mesh: I have " << external_mesh_pt->nelement()
1606  << " elements, and " << std::endl
1607  << external_mesh_pt->nexternal_halo_element()
1608  << " external halo elements, "
1609  << external_mesh_pt->nexternal_haloed_element()
1610  << " external haloed elements" << std::endl;
1611 
1612  // How many external nodes does each submesh have now?
1613  oomph_info << "------------------------------------------" << std::endl;
1614  oomph_info << "External mesh: I have " << external_mesh_pt->nnode()
1615  << " nodes, and " << std::endl
1616  << external_mesh_pt->nexternal_halo_node()
1617  << " external halo nodes, "
1618  << external_mesh_pt->nexternal_haloed_node()
1619  << " external haloed nodes" << std::endl;
1620  oomph_info << "------------------------------------------" << std::endl;
1621  }
1622 
1623  // Output further information about (external) halo(ed)
1624  // elements and nodes if required
1625  if (Doc_full_stats)
1626  {
1627  // How many elements does this submesh have for each of the processors?
1628  for (int iproc = 0; iproc < n_proc; iproc++)
1629  {
1630  oomph_info << "----------------------------------------" << std::endl;
1631  oomph_info << "With process " << iproc << " there are "
1632  << external_mesh_pt->nroot_halo_element(iproc)
1633  << " root halo elements, and "
1634  << external_mesh_pt->nroot_haloed_element(iproc)
1635  << " root haloed elements" << std::endl
1636  << "and there are "
1637  << external_mesh_pt->nexternal_halo_element(iproc)
1638  << " external halo elements, and "
1639  << external_mesh_pt->nexternal_haloed_element(iproc)
1640  << " external haloed elements." << std::endl;
1641 
1642  oomph_info << "----------------------------------------" << std::endl;
1643  oomph_info << "With process " << iproc << " there are "
1644  << external_mesh_pt->nhalo_node(iproc) << " halo nodes, and "
1645  << external_mesh_pt->nhaloed_node(iproc) << " haloed nodes"
1646  << std::endl
1647  << "and there are "
1648  << external_mesh_pt->nexternal_halo_node(iproc)
1649  << " external halo nodes, and "
1650  << external_mesh_pt->nexternal_haloed_node(iproc)
1651  << " external haloed nodes." << std::endl;
1652  }
1653  oomph_info << "-----------------------------------------" << std::endl
1654  << std::endl;
1655  }
1656 
1657 #endif
1658 
1659  // Doc timings if required
1660  if (Doc_timings)
1661  {
1662  t_end = TimingHelpers::timer();
1663  oomph_info << "CPU for (one way) aux_setup_multi_domain_interaction: "
1664  << t_end - t_start << std::endl;
1665  }
1666 
1667  } // end of aux_setup_multi_domain_interaction
int i
Definition: BiCGSTAB_step_by_step.cpp:9
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
Array< double, 1, 3 > e(1./3., 0.5, 2.)
Base class for all bin arrays.
Definition: sample_point_container.h:402
unsigned max_bin_dimension() const
Max. bin dimension (number of bins in coordinate directions)
Definition: sample_point_container.cc:659
virtual void output_bins(std::ofstream &outfile)=0
Output bins (boundaries and number of sample points in them)
NonRefineableBinArray class.
Definition: sample_point_container.h:819
unsigned n_spiral_chunk() const
Number of spirals to be searched in one go const version.
Definition: sample_point_container.h:866
unsigned & current_max_spiral_level()
Access function to current max. spiral level.
Definition: sample_point_container.h:891
unsigned & current_min_spiral_level()
Access function to current min. spiral level.
Definition: sample_point_container.h:885
RefineableBinArray class.
Definition: sample_point_container.h:521
unsigned total_number_of_sample_points_computed_recursively() const
Compute total number of sample points recursively.
Definition: sample_point_container.cc:1820
unsigned & initial_last_sample_point_to_actually_lookup_during_locate_zeta()
Definition: sample_point_container.h:741
unsigned & first_sample_point_to_actually_lookup_during_locate_zeta()
Definition: sample_point_container.h:712
unsigned & last_sample_point_to_actually_lookup_during_locate_zeta()
Definition: sample_point_container.h:720
unsigned & multiplier_for_max_sample_point_to_actually_lookup_during_locate_zeta()
Definition: sample_point_container.h:732
#define min(a, b)
Definition: datatypes.h:22
#define max(a, b)
Definition: datatypes.h:23
RealScalar s
Definition: level1_cplx_impl.h:130
static const unsigned Dim
Problem dimension.
Definition: two_d_tilted_square.cc:62
string filename
Definition: MergeRestartFiles.py:39
bool Doc_full_stats
Definition: missing_masters.cc:67
bool Doc_stats
Definition: missing_masters.cc:63
bool Doc_timings
Boolean to indicate whether to doc timings or not.
Definition: missing_masters.cc:59
Vector< Vector< unsigned > > External_element_located
Definition: multi_domain.cc:68
void clean_up()
Definition: multi_domain.cc:2413
Vector< double > Flat_packed_zetas_not_found_locally
Definition: multi_domain.cc:74
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)
Definition: multi_domain.cc:2153
bool Use_bulk_element_as_external
Definition: multi_domain.cc:142
bool Accept_failed_locate_zeta_in_setup_multi_domain_interaction
Definition: multi_domain.cc:56
@ UseRefineableBinArray
Definition: sample_point_parameters.h:41
@ UseNonRefineableBinArray
Definition: sample_point_parameters.h:42
OomphInfo oomph_info
Definition: oomph_definitions.cc:319
list x
Definition: plotDoE.py:28
t
Definition: plotPSD.py:36
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86
double timer
Definition: oomph_metis_from_parmetis_3.1.1/struct.h:210

References Accept_failed_locate_zeta_in_setup_multi_domain_interaction, clean_up(), oomph::Problem::communicator_pt(), NonRefineableBinArray::current_max_spiral_level(), NonRefineableBinArray::current_min_spiral_level(), Global_Variables::Dim, oomph::FiniteElement::dim(), oomph::Missing_masters_functions::Doc_full_stats, oomph::Missing_masters_functions::Doc_stats, oomph::Missing_masters_functions::Doc_timings, e(), oomph::Mesh::element_pt(), External_element_located, oomph::ElementWithExternalElement::external_element_pt(), MergeRestartFiles::filename, oomph::Mesh::finite_element_pt(), RefineableBinArray::first_sample_point_to_actually_lookup_during_locate_zeta(), Flat_packed_zetas_not_found_locally, i, RefineableBinArray::initial_last_sample_point_to_actually_lookup_during_locate_zeta(), oomph::ElementWithExternalElement::initialise_external_element_storage(), oomph::FiniteElement::integral_pt(), oomph::FiniteElement::interpolated_x(), oomph::Integral::knot(), RefineableBinArray::last_sample_point_to_actually_lookup_during_locate_zeta(), locate_zeta_for_local_coordinates(), max, BinArray::max_bin_dimension(), min, RefineableBinArray::multiplier_for_max_sample_point_to_actually_lookup_during_locate_zeta(), oomph::OomphCommunicator::my_rank(), n, NonRefineableBinArray::n_spiral_chunk(), oomph::Node::ndim(), oomph::Mesh::nelement(), oomph::Mesh::nnode(), oomph::FiniteElement::node_pt(), oomph::OomphCommunicator::nproc(), oomph::Integral::nweight(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, oomph::oomph_info, oomph::FiniteElement::output(), BinArray::output_bins(), s, plotPSD::t, oomph::TimingHelpers::timer(), RefineableBinArray::total_number_of_sample_points_computed_recursively(), Use_bulk_element_as_external, oomph::UseNonRefineableBinArray, oomph::UseRefineableBinArray, and plotDoE::x.

◆ aux_setup_multi_domain_interaction() [2/2]

template<class EXT_ELEMENT , class GEOM_OBJECT >
void oomph::Multi_domain_functions::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.

This routine calls the locate_zeta routine (simultaneously on each processor for each individual processor's element set if necessary) and sets up the external (halo) element and node storage as necessary. The locate_zeta procedure here works for all multi-domain problems where either two meshes occupy the same physical space but have differing element types (e.g. a Boussinesq convection problem where AdvectionDiffusion elements interact with Navier-Stokes type elements) or two meshes interact along some boundary of the external mesh, represented by a "face mesh", such as an FSI problem.

491  {
492  // Convert to vector-based storage
493  Vector<Mesh*> mesh_pt_vector(1);
494  mesh_pt_vector[0] = mesh_pt;
495  Vector<Mesh*> external_face_mesh_pt_vector(1);
496  external_face_mesh_pt_vector[0] = external_face_mesh_pt;
497 
498  // Call vector-based version
499  aux_setup_multi_domain_interaction<EXT_ELEMENT, GEOM_OBJECT>(
500  problem_pt,
501  mesh_pt_vector,
502  external_mesh_pt,
503  interaction_index,
504  external_face_mesh_pt_vector);
505 
506  } // end of aux_setup_multi_domain_interaction

◆ clean_up()

void oomph::Multi_domain_functions::clean_up ( )

Helper function that clears all the information used during the external storage creation

Helper function that clears all the intermediate information used during the external storage creation at the end of the procedure

2414  {
2418  Located_element_status.clear();
2420  Flat_packed_doubles.clear();
2421  Flat_packed_unsigneds.clear();
2422  External_element_located.clear();
2423  }
Vector< int > Proc_id_plus_one_of_external_element
Definition: multi_domain.cc:91
Vector< double > Flat_packed_located_coordinates
Definition: multi_domain.cc:102
Vector< double > Flat_packed_doubles
Definition: multi_domain.cc:106
Vector< unsigned > Flat_packed_unsigneds
Definition: multi_domain.cc:118
Vector< double > Received_flat_packed_zetas_to_be_found
Definition: multi_domain.cc:82
Vector< unsigned > Located_element_status
Definition: multi_domain.cc:98

References External_element_located, Flat_packed_doubles, Flat_packed_located_coordinates, Flat_packed_unsigneds, Flat_packed_zetas_not_found_locally, Located_element_status, Proc_id_plus_one_of_external_element, and Received_flat_packed_zetas_to_be_found.

Referenced by aux_setup_multi_domain_interaction().

◆ first_closer_than_second()

bool oomph::Multi_domain_functions::first_closer_than_second ( const std::pair< FiniteElement *, Vector< double >> &  p1,
const std::pair< FiniteElement *, Vector< double >> &  p2 
)

Comparison function for sorting entries in bin: Returns true if point identified by p1 (comprising pointer to finite element and vector of local coordinates within that element) is closer to Zeta_coords_for_further_away_comparison than p2

2436  {
2437  // First point
2438  FiniteElement* el_pt = p1.first;
2439  Vector<double> s(p1.second);
2440  Vector<double> zeta(Dim);
2441  el_pt->interpolated_zeta(s, zeta);
2442  double dist_squared1 = 0.0;
2443  for (unsigned i = 0; i < Dim; i++)
2444  {
2445  dist_squared1 +=
2448  }
2449 
2450  // Second point
2451  el_pt = p2.first;
2452  s = p2.second;
2453  el_pt->interpolated_zeta(s, zeta);
2454  double dist_squared2 = 0.0;
2455  for (unsigned i = 0; i < Dim; i++)
2456  {
2457  dist_squared2 +=
2460  }
2461 
2462  // Which one is further
2463  if (dist_squared1 < dist_squared2)
2464  {
2465  return true;
2466  }
2467  else
2468  {
2469  return false;
2470  }
2471  }
Vector3f p1
Definition: MatrixBase_all.cpp:2
EIGEN_STRONG_INLINE const Eigen::CwiseBinaryOp< Eigen::internal::scalar_zeta_op< typename DerivedX::Scalar >, const DerivedX, const DerivedQ > zeta(const Eigen::ArrayBase< DerivedX > &x, const Eigen::ArrayBase< DerivedQ > &q)
Definition: SpecialFunctionsArrayAPI.h:152
unsigned Dim
Definition: multi_domain.cc:60
Vector< double > Zeta_coords_for_further_away_comparison
Definition: multi_domain.cc:2427

References Dim, i, oomph::FiniteElement::interpolated_zeta(), p1, s, Eigen::zeta(), and Zeta_coords_for_further_away_comparison.

◆ get_dim_helper()

void oomph::Multi_domain_functions::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 checks they are the same). Stores result in Dim.

Helper function that computes the dimension of the elements within each of the specified meshes (and checks they are the same) Stores result in Dim.

2346  {
2347 #ifdef OOMPH_HAS_MPI
2348  // Storage for number of processors, current process and communicator
2349  OomphCommunicator* comm_pt = problem_pt->communicator_pt();
2350 #endif
2351 
2352  // Extract the element dimensions from the first element of each mesh
2353  unsigned mesh_dim = 0;
2354  if (mesh_pt->nelement() > 0)
2355  {
2356  mesh_dim = dynamic_cast<FiniteElement*>(mesh_pt->element_pt(0))->dim();
2357  }
2358  unsigned external_mesh_dim = 0;
2359  if (external_mesh_pt->nelement() > 0)
2360  {
2361  external_mesh_dim =
2362  dynamic_cast<FiniteElement*>(external_mesh_pt->element_pt(0))->dim();
2363  }
2364 
2365  // Need to do an Allreduce
2366 #ifdef OOMPH_HAS_MPI
2367  int n_proc = comm_pt->nproc();
2368  if (n_proc > 1)
2369  {
2370  unsigned mesh_dim_reduce;
2371  MPI_Allreduce(&mesh_dim,
2372  &mesh_dim_reduce,
2373  1,
2374  MPI_UNSIGNED,
2375  MPI_MAX,
2376  comm_pt->mpi_comm());
2377  mesh_dim = mesh_dim_reduce;
2378 
2379  unsigned external_mesh_dim_reduce;
2380  MPI_Allreduce(&external_mesh_dim,
2381  &external_mesh_dim_reduce,
2382  1,
2383  MPI_UNSIGNED,
2384  MPI_MAX,
2385  comm_pt->mpi_comm());
2386  external_mesh_dim = external_mesh_dim_reduce;
2387  }
2388 #endif
2389 
2390  // Check the dimensions are the same!
2391  if (mesh_dim != external_mesh_dim)
2392  {
2393  std::ostringstream error_stream;
2394  error_stream << "The elements within the two meshes do not\n"
2395  << "have the same dimension, so the multi-domain\n"
2396  << "method will not work.\n"
2397  << "For the mesh, dim=" << mesh_dim
2398  << ", and the external mesh, dim=" << external_mesh_dim
2399  << "\n";
2400  throw OomphLibError(
2401  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2402  }
2403 
2404  // Set dimension
2405  Dim = mesh_dim;
2406  }

References oomph::Problem::communicator_pt(), Dim, oomph::Mesh::element_pt(), oomph::Mesh::nelement(), oomph::OomphCommunicator::nproc(), OOMPH_CURRENT_FUNCTION, and OOMPH_EXCEPTION_LOCATION.

Referenced by setup_multi_domain_interaction().

◆ locate_zeta_for_local_coordinates()

void oomph::Multi_domain_functions::locate_zeta_for_local_coordinates ( const Vector< Mesh * > &  mesh_pt,
Mesh *const &  external_mesh_pt,
Vector< MeshAsGeomObject * > &  mesh_geom_obj_pt,
const unsigned interaction_index 
)

locate zeta for current set of "local" coordinates vector-based version

Helper function to locate "local" zeta coordinates This is the vector-based version which operates simultaenously on the meshes contained in the Vectors.

2158  {
2159  // Flush storage for zetas not found locally
2161 
2162  // Number of meshes
2163  unsigned n_mesh = mesh_pt.size();
2164 
2165 #ifdef PARANOID
2166  if (mesh_geom_obj_pt.size() != n_mesh)
2167  {
2168  std::ostringstream error_stream;
2169  error_stream << "Sizes of mesh_geom_obj_pt [ "
2170  << mesh_geom_obj_pt.size() << " ] and "
2171  << "mesh_pt [ " << n_mesh << " ] don't match.\n";
2172  throw OomphLibError(
2173  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2174  }
2175 #endif
2176 
2177  // Element counter
2178  unsigned e_count = 0;
2179 
2180  // Loop over meshes
2181  for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
2182  {
2183  // Number of local elements
2184  unsigned n_element = mesh_pt[i_mesh]->nelement();
2185 
2186  // Loop over this processor's elements
2187  for (unsigned e = 0; e < n_element; e++)
2188  {
2189  ElementWithExternalElement* el_pt =
2190  dynamic_cast<ElementWithExternalElement*>(
2191  mesh_pt[i_mesh]->element_pt(e));
2192 #ifdef OOMPH_HAS_MPI
2193  // Only visit non-halo elements -- we're not setting up external
2194  // elements for on-halos!
2195  if (!el_pt->is_halo())
2196 #endif
2197  {
2198  // Find number of Gauss points and element dimension
2199  unsigned n_intpt = el_pt->integral_pt()->nweight();
2200  unsigned el_dim = el_pt->dim();
2201 
2202 
2203 #ifdef PARANOID
2204  if (el_dim != Dim)
2205  {
2206  std::ostringstream error_stream;
2207  error_stream << "Dimension of element " << el_dim
2208  << " is not consitent with dimension assumed \n"
2209  << " in multidomain namespace, " << Dim << std::endl;
2210  throw OomphLibError(error_stream.str(),
2213  }
2214 #endif
2215 
2216  // Set storage for local and global coordinates
2217  Vector<double> s_local(el_dim);
2218  Vector<double> x_global(el_dim);
2219 
2220  // Loop over integration points
2221  for (unsigned ipt = 0; ipt < n_intpt; ipt++)
2222  {
2223  // Has this integration point been done yet?
2224  if (External_element_located[e_count][ipt] == 0)
2225  {
2226  // Get local coordinates
2227  for (unsigned i = 0; i < el_dim; i++)
2228  {
2229  s_local[i] = el_pt->integral_pt()->knot(ipt, i);
2230  }
2231  // Interpolate to global coordinates
2232  el_pt->interpolated_zeta(s_local, x_global);
2233 
2234  // Storage for geometric object and its local coordinates
2235  GeomObject* sub_geom_obj_pt = 0;
2236  Vector<double> s_ext(el_dim);
2237  mesh_geom_obj_pt[i_mesh]->locate_zeta(
2238  x_global, sub_geom_obj_pt, s_ext);
2239 
2240  // Has the required element been located?
2241  if (sub_geom_obj_pt != 0)
2242  {
2243  // The required element has been located
2244  // The located coordinates have the same dimension as the bulk
2245  GeneralisedElement* source_el_pt;
2246  Vector<double> s_source(el_dim);
2247 
2248  // Is the bulk element the actual external element?
2250  {
2251  // Use the object directly (it must be a finite element)
2252  source_el_pt =
2253  dynamic_cast<FiniteElement*>(sub_geom_obj_pt);
2254  s_source = s_ext;
2255  }
2256  else
2257  {
2258  // Cast to a FaceElement and use the bulk element
2259  FaceElement* face_el_pt =
2260  dynamic_cast<FaceElement*>(sub_geom_obj_pt);
2261  source_el_pt = face_el_pt->bulk_element_pt();
2262 
2263  // Need to resize the located coordinates to have the same
2264  // dimension as the bulk element
2265  s_source.resize(
2266  dynamic_cast<FiniteElement*>(source_el_pt)->dim());
2267 
2268  // Translate the returned local coords into the bulk element
2269  face_el_pt->get_local_coordinate_in_bulk(s_ext, s_source);
2270  }
2271 
2272  // Check if it's a halo; if it is then the non-halo equivalent
2273  // needs to be located from another processor (unless we
2274  // accept halo elements as external elements)
2275 #ifdef OOMPH_HAS_MPI
2277  (!source_el_pt->is_halo()))
2278 #endif
2279  {
2280  // Need to cast to a FiniteElement
2281  FiniteElement* source_finite_el_pt =
2282  dynamic_cast<FiniteElement*>(source_el_pt);
2283 
2284  // Set the external element pointer and local coordinates
2285  el_pt->external_element_pt(interaction_index, ipt) =
2286  source_finite_el_pt;
2287  el_pt->external_element_local_coord(interaction_index,
2288  ipt) = s_source;
2289 
2290  // Set the lookup array to 1/true
2291  External_element_located[e_count][ipt] = 1;
2292  }
2293 #ifdef OOMPH_HAS_MPI
2294  // located element is halo and we're not accepting haloes
2295  // obviously only makes sense in mpi mode...
2296  else
2297  {
2298  // Add required information to arrays
2299  for (unsigned i = 0; i < el_dim; i++)
2300  {
2302  x_global[i]);
2303  }
2304  }
2305 #endif
2306  }
2307  else
2308  {
2309  // Search has failed then add the required information to the
2310  // arrays which need to be sent to the other processors so
2311  // that they can perform the locate_zeta
2312 
2313  // Add this global coordinate to the LOCAL zeta array
2314  for (unsigned i = 0; i < el_dim; i++)
2315  {
2316  Flat_packed_zetas_not_found_locally.push_back(x_global[i]);
2317  }
2318  }
2319  }
2320  } // end loop over integration points
2321  } // end for halo
2322 
2323  // Bump up counter for all elements
2324  e_count++;
2325 
2326  } // end loop over local elements
2327 
2328  // Mark end of mesh data in flat packed array
2329  for (unsigned i = 0; i < Dim; i++)
2330  {
2331  Flat_packed_zetas_not_found_locally.push_back(DBL_MAX);
2332  }
2333 
2334  } // end of loop over meshes
2335  }
bool Allow_use_of_halo_elements_as_external_elements
Definition: multi_domain.cc:149
unsigned el_dim
dimension
Definition: overloaded_cartesian_element_body.h:30

References Allow_use_of_halo_elements_as_external_elements, oomph::FaceElement::bulk_element_pt(), oomph::FiniteElement::dim(), Dim, e(), el_dim, oomph::ElementWithExternalElement::external_element_local_coord(), External_element_located, oomph::ElementWithExternalElement::external_element_pt(), Flat_packed_zetas_not_found_locally, oomph::FaceElement::get_local_coordinate_in_bulk(), i, oomph::FiniteElement::integral_pt(), oomph::FiniteElement::interpolated_zeta(), oomph::Integral::knot(), oomph::Integral::nweight(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and Use_bulk_element_as_external.

Referenced by aux_setup_multi_domain_interaction().

◆ setup_bulk_elements_adjacent_to_face_mesh() [1/2]

template<class BULK_ELEMENT , unsigned DIM>
void oomph::Multi_domain_functions::setup_bulk_elements_adjacent_to_face_mesh ( Problem problem_pt,
const unsigned boundary_in_bulk_mesh,
Mesh *const &  bulk_mesh_pt,
Mesh *const &  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 bulk elements next to the boundary_in_bulk_mesh -th boundary of the mesh pointed to by bulk_mesh_pt. The FaceElements must be derived from the ElementWithExternalElement base class and the adjacent bulk elements are stored as their external elements.

213  {
214  // Convert to vector-based storage
215  Vector<unsigned> boundary_in_bulk_mesh_vect(1);
216  boundary_in_bulk_mesh_vect[0] = boundary_in_bulk_mesh;
217  Vector<Mesh*> face_mesh_pt_vect(1);
218  face_mesh_pt_vect[0] = face_mesh_pt;
219 
220  // Call vector-based version
221  setup_bulk_elements_adjacent_to_face_mesh<BULK_ELEMENT, DIM>(
222  problem_pt,
223  boundary_in_bulk_mesh_vect,
224  bulk_mesh_pt,
225  face_mesh_pt_vect,
226  interaction);
227  }

◆ setup_bulk_elements_adjacent_to_face_mesh() [2/2]

template<class BULK_ELEMENT , unsigned DIM>
void oomph::Multi_domain_functions::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 
)

/ Templated helper functions for multi-domain methods using locate_zeta

Identify the FaceElements (stored in the mesh pointed to by face_mesh_pt) that are adjacent to the bulk elements next to the boundary_in_bulk_mesh -th boundary of the mesh pointed to by bulk_mesh_pt. The FaceElements must be derived from the ElementWithExternalElement base class and the adjacent bulk elements are stored as their external elements.

This is the vector-based version which deals with multiple bulk mesh boundaries at the same time.

78  {
79  unsigned n_mesh = boundary_in_bulk_mesh.size();
80 
81 #ifdef PARANOID
82  // Check sizes match
83  if (boundary_in_bulk_mesh.size() != face_mesh_pt.size())
84  {
85  std::ostringstream error_message;
86  error_message << "Sizes of vector of boundary ids in bulk mesh ("
87  << boundary_in_bulk_mesh.size()
88  << ") and vector of pointers\n"
89  << "to FaceElements (" << face_mesh_pt.size()
90  << " doesn't match.\n";
91  throw OomphLibError(
92  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
93  }
94 #endif
95 
96  // Create face meshes adjacent to the bulk mesh's b-th boundary.
97  // Each face mesh consists of FaceElements that may also be
98  // interpreted as GeomObjects
99  Vector<Mesh*> bulk_face_mesh_pt(n_mesh);
100 
101  // Loop over all meshes
102  for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
103  {
104  bulk_face_mesh_pt[i_mesh] = new Mesh;
105  bulk_mesh_pt
106  ->template build_face_mesh<BULK_ELEMENT, FaceElementAsGeomObject>(
107  boundary_in_bulk_mesh[i_mesh], bulk_face_mesh_pt[i_mesh]);
108 
109  // Loop over these new face elements and tell them the boundary number
110  // from the bulk mesh -- this is required to they can
111  // get access to the boundary coordinates!
112  unsigned n_face_element = bulk_face_mesh_pt[i_mesh]->nelement();
113  for (unsigned e = 0; e < n_face_element; e++)
114  {
115  // Cast the element pointer to the correct thing!
116  FaceElementAsGeomObject<BULK_ELEMENT>* el_pt =
117  dynamic_cast<FaceElementAsGeomObject<BULK_ELEMENT>*>(
118  bulk_face_mesh_pt[i_mesh]->element_pt(e));
119 
120  // Set bulk boundary number
121  el_pt->set_boundary_number_in_bulk_mesh(boundary_in_bulk_mesh[i_mesh]);
122 
123  // Doc?
124  if (Doc_boundary_coordinate_file.is_open())
125  {
126  Vector<double> s(DIM - 1);
127  Vector<double> zeta(DIM - 1);
128  Vector<double> x(DIM);
129  unsigned n_plot = 5;
130  Doc_boundary_coordinate_file << el_pt->tecplot_zone_string(n_plot);
131 
132  // Loop over plot points
133  unsigned num_plot_points = el_pt->nplot_points(n_plot);
134  for (unsigned iplot = 0; iplot < num_plot_points; iplot++)
135  {
136  // Get local coordinates of plot point
137  el_pt->get_s_plot(iplot, n_plot, s);
138  el_pt->interpolated_zeta(s, zeta);
139  el_pt->interpolated_x(s, x);
140  for (unsigned i = 0; i < DIM; i++)
141  {
142  Doc_boundary_coordinate_file << x[i] << " ";
143  }
144  for (unsigned i = 0; i < DIM - 1; i++)
145  {
147  }
148  Doc_boundary_coordinate_file << std::endl;
149  }
150  el_pt->write_tecplot_zone_footer(Doc_boundary_coordinate_file,
151  n_plot);
152  }
153  }
154 
155  // Now sort the elements based on the boundary coordinates.
156  // This may allow a faster implementation of the locate_zeta
157  // function for the MeshAsGeomObject representation of this
158  // mesh, but also creates a unique ordering of the elements
159  std::sort(bulk_face_mesh_pt[i_mesh]->element_pt().begin(),
160  bulk_face_mesh_pt[i_mesh]->element_pt().end(),
161  CompareBoundaryCoordinate<BULK_ELEMENT>());
162  } // end of loop over meshes
163 
164 
165  // Setup the interactions for this problem using the surface mesh
166  // on the fluid mesh. The interaction parameter in this instance is
167  // given by the "face" parameter.
169  BULK_ELEMENT,
170  FaceElementAsGeomObject<BULK_ELEMENT>>(
171  problem_pt, face_mesh_pt, bulk_mesh_pt, bulk_face_mesh_pt, interaction);
172 
173 
174  // Loop over all meshes to clean up
175  for (unsigned i_mesh = 0; i_mesh < n_mesh; i_mesh++)
176  {
177  unsigned n_face_element = bulk_face_mesh_pt[i_mesh]->nelement();
178 
179  // The MeshAsGeomObject has already been deleted (in set_external_storage)
180 
181  // Must be careful with the FaceMesh, because we cannot delete the nodes
182  // Loop over the elements backwards (paranoid!) and delete them
183  for (unsigned e = n_face_element; e > 0; e--)
184  {
185  delete bulk_face_mesh_pt[i_mesh]->element_pt(e - 1);
186  bulk_face_mesh_pt[i_mesh]->element_pt(e - 1) = 0;
187  }
188  // Now clear all element and node storage (should maybe fine-grain this)
189  bulk_face_mesh_pt[i_mesh]->flush_element_and_node_storage();
190 
191  // Finally delete the mesh
192  delete bulk_face_mesh_pt[i_mesh];
193 
194  } // end of loop over meshes
195  }
static constexpr lastp1_t end
Definition: IndexedViewHelper.h:79
#define DIM
Definition: linearised_navier_stokes_elements.h:44
std::ofstream Doc_boundary_coordinate_file
Definition: multi_domain.cc:47
void setup_multi_domain_interaction(Problem *problem_pt, Mesh *const &mesh_pt, Mesh *const &external_mesh_pt, const unsigned &interaction_index=0)
Definition: multi_domain.template.cc:280

References DIM, Doc_boundary_coordinate_file, e(), Eigen::placeholders::end, oomph::FiniteElement::get_s_plot(), i, oomph::FaceElement::interpolated_x(), oomph::FiniteElement::interpolated_zeta(), oomph::FiniteElement::nplot_points(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, s, oomph::FaceElement::set_boundary_number_in_bulk_mesh(), setup_multi_domain_interaction(), oomph::FiniteElement::tecplot_zone_string(), oomph::FiniteElement::write_tecplot_zone_footer(), plotDoE::x, and Eigen::zeta().

Referenced by oomph::FSI_functions::setup_fluid_load_info_for_solid_elements(), PressureWaveFSIProblem< FLUID_ELEMENT, SOLID_ELEMENT >::setup_fsi(), CoatedDiskProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >::setup_interaction(), CoatedSphereProblem< ELASTICITY_ELEMENT, HELMHOLTZ_ELEMENT >::setup_interaction(), and oomph::FSI_functions::setup_solid_elements_for_displacement_bc().

◆ setup_multi_domain_interaction() [1/3]

template<class EXT_ELEMENT , class FACE_ELEMENT_GEOM_OBJECT >
void oomph::Multi_domain_functions::setup_multi_domain_interaction ( Problem problem_pt,
const Vector< Mesh * > &  mesh_pt,
Mesh *const &  external_mesh_pt,
const Vector< Mesh * > &  external_face_mesh_pt,
const unsigned interaction_index = 0 
)

Function to set up the one-way multi-domain interaction for FSI-like problems.

  • mesh_pt points to the mesh of ElemenWithExternalElements for which the interaction is set up. In an FSI example, this mesh would contain the FSIWallElements (either beam/shell elements or the FSISolidTractionElements that apply the traction to a "bulk" solid mesh that is loaded by the fluid.)
  • external_mesh_pt points to the mesh that contains the elements of type EXT_ELEMENT that provide the "source" for the ElementWithExternalElements. In an FSI example, this mesh would contain the "bulk" fluid elements.
  • external_face_mesh_pt points to the mesh of FaceElements attached to the external_mesh_pt. The mesh pointed to by external_face_mesh_pt has the same dimension as mesh_pt. The elements contained in external_face_mesh_pt are of type FACE_ELEMENT_GEOM_OBJECT. In an FSI example, these elements are usually the FaceElementAsGeomObjects (templated by the type of the "bulk" fluid elements to which they are attached) that define the FSI boundary of the fluid domain.
  • The interaction_index parameter defaults to zero and must otherwise be set by the user if there is more than one mesh that provides "external elements" for the Mesh pointed to by mesh_pt (e.g. in the case when a beam or shell structure is loaded by fluid from both sides.)

This is the vector-based version which operates simultaneously on the meshes contained in the Vector arguments.

Function to set up the one-way multi-domain interaction for FSI-like problems.

  • mesh_pt points to the mesh of ElemenWithExternalElements for which the interaction is set up. In an FSI example, this mesh would contain the FSIWallElements (either beam/shell elements or the FSISolidTractionElements that apply the traction to a "bulk" solid mesh that is loaded by the fluid.)
  • external_mesh_pt points to the mesh that contains the elements of type EXT_ELEMENT that provide the "source" for the ElementWithExternalElements. In an FSI example, this mesh would contain the "bulk" fluid elements.
  • external_face_mesh_pt points to the mesh of FaceElements attached to the external_mesh_pt. The mesh pointed to by external_face_mesh_pt has the same dimension as mesh_pt. The elements contained in external_face_mesh_pt are of type FACE_ELEMENT_GEOM_OBJECT. In an FSI example, these elements are usually the FaceElementAsGeomObjects (templated by the type of the "bulk" fluid elements to which they are attached) that define the FSI boundary of the fluid domain.
  • The interaction_index parameter defaults to zero and must otherwise be set by the user if there is more than one mesh that provides "external elements" for the Mesh pointed to by mesh_pt (e.g. in the case when a beam or shell structure is loaded by fluid from both sides.)

Vector-based version operates simultaneously on the meshes contained in the vectors.

406  {
407  // How many meshes do we have?
408  unsigned n_mesh = mesh_pt.size();
409 
410 #ifdef PARANOID
411  if (external_face_mesh_pt.size() != n_mesh)
412  {
413  std::ostringstream error_stream;
414  error_stream << "Sizes of external_face_mesh_pt [ "
415  << external_face_mesh_pt.size() << " ] and "
416  << "mesh_pt [ " << n_mesh << " ] don't match.\n";
417  throw OomphLibError(
418  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
419  }
420 #endif
421 
422  // Bail out?
423  if (n_mesh == 0) return;
424 
425  // Bulk elements must be external elements in this case
427 
428  // Call the auxiliary routine with GEOM_OBJECT=FACE_ELEMENT_GEOM_OBJECT
429  // and EL_DIM_LAG=Dim, EL_DIM_EUL=Dim+1. Use first mesh only.
430  get_dim_helper(problem_pt, mesh_pt[0], external_face_mesh_pt[0]);
431 
432 
433 #ifdef PARANOID
434  // Check consitency
435  unsigned old_dim = Dim;
436  for (unsigned i = 1; i < n_mesh; i++)
437  {
438  // Set up Dim again
439  get_dim_helper(problem_pt, mesh_pt[i], external_face_mesh_pt[i]);
440 
441  if (Dim != old_dim)
442  {
443  std::ostringstream error_stream;
444  error_stream << "Inconsistency: Mesh " << i << " has Dim=" << Dim
445  << "while mesh 0 has Dim=" << old_dim << std::endl;
446  throw OomphLibError(
447  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
448  }
449  }
450 #endif
451 
452  if (Dim > 2)
453  {
454  std::ostringstream error_stream;
455  error_stream << "The elements within the two interacting meshes have a\n"
456  << "dimension not equal to 1 or 2.\n"
457  << "The multi-domain method will not work in this case.\n"
458  << "The dimension is: " << Dim << "\n";
459  throw OomphLibError(
460  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
461  }
462 
463  // Now do the actual work for all meshes simultaneously
464  aux_setup_multi_domain_interaction<EXT_ELEMENT, FACE_ELEMENT_GEOM_OBJECT>(
465  problem_pt,
466  mesh_pt,
467  external_mesh_pt,
468  interaction_index,
469  external_face_mesh_pt);
470  }
void get_dim_helper(Problem *problem_pt, Mesh *const &mesh_pt, Mesh *const &external_mesh_pt)
Definition: multi_domain.cc:2343

References Global_Variables::Dim, get_dim_helper(), i, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and Use_bulk_element_as_external.

◆ setup_multi_domain_interaction() [2/3]

template<class EXT_ELEMENT >
void oomph::Multi_domain_functions::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 mesh_pt and external_mesh_pt occupy the same physical space, and the elements in external_mesh_pt act as "external elements" for the ElementWithExternalElements in mesh_pt (but not vice versa):

  • mesh_pt points to the mesh of ElemenWithExternalElements for which the interaction is set up.
  • external_mesh_pt points to the mesh that contains the elements of type EXT_ELEMENT that act as "external elements" for the ElementWithExternalElements in \ mesh_pt.
  • The interaction_index parameter defaults to zero and must be otherwise set by the user if there is more than one mesh that provides sources for the Mesh pointed to by mesh_pt.

Function to set up the one-way multi-domain interaction for problems where the meshes pointed to by mesh_pt and external_mesh_pt occupy the same physical space, and the elements in external_mesh_pt act as "external elements" for the ElementWithExternalElements in mesh_pt (but not vice versa):

  • mesh_pt points to the mesh of ElemenWithExternalElements for which the interaction is set up.
  • external_mesh_pt points to the mesh that contains the elements of type EXT_ELEMENT that act as "external elements" for the ElementWithExternalElements in mesh_pt.
  • The interaction_index parameter defaults to zero and must be otherwise set by the user if there is more than one mesh that provides sources for the Mesh pointed to by mesh_pt.
285  {
286  // Bulk elements must not be external elements in this case
288 
289  // Call the auxiliary function with GEOM_OBJECT=EXT_ELEMENT
290  // and EL_DIM_EUL=EL_DIM_LAG=dimension returned from helper function
291  get_dim_helper(problem_pt, mesh_pt, external_mesh_pt);
292 
293  if (Dim > 3)
294  {
295  std::ostringstream error_stream;
296  error_stream << "The elements within the two interacting meshes have a\n"
297  << "dimension not equal to 1, 2 or 3.\n"
298  << "The multi-domain method will not work in this case.\n"
299  << "The dimension is: " << Dim << "\n";
300  throw OomphLibError(
301  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
302  }
303 
304  // Wrapper for each dimension (template parameter)
305  aux_setup_multi_domain_interaction<EXT_ELEMENT, EXT_ELEMENT>(
306  problem_pt, mesh_pt, external_mesh_pt, interaction_index);
307  }

References Global_Variables::Dim, get_dim_helper(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and Use_bulk_element_as_external.

Referenced by MortaringValidationProblem< ELEMENT, NON_MORTAR_ELEMENT >::actions_after_adapt(), oomph::RefineableTetgenMesh< ELEMENT >::adapt(), ContactProblem< ELEMENT >::complete_problem_setup(), MortaringValidationProblem< ELEMENT, NON_MORTAR_ELEMENT >::MortaringValidationProblem(), oomph::ProjectionProblem< PROJECTABLE_ELEMENT >::project(), and setup_bulk_elements_adjacent_to_face_mesh().

◆ setup_multi_domain_interaction() [3/3]

template<class EXT_ELEMENT , class FACE_ELEMENT_GEOM_OBJECT >
void oomph::Multi_domain_functions::setup_multi_domain_interaction ( Problem problem_pt,
Mesh *const &  mesh_pt,
Mesh *const &  external_mesh_pt,
Mesh *const &  external_face_mesh_pt,
const unsigned interaction_index = 0 
)

Function to set up the one-way multi-domain interaction for FSI-like problems.

  • mesh_pt points to the mesh of ElemenWithExternalElements for which the interaction is set up. In an FSI example, this mesh would contain the FSIWallElements (either beam/shell elements or the FSISolidTractionElements that apply the traction to a "bulk" solid mesh that is loaded by the fluid.)
  • external_mesh_pt points to the mesh that contains the elements of type EXT_ELEMENT that provide the "source" for the ElementWithExternalElements. In an FSI example, this mesh would contain the "bulk" fluid elements.
  • external_face_mesh_pt points to the mesh of FaceElements attached to the external_mesh_pt. The mesh pointed to by external_face_mesh_pt has the same dimension as mesh_pt. The elements contained in external_face_mesh_pt are of type FACE_ELEMENT_GEOM_OBJECT. In an FSI example, these elements are usually the FaceElementAsGeomObjects (templated by the type of the "bulk" fluid elements to which they are attached) that define the FSI boundary of the fluid domain.
  • The interaction_index parameter defaults to zero and must otherwise be set by the user if there is more than one mesh that provides "external elements" for the Mesh pointed to by mesh_pt (e.g. in the case when a beam or shell structure is loaded by fluid from both sides.)
342  {
343  // Bulk elements must be external elements in this case
345 
346  // Call the auxiliary routine with GEOM_OBJECT=FACE_ELEMENT_GEOM_OBJECT
347  // and EL_DIM_LAG=Dim, EL_DIM_EUL=Dim+1
348  get_dim_helper(problem_pt, mesh_pt, external_face_mesh_pt);
349 
350  if (Dim > 2)
351  {
352  std::ostringstream error_stream;
353  error_stream << "The elements within the two interacting meshes have a\n"
354  << "dimension not equal to 1 or 2.\n"
355  << "The multi-domain method will not work in this case.\n"
356  << "The dimension is: " << Dim << "\n";
357  throw OomphLibError(
358  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
359  }
360 
361  // Call the function that actually does the work
362  aux_setup_multi_domain_interaction<EXT_ELEMENT, FACE_ELEMENT_GEOM_OBJECT>(
363  problem_pt,
364  mesh_pt,
365  external_mesh_pt,
366  interaction_index,
367  external_face_mesh_pt);
368  }

References Global_Variables::Dim, get_dim_helper(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION, and Use_bulk_element_as_external.

◆ setup_multi_domain_interactions()

template<class ELEMENT_0 , class ELEMENT_1 >
void oomph::Multi_domain_functions::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're setting up in the two meshes. They default to zero, which is appropriate if there's only a single interaction.

250  {
251  // Delete all the current external halo(ed) element and node storage
252  first_mesh_pt->delete_all_external_storage();
253  second_mesh_pt->delete_all_external_storage();
254 
255  // Call setup_multi_domain_interaction in both directions
256  setup_multi_domain_interaction<ELEMENT_1>(
257  problem_pt, first_mesh_pt, second_mesh_pt, first_interaction);
258 
259  setup_multi_domain_interaction<ELEMENT_0>(
260  problem_pt, second_mesh_pt, first_mesh_pt, second_interaction);
261  }

References oomph::Mesh::delete_all_external_storage().

Referenced by RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >::actions_after_adapt(), RefineableDDConvectionProblem< NST_ELEMENT, AD_ELEMENT >::actions_after_adapt(), ConvectionProblem< NST_ELEMENT, AD_ELEMENT >::actions_after_distribute(), RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >::actions_after_distribute(), and DDConvectionProblem< NST_ELEMENT, AD_ELEMENT >::DDConvectionProblem().

Variable Documentation

◆ Accept_failed_locate_zeta_in_setup_multi_domain_interaction

bool oomph::Multi_domain_functions::Accept_failed_locate_zeta_in_setup_multi_domain_interaction = false

Boolean to indicate that failure in setup multi domain functions is acceptable; defaults to false. If set to true external element pointers are set to null for those elements for which external elements couldn't be located.

Referenced by aux_setup_multi_domain_interaction(), MortaringHelpers::setup_constraint_elements_at_nodes(), and MortaringValidationProblem< ELEMENT, NON_MORTAR_ELEMENT >::setup_multi_domain_interaction().

◆ Allow_use_of_halo_elements_as_external_elements

bool oomph::Multi_domain_functions::Allow_use_of_halo_elements_as_external_elements = true

Boolean to indicate if we're allowed to use halo elements as external elements. Can drastically reduce the number of external halo elements – currently not aware of any problems therefore set to true by default but retention of this flag allows easy return to previous implementation.

Referenced by locate_zeta_for_local_coordinates().

◆ Allow_use_of_halo_elements_as_external_elements_for_projection

bool oomph::Multi_domain_functions::Allow_use_of_halo_elements_as_external_elements_for_projection = true

Indicate whether we are allowed to use halo elements as external elements for projection, possibly only required in parallel unstructured mesh generation during the projection stage. Default set to true

◆ Counter_for_flat_packed_doubles

unsigned oomph::Multi_domain_functions::Counter_for_flat_packed_doubles

Counter used when processing vector of flat-packed doubles – this is really "private" data, declared here to avoid having to pass it (and the associated array) between the various helper functions

◆ Counter_for_flat_packed_unsigneds

unsigned oomph::Multi_domain_functions::Counter_for_flat_packed_unsigneds

Counter used when processing vector of flat-packed unsigneds – this is really "private" data, declared here to avoid having to pass it (and the associated array) between the various helper functions

◆ Dim

unsigned oomph::Multi_domain_functions::Dim

Dimension of zeta tuples (set by get_dim_helper) – needed because we store the scalar coordinates in flat-packed form.

Referenced by first_closer_than_second(), get_dim_helper(), and locate_zeta_for_local_coordinates().

◆ Doc_boundary_coordinate_file

std::ofstream oomph::Multi_domain_functions::Doc_boundary_coordinate_file

Output file to document the boundary coordinate along the mesh boundary of the bulk mesh during call to setup_bulk_elements_adjacent_to_face_mesh(...)

Referenced by PseudoElasticCollapsibleChannelProblem< FLUID_ELEMENT, SOLID_ELEMENT >::PseudoElasticCollapsibleChannelProblem(), setup_bulk_elements_adjacent_to_face_mesh(), and UnstructuredFSIProblem< FLUID_ELEMENT, SOLID_ELEMENT >::UnstructuredFSIProblem().

◆ Doc_full_stats

bool oomph::Multi_domain_functions::Doc_full_stats = false

Boolean to indicate whether to output further info during setup_multi_domain_interaction() routines

Boolean to indicate whether to document further info (to screen) during setup_multi_domain_interaction() routines

◆ Doc_stats

bool oomph::Multi_domain_functions::Doc_stats = false

Boolean to indicate whether to output basic info during setup_multi_domain_interaction() routines

Boolean to indicate whether to document basic info (to screen) during setup_multi_domain_interaction() routines

Referenced by RefineableConvectionProblem< NST_ELEMENT, AD_ELEMENT >::RefineableConvectionProblem().

◆ Doc_timings

bool oomph::Multi_domain_functions::Doc_timings = false

Boolean to indicate whether to doc timings or not.

◆ External_element_located

Vector< Vector< unsigned > > oomph::Multi_domain_functions::External_element_located

Lookup scheme for whether a local element's integration point has had an external element assigned to it – essentially boolean. External_element_located[e][ipt] = {0,1} if external element for ipt-th integration in local element e {has not, has} been found. Used locally to ensure that we're not searching for the same elements over and over again when we go around the spirals.

Referenced by aux_setup_multi_domain_interaction(), clean_up(), and locate_zeta_for_local_coordinates().

◆ Flat_packed_doubles

Vector< double > oomph::Multi_domain_functions::Flat_packed_doubles

Vector of flat-packed doubles to be communicated with other processors

Referenced by clean_up().

◆ Flat_packed_located_coordinates

Vector< double > oomph::Multi_domain_functions::Flat_packed_located_coordinates

Vector of flat-packed local coordinates for zeta tuples that have been located

Referenced by clean_up().

◆ Flat_packed_unsigneds

Vector< unsigned > oomph::Multi_domain_functions::Flat_packed_unsigneds

Vector of flat-packed unsigneds to be communicated with other processors – this is really "private" data, declared here to avoid having to pass the array between the various helper functions

Referenced by clean_up().

◆ Flat_packed_zetas_not_found_locally

Vector< double > oomph::Multi_domain_functions::Flat_packed_zetas_not_found_locally

Vector of flat-packed zeta coordinates for which the external element could not be found during current local search. These will be sent to the next processor in the ring-like parallel search. The zeta coordinates come in groups of Dim (scalar) coordinates.

Referenced by aux_setup_multi_domain_interaction(), clean_up(), and locate_zeta_for_local_coordinates().

◆ Located_element_status

Vector< unsigned > oomph::Multi_domain_functions::Located_element_status

Vector to indicate (to another processor) whether a located element (that will have to represented as an external halo element on that processor) should be newly created on that processor (2), already exists on that processor (1), or is not on the current processor either (0).

Referenced by clean_up().

◆ Proc_id_plus_one_of_external_element

Vector< int > oomph::Multi_domain_functions::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 which the i-th zeta coordinate tuple received from elsewhere (in the order in which these are stored in Received_flat_packed_zetas_to_be_found) was located; it's zero if it wasn't found during the current stage of the ring-like parallel search.

Referenced by clean_up().

◆ Received_flat_packed_zetas_to_be_found

Vector< double > oomph::Multi_domain_functions::Received_flat_packed_zetas_to_be_found

Vector of flat-packed zeta coordinates for which the external element could not be found on another processor and for which we're currently searching here. Whatever can't be found here, gets written into Flat_packed_zetas_not_found_locally and then passed on to the next processor during the ring-like parallel search. The zeta coordinates come in groups of Dim (scalar) coordinates.

Referenced by clean_up().

◆ Use_bulk_element_as_external

bool oomph::Multi_domain_functions::Use_bulk_element_as_external = false

Boolean to indicate when to use the bulk element as the external element. Defaults to false, you must have set up FaceElements properly first in order for it to work

Referenced by aux_setup_multi_domain_interaction(), locate_zeta_for_local_coordinates(), and setup_multi_domain_interaction().

◆ Zeta_coords_for_further_away_comparison

Vector<double> oomph::Multi_domain_functions::Zeta_coords_for_further_away_comparison

Vector of zeta coordinates that we're currently trying to locate; used in sorting of bin entries in further_away() comparison function

Referenced by first_closer_than_second().