mesh.h
Go to the documentation of this file.
1 // LIC// ====================================================================
2 // LIC// This file forms part of oomph-lib, the object-oriented,
3 // LIC// multi-physics finite-element library, available
4 // LIC// at http://www.oomph-lib.org.
5 // LIC//
6 // LIC// Copyright (C) 2006-2022 Matthias Heil and Andrew Hazel
7 // LIC//
8 // LIC// This library is free software; you can redistribute it and/or
9 // LIC// modify it under the terms of the GNU Lesser General Public
10 // LIC// License as published by the Free Software Foundation; either
11 // LIC// version 2.1 of the License, or (at your option) any later version.
12 // LIC//
13 // LIC// This library is distributed in the hope that it will be useful,
14 // LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // LIC// Lesser General Public License for more details.
17 // LIC//
18 // LIC// You should have received a copy of the GNU Lesser General Public
19 // LIC// License along with this library; if not, write to the Free Software
20 // LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 // LIC// 02110-1301 USA.
22 // LIC//
23 // LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24 // LIC//
25 // LIC//====================================================================
26 // Header file for general mesh classes
27 
28 // Include guards to prevent multiple inclusion of the header
29 #ifndef OOMPH_GENERIC_MESH_HEADER
30 #define OOMPH_GENERIC_MESH_HEADER
31 
32 // Config header generated by autoconfig
33 #ifdef HAVE_CONFIG_H
34 #include <oomph-lib-config.h>
35 #endif
36 
37 #ifdef OOMPH_HAS_MPI
38 #include "mpi.h"
39 #endif
40 
41 #include <float.h>
42 #include <list>
43 #include <typeinfo>
44 #include <string>
45 
46 // oomph-lib headers
47 #include "Vector.h"
48 #include "nodes.h"
49 #include "elements.h"
50 #include "timesteppers.h"
52 #include "matrices.h"
53 #include "refineable_elements.h"
54 
55 namespace oomph
56 {
57  //=================================================================
65  //=================================================================
66  class Mesh
67  {
68  public:
70  friend class Problem;
71 
72 
76 
77 
78  protected:
84 
88 
92 
96 
97 #ifdef OOMPH_HAS_MPI
98 
100  std::map<unsigned, Vector<GeneralisedElement*>> Root_halo_element_pt;
101 
103  std::map<unsigned, Vector<GeneralisedElement*>> Root_haloed_element_pt;
104 
106  std::map<unsigned, Vector<Node*>> Halo_node_pt;
107 
109  std::map<unsigned, Vector<Node*>> Haloed_node_pt;
110 
116  std::map<unsigned, Vector<Node*>> Shared_node_pt;
117 
119  OomphCommunicator* Comm_pt;
120 
124 
126  std::map<unsigned, Vector<GeneralisedElement*>> External_halo_element_pt;
127 
129  std::map<unsigned, Vector<GeneralisedElement*>> External_haloed_element_pt;
130 
131 
132  // External halo(ed) nodes are on the external halo(ed) elements
133 
135  std::map<unsigned, Vector<Node*>> External_halo_node_pt;
136 
138  std::map<unsigned, Vector<Node*>> External_haloed_node_pt;
139 
141  bool Keep_all_elements_as_halos;
142 
144  bool Resize_halo_nodes_not_required;
145 
147  void setup_shared_node_scheme();
148 
149 #endif
150 
154  unsigned long assign_global_eqn_numbers(Vector<double*>& Dof_pt);
155 
164  void describe_dofs(std::ostream& out,
165  const std::string& current_string) const;
166 
175  void describe_local_dofs(std::ostream& out,
176  const std::string& current_string) const;
177 
180  void assign_local_eqn_numbers(const bool& store_local_dof_pt);
181 
184 
187 
190  std::vector<bool> Boundary_coordinate_exists;
191 
200 
202 
203 
204  public:
205 #ifdef OOMPH_HAS_MPI
206 
207 
216  void resize_halo_nodes();
217 
218 #endif
219 
220 
224  const Vector<double>& x, Vector<double>& soln);
225 
229  const double& time, const Vector<double>& x, Vector<double>& soln);
230 
234 
237  {
238  // Lookup scheme hasn't been setup yet
240 #ifdef OOMPH_HAS_MPI
241  // Set defaults for distributed meshes
242 
243  // Mesh hasn't been distributed: Null out pointer to communicator
244  Comm_pt = 0;
245  // Don't keep all objects as halos
246  Keep_all_elements_as_halos = false;
247  // Don't output halo elements
248  Output_halo_elements = false;
249  // Don't suppress automatic resizing of halo nodes
250  Resize_halo_nodes_not_required = false;
251 #endif
252  }
253 
257  Mesh(const Vector<Mesh*>& sub_mesh_pt)
258  {
259 #ifdef OOMPH_HAS_MPI
260  // Mesh hasn't been distributed: Null out pointer to communicator
261  Comm_pt = 0;
262 #endif
263  // Now merge the meshes
264  merge_meshes(sub_mesh_pt);
265  }
266 
270  void merge_meshes(const Vector<Mesh*>& sub_mesh_pt);
271 
275  virtual void setup_boundary_element_info() {}
276 
281  virtual void setup_boundary_element_info(std::ostream& outfile) {}
282 
285  Vector<unsigned>& ntmp_boundary_elements,
286  Vector<Vector<unsigned>>& ntmp_boundary_elements_in_region,
287  Vector<FiniteElement*>& deleted_elements)
288  {
289  std::ostringstream error_stream;
290  error_stream << "Empty default reset boundary element info function"
291  << "called.\n";
292  error_stream << "This should be overloaded in a specific "
293  << "TriangleMeshBase\n";
294  throw OomphLibError(error_stream.str(),
295  "Mesh::reset_boundary_element_info()",
297  }
298 
302  template<class BULK_ELEMENT>
303  void doc_boundary_coordinates(const unsigned& b, std::ofstream& the_file)
304  {
305  if (nelement() == 0) return;
307  {
308  oomph_info << "No boundary coordinates were set up for boundary " << b
309  << std::endl;
310  return;
311  }
312 
313  // Get spatial dimension
314  unsigned dim = finite_element_pt(0)->node_pt(0)->ndim();
315 
316  // Loop over all elements on boundaries
317  unsigned nel = this->nboundary_element(b);
318 
319  // Loop over the bulk elements adjacent to boundary b
320  for (unsigned e = 0; e < nel; e++)
321  {
322  // Get pointer to the bulk element that is adjacent to boundary b
323  FiniteElement* bulk_elem_pt = this->boundary_element_pt(b, e);
324 
325  // Find the index of the face of element e along boundary b
326  int face_index = this->face_index_at_boundary(b, e);
327 
328  // Create new face element
330  new DummyFaceElement<BULK_ELEMENT>(bulk_elem_pt, face_index);
331 
332  // Specify boundary id in bulk mesh (needed to extract
333  // boundary coordinate)
335 
336  // Doc boundary coordinate
337  Vector<double> s(dim - 1);
338  Vector<double> zeta(dim - 1);
339  Vector<double> x(dim);
340  unsigned n_plot = 5;
341  the_file << el_pt->tecplot_zone_string(n_plot);
342 
343  // Loop over plot points
344  unsigned num_plot_points = el_pt->nplot_points(n_plot);
345  for (unsigned iplot = 0; iplot < num_plot_points; iplot++)
346  {
347  // Get local coordinates of plot point
348  el_pt->get_s_plot(iplot, n_plot, s);
349  el_pt->interpolated_zeta(s, zeta);
350  el_pt->interpolated_x(s, x);
351  for (unsigned i = 0; i < dim; i++)
352  {
353  the_file << x[i] << " ";
354  }
355  for (unsigned i = 0; i < (dim - 1); i++)
356  {
357  the_file << zeta[i] << " ";
358  }
359 
360  the_file << std::endl;
361  }
362  el_pt->write_tecplot_zone_footer(the_file, n_plot);
363 
364  // Cleanup
365  delete el_pt;
366  }
367  }
368 
369 
373  virtual void scale_mesh(const double& factor)
374  {
375  unsigned nnod = this->nnode();
376  unsigned dim = this->node_pt(0)->ndim();
377  for (unsigned j = 0; j < nnod; j++)
378  {
379  Node* nod_pt = this->node_pt(j);
380  for (unsigned i = 0; i < dim; i++)
381  {
382  nod_pt->x(i) *= factor;
383  }
384  }
385  }
386 
388  Mesh(const Mesh& dummy) = delete;
389 
391  void operator=(const Mesh&) = delete;
392 
394  virtual ~Mesh();
395 
396 
408  {
411  }
412 
424  {
425  Element_pt.clear();
426  }
427 
431  {
432  Node_pt.clear();
433  }
434 
436  Node*& node_pt(const unsigned long& n)
437  {
438  return Node_pt[n];
439  }
440 
442  Node* node_pt(const unsigned long& n) const
443  {
444  return Node_pt[n];
445  }
446 
448  GeneralisedElement*& element_pt(const unsigned long& e)
449  {
450  return Element_pt[e];
451  }
452 
454  GeneralisedElement* element_pt(const unsigned long& e) const
455  {
456  return Element_pt[e];
457  }
458 
461  {
462  return Element_pt;
463  }
464 
467  {
468  return Element_pt;
469  }
470 
473  FiniteElement* finite_element_pt(const unsigned& e) const
474  {
475 #ifdef PARANOID
476  FiniteElement* el_pt = dynamic_cast<FiniteElement*>(Element_pt[e]);
477  if (el_pt == 0)
478  {
479  // Error
480  throw OomphLibError("Failed cast to FiniteElement* ",
483  // Dummy return to keep intel compiler happy
484  return el_pt;
485  }
486  return el_pt;
487 #else
488  return dynamic_cast<FiniteElement*>(Element_pt[e]);
489 #endif
490  }
491 
493  Node*& boundary_node_pt(const unsigned& b, const unsigned& n)
494  {
495  return Boundary_node_pt[b][n];
496  }
497 
499  Node* boundary_node_pt(const unsigned& b, const unsigned& n) const
500  {
501  return Boundary_node_pt[b][n];
502  }
503 
505  void set_nboundary(const unsigned& nbound)
506  {
507  Boundary_node_pt.resize(nbound);
508  Boundary_coordinate_exists.resize(nbound, false);
509  }
510 
512  void remove_boundary_nodes();
513 
516  void remove_boundary_nodes(const unsigned& b);
517 
519  void remove_boundary_node(const unsigned& b, Node* const& node_pt);
520 
522  void add_boundary_node(const unsigned& b, Node* const& node_pt);
523 
527  {
528  // Clear existing boundary data
529  Boundary_node_pt.clear();
530 
531  // Loop over nodes adding them to the appropriate boundary lookup schemes
532  // in the mesh.
533  const unsigned n_node = nnode();
534  for (unsigned nd = 0; nd < n_node; nd++)
535  {
536  Node* nd_pt = node_pt(nd);
537 
538  if (nd_pt->is_on_boundary())
539  {
540  // Get set of boundaries that the node is on
541  std::set<unsigned>* boundaries_pt;
542  nd_pt->get_boundaries_pt(boundaries_pt);
543 
544  // If needed then add more boundaries to this mesh
545  unsigned max_boundary_n =
546  1 + *std::max_element(boundaries_pt->begin(), boundaries_pt->end());
547  if (max_boundary_n > nboundary())
548  {
549  set_nboundary(max_boundary_n);
550  }
551 
552  // Add node pointer to the appropriate Boundary_node_pt vectors
553  std::set<unsigned>::const_iterator it;
554  for (it = boundaries_pt->begin(); it != boundaries_pt->end(); it++)
555  {
556  Boundary_node_pt[*it].push_back(nd_pt);
557  }
558  }
559  }
560  }
561 
563  // By default, if the array Boundary_coordinate has not been resized,
564  // return false
565  bool boundary_coordinate_exists(const unsigned& i) const
566  {
567  if (Boundary_coordinate_exists.empty())
568  {
569  return false;
570  }
571  // ALH: This bounds-checking code needs to remain, because
572  // Boundary_coordinate_exists is
573  // an stl vector not our overloaded Vector class
574 #ifdef RANGE_CHECKING
575  if (i >= Boundary_coordinate_exists.size())
576  {
577  std::ostringstream error_message;
578  error_message << "Range Error: " << i << " is not in the range (0,"
579  << Boundary_coordinate_exists.size() - 1 << std::endl;
580 
581  throw OomphLibError(error_message.str(),
584  }
585 #endif
587  }
588 
590  unsigned long nelement() const
591  {
592  return Element_pt.size();
593  }
594 
596  unsigned long nnode() const
597  {
598  return Node_pt.size();
599  }
600 
602  unsigned ndof_types() const;
603 
605  unsigned elemental_dimension() const;
606 
608  unsigned nodal_dimension() const;
609 
611  void add_node_pt(Node* const& node_pt)
612  {
613  Node_pt.push_back(node_pt);
614  }
615 
618  {
619  Element_pt.push_back(element_pt);
620  }
621 
638  virtual void node_update(const bool& update_all_solid_nodes = false);
639 
642  virtual void reorder_nodes(const bool& use_old_ordering = true);
643 
647  virtual void get_node_reordering(Vector<Node*>& reordering,
648  const bool& use_old_ordering = true) const;
649 
652  template<class BULK_ELEMENT, template<class> class FACE_ELEMENT>
653  void build_face_mesh(const unsigned& b, Mesh* const& face_mesh_pt)
654  {
655  // Find the number of nodes on the boundary
656  unsigned nbound_node = nboundary_node(b);
657  // Loop over the boundary nodes and add them to face mesh node pointer
658  for (unsigned n = 0; n < nbound_node; n++)
659  {
660  face_mesh_pt->add_node_pt(boundary_node_pt(b, n));
661  }
662 
663  // Find the number of elements next to the boundary
664  unsigned nbound_element = nboundary_element(b);
665  // Loop over the elements adjacent to boundary b
666  for (unsigned e = 0; e < nbound_element; e++)
667  {
668  // Create the FaceElement
669  FACE_ELEMENT<BULK_ELEMENT>* face_element_pt =
670  new FACE_ELEMENT<BULK_ELEMENT>(boundary_element_pt(b, e),
672 
673  // Add the face element to the face mesh
674  face_mesh_pt->add_element_pt(face_element_pt);
675  }
676 
677 #ifdef OOMPH_HAS_MPI
678  // If the bulk mesh has been distributed then the face mesh is too
679  if (this->is_mesh_distributed())
680  {
681  face_mesh_pt->set_communicator_pt(this->communicator_pt());
682  }
683 #endif
684  }
685 
687  unsigned self_test();
688 
689 
692  void max_and_min_element_size(double& max_size, double& min_size)
693  {
694  max_size = 0.0;
695  min_size = DBL_MAX;
696  unsigned nel = nelement();
697  for (unsigned e = 0; e < nel; e++)
698  {
699  max_size = std::max(max_size, finite_element_pt(e)->size());
700  min_size = std::min(min_size, finite_element_pt(e)->size());
701  }
702  }
703 
704 
708  double total_size()
709  {
710  double size = 0.0;
711  unsigned nel = nelement();
712  for (unsigned e = 0; e < nel; e++)
713  {
715  if (fe_pt != 0)
716  {
717  size += fe_pt->size();
718  }
719  }
720  return size;
721  }
722 
723 
732  void check_inverted_elements(bool& mesh_has_inverted_elements,
733  std::ofstream& inverted_element_file);
734 
735 
742  void check_inverted_elements(bool& mesh_has_inverted_elements)
743  {
744  std::ofstream inverted_element_file;
745  check_inverted_elements(mesh_has_inverted_elements,
746  inverted_element_file);
747  }
748 
749 
752  unsigned check_for_repeated_nodes(const double& epsilon = 1.0e-12)
753  {
754  oomph_info << "\n\nStarting check for repeated nodes...";
755  bool failed = false;
756  unsigned nnod = nnode();
757  for (unsigned j = 0; j < nnod; j++)
758  {
759  Node* nod1_pt = this->node_pt(j);
760  unsigned dim = nod1_pt->ndim();
761  for (unsigned k = j + 1; k < nnod; k++)
762  {
763  Node* nod2_pt = this->node_pt(k);
764  double dist = 0.0;
765  for (unsigned i = 0; i < dim; i++)
766  {
767  dist += pow((nod1_pt->x(i) - nod2_pt->x(i)), 2);
768  }
769  dist = sqrt(dist);
770  if (dist < epsilon)
771  {
772  oomph_info << "\n\nRepeated node!" << std::endl;
773  oomph_info << "Distance between nodes " << j << " and " << k
774  << std::endl;
775  oomph_info << "is " << dist << " which is less than the"
776  << std::endl;
777  oomph_info << "permitted distance of " << epsilon << std::endl
778  << std::endl;
779  oomph_info << "The offending nodes are located at: " << std::endl;
780  for (unsigned i = 0; i < dim; i++)
781  {
782  oomph_info << nod1_pt->x(i) << " ";
783  }
784  if (nod1_pt->is_a_copy() || nod2_pt->is_a_copy())
785  {
786  oomph_info << "\n\n[NOTE: message issued as diagonistic rather "
787  "than an error\n"
788  << " because at least one of the nodes is a copy; you "
789  "may still\n"
790  << " want to check this out. BACKGROUND: Copied nodes "
791  "share the same Data but\n"
792  << " will, in general, have different spatial "
793  "positions (e.g. when used\n"
794  << " as periodic nodes); however there are cases when "
795  "they are located\n"
796  << " at the same spatial position (e.g. in "
797  "oomph-lib's annular mesh which\n"
798  << " is a rolled-around version of the rectangular "
799  "quadmesh). In such cases,\n"
800  << " the nodes could have been deleted and completely "
801  "replaced by \n"
802  << " pointers to existing nodes, but may have been "
803  "left there for convenience\n"
804  << " or out of laziness...]\n";
805  }
806  else
807  {
808  failed = true;
809  }
810  oomph_info << std::endl << std::endl;
811  }
812  }
813  }
814  if (failed) return 1;
815 
816  // If we made it to here, we must have passed the test.
817  oomph_info << "...done: Test passed!" << std::endl << std::endl;
818  return 0;
819  }
820 
825 
827  unsigned nboundary() const
828  {
829  return Boundary_node_pt.size();
830  }
831 
833  unsigned long nboundary_node(const unsigned& ibound) const
834  {
835  return Boundary_node_pt[ibound].size();
836  }
837 
838 
841  const unsigned& e) const
842  {
843 #ifdef PARANOID
845  {
846  throw OomphLibError("Lookup scheme for elements next to boundary "
847  "hasn't been set up yet!\n",
850  }
851 #endif
852  return Boundary_element_pt[b][e];
853  }
854 
855 
860  {
861  for (unsigned nd = 0, nnd = nnode(); nd < nnd; nd++)
862  {
863  if (!(node_pt(nd)->is_on_boundary()))
864  {
865  return node_pt(nd);
866  }
867  }
868 
869  std::ostringstream error_msg;
870  error_msg << "No non-boundary nodes in the mesh.";
871  throw OomphLibError(
873  // Never get here!
874  return 0;
875  }
876 
878  unsigned nboundary_element(const unsigned& b) const
879  {
880 #ifdef PARANOID
882  {
883  throw OomphLibError("Lookup scheme for elements next to boundary "
884  "hasn't been set up yet!\n",
887  }
888 #endif
889  return Boundary_element_pt[b].size();
890  }
891 
892 
896  int face_index_at_boundary(const unsigned& b, const unsigned& e) const
897  {
898 #ifdef PARANOID
900  {
901  throw OomphLibError("Lookup scheme for elements next to boundary "
902  "hasn't been set up yet!\n",
905  }
906 #endif
907  return Face_index_at_boundary[b][e];
908  }
909 
911  virtual void dump(std::ofstream& dump_file,
912  const bool& use_old_ordering = true) const;
913 
915  void dump(const std::string& dump_file_name,
916  const bool& use_old_ordering = true) const
917  {
918  std::ofstream dump_stream(dump_file_name.c_str());
919 #ifdef PARANOID
920  if (!dump_stream.is_open())
921  {
922  std::string err = "Couldn't open file " + dump_file_name;
923  throw OomphLibError(
925  }
926 #endif
927  dump(dump_stream, use_old_ordering);
928  }
929 
931  virtual void read(std::ifstream& restart_file);
932 
933 
939  void output_paraview(std::ofstream& file_out, const unsigned& nplot) const;
940 
946  void output_fct_paraview(
947  std::ofstream& file_out,
948  const unsigned& nplot,
949  FiniteElement::SteadyExactSolutionFctPt exact_soln_pt) const;
950 
956  void output_fct_paraview(
957  std::ofstream& file_out,
958  const unsigned& nplot,
959  const double& time,
960  FiniteElement::UnsteadyExactSolutionFctPt exact_soln_pt) const;
961 
963  void output(std::ostream& outfile);
964 
966  void output(std::ostream& outfile, const unsigned& n_plot);
967 
969  void output(FILE* file_pt);
970 
972  void output(FILE* file_pt, const unsigned& nplot);
973 
975  void output(const std::string& output_filename)
976  {
977  std::ofstream outfile;
978  outfile.open(output_filename.c_str());
979  output(outfile);
980  outfile.close();
981  }
982 
984  void output(const std::string& output_filename, const unsigned& n_plot)
985  {
986  std::ofstream outfile;
987  outfile.open(output_filename.c_str());
988  output(outfile, n_plot);
989  outfile.close();
990  }
991 
993  void output_fct(std::ostream& outfile,
994  const unsigned& n_plot,
996 
999  void output_fct(std::ostream& outfile,
1000  const unsigned& n_plot,
1001  const double& time,
1003 
1005  void output_boundaries(std::ostream& outfile);
1006 
1009  void output_boundaries(const std::string& output_filename)
1010  {
1011  std::ofstream outfile;
1012  outfile.open(output_filename.c_str());
1013  output_boundaries(outfile);
1014  outfile.close();
1015  }
1016 
1019 
1023  void shift_time_values();
1024 
1025 
1028  void calculate_predictions();
1029 
1033  TimeStepper* const& time_stepper_pt, const bool& preserve_existing_data)
1034  {
1035  this->set_nodal_time_stepper(time_stepper_pt, preserve_existing_data);
1036  this->set_elemental_internal_time_stepper(time_stepper_pt,
1037  preserve_existing_data);
1038  }
1039 
1044  virtual void set_mesh_level_time_stepper(
1045  TimeStepper* const& time_stepper_pt, const bool& preserve_existing_data);
1046 
1049  ContinuationStorageScheme* const& continuation_stepper_pt);
1050 
1052  bool does_pointer_correspond_to_mesh_data(double* const& parameter_pt);
1053 
1055  void set_nodal_time_stepper(TimeStepper* const& time_stepper_pt,
1056  const bool& preserve_existing_data);
1057 
1061  TimeStepper* const& time_stepper_pt, const bool& preserve_existing_data);
1062 
1068  virtual void compute_norm(double& norm)
1069  {
1070  // Initialse the norm
1071  norm = 0.0;
1072 
1073  // Per-element norm
1074  double el_norm = 0;
1075 
1076  // Loop over the elements
1077  unsigned long n_element = Element_pt.size();
1078  for (unsigned long e = 0; e < n_element; e++)
1079  {
1080  GeneralisedElement* el_pt = Element_pt[e];
1081 
1082 #ifdef OOMPH_HAS_MPI
1083  // Compute error for each non-halo element
1084  if (!(el_pt->is_halo()))
1085 #endif
1086  {
1087  el_pt->compute_norm(el_norm);
1088  }
1089  norm += el_norm;
1090  }
1091  }
1092 
1093 
1099  virtual void compute_norm(Vector<double>& norm)
1100  {
1101  // How many unknowns are there?
1102  unsigned n_entry = norm.size();
1103 
1104  // Initialse the norm
1105  norm.initialise(0.0);
1106 
1107  // Per-element norm
1108  Vector<double> el_norm(n_entry, 0.0);
1109 
1110  // How many elements are there?
1111  unsigned long n_element = Element_pt.size();
1112 
1113  // Loop over the elements
1114  for (unsigned long e = 0; e < n_element; e++)
1115  {
1116  // Get a pointer to the e-th generalised element
1117  GeneralisedElement* el_pt = Element_pt[e];
1118 
1119 #ifdef OOMPH_HAS_MPI
1120  // Compute error for each non-halo element
1121  if (!(el_pt->is_halo()))
1122 #endif
1123  {
1124  // Compute the elemental norm
1125  el_pt->compute_norm(el_norm);
1126  }
1127 
1128  // Loop over the norm vector entries
1129  for (unsigned i = 0; i < n_entry; i++)
1130  {
1131  // Update the norm of the i-th component
1132  norm[i] += el_norm[i];
1133  }
1134  } // for (unsigned long e=0;e<n_element;e++)
1135  } // End of compute_norm
1136 
1137 
1140  virtual void compute_error(
1141  std::ostream& outfile,
1143  const double& time,
1144  double& error,
1145  double& norm)
1146  {
1147  // Initialse the norm and error
1148  norm = 0.0;
1149  error = 0.0;
1150  // Per-element norm and error
1151  double el_error, el_norm;
1152 
1153  // Loop over the elements
1154  unsigned long Element_pt_range = Element_pt.size();
1155  for (unsigned long e = 0; e < Element_pt_range; e++)
1156  {
1157  // Try to cast to FiniteElement
1158  FiniteElement* el_pt = dynamic_cast<FiniteElement*>(Element_pt[e]);
1159  if (el_pt == 0)
1160  {
1161  throw OomphLibError(
1162  "Can't execute compute_error(...) for non FiniteElements",
1165  }
1166 
1167  // Reset elemental errors and norms
1168  el_norm = 0.0;
1169  el_error = 0.0;
1170 #ifdef OOMPH_HAS_MPI
1171  // Compute error for each non-halo element
1172  if (!(el_pt->is_halo()))
1173 #endif
1174  {
1175  el_pt->compute_error(outfile, exact_soln_pt, time, el_error, el_norm);
1176  }
1177  // Add each element error to the global errors
1178  norm += el_norm;
1179  error += el_error;
1180  }
1181  }
1182 
1186  virtual void compute_error(
1187  std::ostream& outfile,
1189  double& error,
1190  double& norm)
1191  {
1192  // Initialise norm and error
1193  norm = 0.0;
1194  error = 0.0;
1195  // Per-element norm and error
1196  double el_error, el_norm;
1197 
1198  // Loop over the elements
1199  unsigned long Element_pt_range = Element_pt.size();
1200  for (unsigned long e = 0; e < Element_pt_range; e++)
1201  {
1202  // Try to cast to FiniteElement
1203  FiniteElement* el_pt = dynamic_cast<FiniteElement*>(Element_pt[e]);
1204  if (el_pt == 0)
1205  {
1206  throw OomphLibError(
1207  "Can't execute compute_error(...) for non FiniteElements",
1210  }
1211  // Reset elemental errors and norms
1212  el_norm = 0.0;
1213  el_error = 0.0;
1214  // Calculate the elemental errors for each non-halo element
1215 #ifdef OOMPH_HAS_MPI
1216  if (!(el_pt->is_halo()))
1217 #endif
1218  {
1219  el_pt->compute_error(outfile, exact_soln_pt, el_error, el_norm);
1220  }
1221  // Add each elemental error to the global error
1222  norm += el_norm;
1223  error += el_error;
1224  }
1225  }
1226 
1227 
1231  virtual void compute_error(
1233  double& error,
1234  double& norm)
1235  {
1236  // Initialise norm and error
1237  norm = 0.0;
1238  error = 0.0;
1239 
1240  // Per-element norm and error
1241  double el_error, el_norm;
1242 
1243  // Loop over the elements
1244  unsigned long Element_pt_range = Element_pt.size();
1245  for (unsigned long e = 0; e < Element_pt_range; e++)
1246  {
1247  // Try to cast to FiniteElement
1248  FiniteElement* el_pt = dynamic_cast<FiniteElement*>(Element_pt[e]);
1249  if (el_pt == 0)
1250  {
1251  throw OomphLibError(
1252  "Can't execute compute_error(...) for non FiniteElements",
1255  }
1256 
1257  // Reset elemental errors and norms
1258  el_norm = 0.0;
1259  el_error = 0.0;
1260 
1261  // Calculate the elemental errors for each non-halo element
1262 #ifdef OOMPH_HAS_MPI
1263  if (!(el_pt->is_halo()))
1264 #endif
1265  {
1266  el_pt->compute_error(exact_soln_pt, el_error, el_norm);
1267  }
1268 
1269  // Add each elemental error to the global error
1270  norm += el_norm;
1271  error += el_error;
1272  }
1273  } // End of compute_error
1274 
1275 
1279  virtual void compute_error(
1282  Vector<double>& norm)
1283  {
1284  // Initialise norm vector entries
1285  norm.initialise(0.0);
1286 
1287  // Initialise error vector entries
1288  error.initialise(0.0);
1289 
1290  // Norm vector size
1291  unsigned n_norm = norm.size();
1292 
1293  // Error vector size
1294  unsigned n_error = error.size();
1295 
1296  // Per-element norm and error
1297  Vector<double> el_norm(n_norm, 0.0);
1298 
1299  // Per-element norm and error
1300  Vector<double> el_error(n_error, 0.0);
1301 
1302  // How many elements are there?
1303  unsigned long element_pt_range = Element_pt.size();
1304 
1305  // Loop over the elements
1306  for (unsigned long e = 0; e < element_pt_range; e++)
1307  {
1308  // Try to cast to FiniteElement
1309  FiniteElement* el_pt = dynamic_cast<FiniteElement*>(Element_pt[e]);
1310  if (el_pt == 0)
1311  {
1312  throw OomphLibError(
1313  "Can't execute compute_error(...) for non FiniteElements",
1316  }
1317 
1318  // Re-initialise norm vector entries
1319  el_norm.initialise(0.0);
1320 
1321  // Re-initialise error vector entries
1322  el_error.initialise(0.0);
1323 
1324  // Calculate the elemental errors for each non-halo element
1325 #ifdef OOMPH_HAS_MPI
1326  if (!(el_pt->is_halo()))
1327 #endif
1328  {
1329  el_pt->compute_error(exact_soln_pt, el_error, el_norm);
1330  }
1331 
1332  // Add each elemental norm contribution to the global norm
1333  for (unsigned i = 0; i < n_norm; i++)
1334  {
1335  norm[i] += el_norm[i];
1336  }
1337 
1338  // Add each elemental error contribution to the global error
1339  for (unsigned i = 0; i < n_error; i++)
1340  {
1341  error[i] += el_error[i];
1342  }
1343  } // for (unsigned long e=0;e<element_pt_range;e++)
1344  } // End of compute_error
1345 
1346 
1351  virtual void compute_error(
1352  std::ostream& outfile,
1354  const double& time,
1356  Vector<double>& norm)
1357  {
1358  // Initialise norm and error
1359  unsigned n_error = error.size();
1360  unsigned n_norm = norm.size();
1361  for (unsigned i = 0; i < n_error; i++)
1362  {
1363  error[i] = 0.0;
1364  }
1365  for (unsigned i = 0; i < n_norm; i++)
1366  {
1367  norm[i] = 0.0;
1368  }
1369  // Per-element norm and error
1370  Vector<double> el_error(n_error), el_norm(n_norm);
1371 
1372  // Loop over the elements
1373  unsigned long Element_pt_range = Element_pt.size();
1374  for (unsigned long e = 0; e < Element_pt_range; e++)
1375  {
1376  // Try to cast to FiniteElement
1377  FiniteElement* el_pt = dynamic_cast<FiniteElement*>(Element_pt[e]);
1378  if (el_pt == 0)
1379  {
1380  throw OomphLibError(
1381  "Can't execute compute_error(...) for non FiniteElements",
1384  }
1385  // Reset elemental errors and norms
1386  for (unsigned i = 0; i < n_error; i++)
1387  {
1388  el_error[i] = 0.0;
1389  }
1390  for (unsigned i = 0; i < n_norm; i++)
1391  {
1392  el_norm[i] = 0.0;
1393  }
1394  // Calculate the elemental errors for each non-halo element
1395 #ifdef OOMPH_HAS_MPI
1396  if (!(el_pt->is_halo()))
1397 #endif
1398  {
1399  el_pt->compute_error(outfile, exact_soln_pt, time, el_error, el_norm);
1400  }
1401  // Add each elemental error to the global error
1402  for (unsigned i = 0; i < n_error; i++)
1403  {
1404  error[i] += el_error[i];
1405  }
1406  for (unsigned i = 0; i < n_norm; i++)
1407  {
1408  norm[i] += el_norm[i];
1409  }
1410  }
1411  }
1412 
1417  virtual void compute_error(
1418  std::ostream& outfile,
1421  Vector<double>& norm)
1422  {
1423  // Initialise norm and error
1424  unsigned n_error = error.size();
1425  unsigned n_norm = norm.size();
1426  for (unsigned i = 0; i < n_error; i++)
1427  {
1428  error[i] = 0.0;
1429  }
1430  for (unsigned i = 0; i < n_norm; i++)
1431  {
1432  norm[i] = 0.0;
1433  }
1434  // Per-element norm and error
1435  Vector<double> el_error(n_error), el_norm(n_norm);
1436 
1437  // Loop over the elements
1438  unsigned long Element_pt_range = Element_pt.size();
1439  for (unsigned long e = 0; e < Element_pt_range; e++)
1440  {
1441  // Try to cast to FiniteElement
1442  FiniteElement* el_pt = dynamic_cast<FiniteElement*>(Element_pt[e]);
1443  if (el_pt == 0)
1444  {
1445  throw OomphLibError(
1446  "Can't execute compute_error(...) for non FiniteElements",
1449  }
1450  // Reset elemental errors and norms
1451  for (unsigned i = 0; i < n_error; i++)
1452  {
1453  el_error[i] = 0.0;
1454  }
1455  for (unsigned i = 0; i < n_norm; i++)
1456  {
1457  el_norm[i] = 0.0;
1458  }
1459  // Calculate the elemental errors for each non-halo element
1460 #ifdef OOMPH_HAS_MPI
1461  if (!(el_pt->is_halo()))
1462 #endif
1463  {
1464  el_pt->compute_error(outfile, exact_soln_pt, el_error, el_norm);
1465  }
1466  // Add each elemental error to the global error
1467  for (unsigned i = 0; i < n_error; i++)
1468  {
1469  error[i] += el_error[i];
1470  }
1471  for (unsigned i = 0; i < n_norm; i++)
1472  {
1473  norm[i] += el_norm[i];
1474  }
1475  }
1476  }
1477 
1479  virtual void compute_error(
1481  const double& time,
1482  double& error,
1483  double& norm)
1484  {
1485  // Initialse the norm and error
1486  norm = 0.0;
1487  error = 0.0;
1488  // Per-element norm and error
1489  double el_error, el_norm;
1490 
1491  // Loop over the elements
1492  unsigned long Element_pt_range = Element_pt.size();
1493  for (unsigned long e = 0; e < Element_pt_range; e++)
1494  {
1495  // Try to cast to FiniteElement
1496  FiniteElement* el_pt = dynamic_cast<FiniteElement*>(Element_pt[e]);
1497  if (el_pt == 0)
1498  {
1499  throw OomphLibError(
1500  "Can't execute compute_error(...) for non FiniteElements",
1503  }
1504 
1505  // Reset elemental errors and norms
1506  el_norm = 0.0;
1507  el_error = 0.0;
1508 #ifdef OOMPH_HAS_MPI
1509  // Compute error for each non-halo element
1510  if (!(el_pt->is_halo()))
1511 #endif
1512  {
1513  el_pt->compute_error(exact_soln_pt, time, el_error, el_norm);
1514  }
1515  // Add each element error to the global errors
1516  norm += el_norm;
1517  error += el_error;
1518  }
1519  }
1520 
1521 
1525  virtual void compute_error(
1527  const double& time,
1529  Vector<double>& norm)
1530  {
1531  // Initialise norm and error
1532  unsigned n_error = error.size();
1533  unsigned n_norm = norm.size();
1534  for (unsigned i = 0; i < n_error; i++)
1535  {
1536  error[i] = 0.0;
1537  }
1538  for (unsigned i = 0; i < n_norm; i++)
1539  {
1540  norm[i] = 0.0;
1541  }
1542  // Per-element norm and error
1543  Vector<double> el_error(n_error), el_norm(n_norm);
1544 
1545  // Loop over the elements
1546  unsigned long Element_pt_range = Element_pt.size();
1547  for (unsigned long e = 0; e < Element_pt_range; e++)
1548  {
1549  // Try to cast to FiniteElement
1550  FiniteElement* el_pt = dynamic_cast<FiniteElement*>(Element_pt[e]);
1551  if (el_pt == 0)
1552  {
1553  throw OomphLibError(
1554  "Can't execute compute_error(...) for non FiniteElements",
1557  }
1558  // Reset elemental errors and norms
1559  for (unsigned i = 0; i < n_error; i++)
1560  {
1561  el_error[i] = 0.0;
1562  }
1563  for (unsigned i = 0; i < n_norm; i++)
1564  {
1565  el_norm[i] = 0.0;
1566  }
1567  // Calculate the elemental errors for each non-halo element
1568 #ifdef OOMPH_HAS_MPI
1569  if (!(el_pt->is_halo()))
1570 #endif
1571  {
1572  el_pt->compute_error(exact_soln_pt, time, el_error, el_norm);
1573  }
1574  // Add each elemental error to the global error
1575  for (unsigned i = 0; i < n_error; i++)
1576  {
1577  error[i] += el_error[i];
1578  }
1579  for (unsigned i = 0; i < n_norm; i++)
1580  {
1581  norm[i] += el_norm[i];
1582  }
1583  } // for (unsigned long e=0;e<Element_pt_range;e++)
1584  } // End of compute_error
1585 
1586 
1588  bool is_mesh_distributed() const
1589  {
1590 #ifdef OOMPH_HAS_MPI
1591  return communicator_pt() != 0;
1592 #else
1593  // Can't be distributed without mpi
1594  return false;
1595 #endif
1596  }
1597 
1601  {
1602 #ifdef OOMPH_HAS_MPI
1603  return Comm_pt;
1604 #else
1605  return 0;
1606 #endif
1607  }
1608 
1609 
1610 #ifdef OOMPH_HAS_MPI
1611 
1615  void set_communicator_pt(OomphCommunicator* comm_pt)
1616  {
1617  Comm_pt = comm_pt;
1618  }
1619 
1621  void set_keep_all_elements_as_halos()
1622  {
1623  Keep_all_elements_as_halos = true;
1624  }
1625 
1628  void unset_keep_all_elements_as_halos()
1629  {
1630  Keep_all_elements_as_halos = false;
1631  }
1632 
1636  virtual void distribute(OomphCommunicator* comm_pt,
1637  const Vector<unsigned>& element_domain,
1638  Vector<GeneralisedElement*>& deleted_element_pt,
1639  DocInfo& doc_info,
1640  const bool& report_stats,
1641  const bool& overrule_keep_as_halo_element_status);
1642 
1645  void distribute(OomphCommunicator* comm_pt,
1646  const Vector<unsigned>& element_domain,
1647  Vector<GeneralisedElement*>& deleted_element_pt,
1648  const bool& report_stats = false)
1649  {
1650  DocInfo doc_info;
1651  doc_info.disable_doc();
1652  bool overrule_keep_as_halo_element_status = false;
1653  return distribute(comm_pt,
1654  element_domain,
1655  deleted_element_pt,
1656  doc_info,
1657  report_stats,
1658  overrule_keep_as_halo_element_status);
1659  }
1660 
1667  void prune_halo_elements_and_nodes(
1668  Vector<GeneralisedElement*>& deleted_element_pt,
1669  const bool& report_stats = false)
1670  {
1671  DocInfo doc_info;
1672  doc_info.disable_doc();
1673  prune_halo_elements_and_nodes(deleted_element_pt, doc_info, report_stats);
1674  }
1675 
1676 
1683  void prune_halo_elements_and_nodes(
1684  Vector<GeneralisedElement*>& deleted_element_pt,
1685  DocInfo& doc_info,
1686  const bool& report_stats);
1687 
1692  void get_efficiency_of_mesh_distribution(double& av_efficiency,
1693  double& max_efficiency,
1694  double& min_efficiency);
1695 
1697  void doc_mesh_distribution(DocInfo& doc_info);
1698 
1700  void check_halo_schemes(DocInfo& doc_info,
1701  double& max_permitted_error_for_halo_check);
1702 
1706  virtual void classify_halo_and_haloed_nodes(DocInfo& doc_info,
1707  const bool& report_stats);
1708 
1712  virtual void classify_halo_and_haloed_nodes(
1713  const bool& report_stats = false)
1714  {
1715  DocInfo doc_info;
1716  doc_info.disable_doc();
1717  classify_halo_and_haloed_nodes(doc_info, report_stats);
1718  }
1719 
1731  void synchronise_shared_nodes(const bool& report_stats);
1732 
1733 
1736  void get_all_halo_data(std::map<unsigned, double*>& map_of_halo_data);
1737 
1740  Vector<GeneralisedElement*> halo_element_pt(const unsigned& p)
1741  {
1742  // Prepare vector
1743  Vector<GeneralisedElement*> vec_el_pt;
1744 
1745  // Loop over all root halo elements
1746  unsigned nelem = nroot_halo_element(p);
1747  for (unsigned e = 0; e < nelem; e++)
1748  {
1749  GeneralisedElement* el_pt = root_halo_element_pt(p, e);
1750 
1751  // Is it a refineable element?
1752  RefineableElement* ref_el_pt = dynamic_cast<RefineableElement*>(el_pt);
1753  if (ref_el_pt != 0)
1754  {
1755  // Vector of pointers to leaves in tree emanating from
1756  // current root halo element
1757  Vector<Tree*> leaf_pt;
1758  ref_el_pt->tree_pt()->stick_leaves_into_vector(leaf_pt);
1759 
1760  // Loop over leaves and add their objects (the finite elements)
1761  // to vector
1762  unsigned nleaf = leaf_pt.size();
1763  for (unsigned l = 0; l < nleaf; l++)
1764  {
1765  vec_el_pt.push_back(leaf_pt[l]->object_pt());
1766  }
1767  }
1768  else
1769  {
1770  vec_el_pt.push_back(el_pt);
1771  }
1772  }
1773  return vec_el_pt;
1774  }
1775 
1776 
1779  Vector<GeneralisedElement*> haloed_element_pt(const unsigned& p)
1780  {
1781  // Prepare vector
1782  Vector<GeneralisedElement*> vec_el_pt;
1783 
1784  // Loop over all root haloed elements
1785  unsigned nelem = nroot_haloed_element(p);
1786  for (unsigned e = 0; e < nelem; e++)
1787  {
1788  GeneralisedElement* el_pt = root_haloed_element_pt(p, e);
1789 
1790  // Is it a refineable element?
1791  RefineableElement* ref_el_pt = dynamic_cast<RefineableElement*>(el_pt);
1792  if (ref_el_pt != 0)
1793  {
1794  // Vector of pointers to leaves in tree emanating from
1795  // current root haloed element
1796  Vector<Tree*> leaf_pt;
1797  ref_el_pt->tree_pt()->stick_leaves_into_vector(leaf_pt);
1798 
1799  // Loop over leaves and add their objects (the finite elements)
1800  // to vector
1801  unsigned nleaf = leaf_pt.size();
1802  for (unsigned l = 0; l < nleaf; l++)
1803  {
1804  vec_el_pt.push_back(leaf_pt[l]->object_pt());
1805  }
1806  }
1807  else
1808  {
1809  vec_el_pt.push_back(el_pt);
1810  }
1811  }
1812  return vec_el_pt;
1813  }
1814 
1817  unsigned nnon_halo_element()
1818  {
1819  unsigned count = 0;
1820  unsigned n = nelement();
1821  for (unsigned e = 0; e < n; e++)
1822  {
1823  if (!(element_pt(e)->is_halo())) count++;
1824  }
1825  return count;
1826  }
1827 
1828 
1830  unsigned nroot_halo_element()
1831  {
1832  unsigned n = 0;
1833  for (std::map<unsigned, Vector<GeneralisedElement*>>::iterator it =
1834  Root_halo_element_pt.begin();
1835  it != Root_halo_element_pt.end();
1836  it++)
1837  {
1838  n += it->second.size();
1839  }
1840  return n;
1841  }
1842 
1843 
1846  unsigned nroot_halo_element(const unsigned& p)
1847  {
1848  return Root_halo_element_pt[p].size();
1849  }
1850 
1851 
1854  Vector<GeneralisedElement*> root_halo_element_pt(const unsigned& p)
1855  {
1856  return Root_halo_element_pt[p];
1857  }
1858 
1859 
1862  GeneralisedElement*& root_halo_element_pt(const unsigned& p,
1863  const unsigned& e)
1864  {
1865  return Root_halo_element_pt[p][e];
1866  }
1867 
1868 
1871  void add_root_halo_element_pt(const unsigned& p, GeneralisedElement*& el_pt)
1872  {
1873  Root_halo_element_pt[p].push_back(el_pt);
1874  el_pt->set_halo(p);
1875  }
1876 
1878  unsigned nhalo_node()
1879  {
1880  unsigned n = 0;
1881  for (std::map<unsigned, Vector<Node*>>::iterator it =
1882  Halo_node_pt.begin();
1883  it != Halo_node_pt.end();
1884  it++)
1885  {
1886  n += it->second.size();
1887  }
1888  return n;
1889  }
1890 
1893  unsigned nhalo_node(const unsigned& p)
1894  {
1895  // Memory saving version of: return Halo_node_pt[p].size();
1896  std::map<unsigned, Vector<Node*>>::iterator it = Halo_node_pt.find(p);
1897  if (it == Halo_node_pt.end())
1898  {
1899  return 0;
1900  }
1901  return (*it).second.size();
1902  }
1903 
1906  void add_halo_node_pt(const unsigned& p, Node*& nod_pt)
1907  {
1908  Halo_node_pt[p].push_back(nod_pt);
1909  }
1910 
1911 
1914  Node* halo_node_pt(const unsigned& p, const unsigned& j)
1915  {
1916  return Halo_node_pt[p][j];
1917  }
1918 
1919 
1921  unsigned nroot_haloed_element()
1922  {
1923  unsigned n = 0;
1924  for (std::map<unsigned, Vector<GeneralisedElement*>>::iterator it =
1925  Root_haloed_element_pt.begin();
1926  it != Root_haloed_element_pt.end();
1927  it++)
1928  {
1929  n += it->second.size();
1930  }
1931  return n;
1932  }
1933 
1936  unsigned nroot_haloed_element(const unsigned& p)
1937  {
1938  // Memory saving version of: return Root_haloed_element_pt[p].size();
1939  std::map<unsigned, Vector<GeneralisedElement*>>::iterator it =
1940  Root_haloed_element_pt.find(p);
1941  if (it == Root_haloed_element_pt.end())
1942  {
1943  return 0;
1944  }
1945  return (*it).second.size();
1946  }
1947 
1948 
1951  Vector<GeneralisedElement*> root_haloed_element_pt(const unsigned& p)
1952  {
1953  // Memory saving version of: return Root_haloed_element_pt[p];
1954  std::map<unsigned, Vector<GeneralisedElement*>>::iterator it =
1955  Root_haloed_element_pt.find(p);
1956  if (it == Root_haloed_element_pt.end())
1957  {
1958  Vector<GeneralisedElement*> tmp;
1959  return tmp;
1960  }
1961  return (*it).second;
1962  }
1963 
1966  GeneralisedElement*& root_haloed_element_pt(const unsigned& p,
1967  const unsigned& e)
1968  {
1969  return Root_haloed_element_pt[p][e];
1970  }
1971 
1977  void add_root_haloed_element_pt(const unsigned& p,
1978  GeneralisedElement*& el_pt)
1979  {
1980  Root_haloed_element_pt[p].push_back(el_pt);
1981  }
1982 
1983 
1985  unsigned nhaloed_node()
1986  {
1987  unsigned n = 0;
1988  for (std::map<unsigned, Vector<Node*>>::iterator it =
1989  Haloed_node_pt.begin();
1990  it != Haloed_node_pt.end();
1991  it++)
1992  {
1993  n += it->second.size();
1994  }
1995  return n;
1996  }
1997 
1998 
2001  unsigned nhaloed_node(const unsigned& p)
2002  {
2003  // Memory saving version of: return Haloed_node_pt[p].size();
2004  std::map<unsigned, Vector<Node*>>::iterator it = Haloed_node_pt.find(p);
2005  if (it == Haloed_node_pt.end())
2006  {
2007  return 0;
2008  }
2009  return (*it).second.size();
2010  }
2011 
2014  Node* haloed_node_pt(const unsigned& p, const unsigned& j)
2015  {
2016  return Haloed_node_pt[p][j];
2017  }
2018 
2021  void add_haloed_node_pt(const unsigned& p, Node*& nod_pt)
2022  {
2023  Haloed_node_pt[p].push_back(nod_pt);
2024  }
2025 
2027  bool Output_halo_elements;
2028 
2029 
2032  void disable_resizing_of_halo_nodes()
2033  {
2034  Resize_halo_nodes_not_required = true;
2035  }
2036 
2037 
2040  void enable_resizing_of_halo_nodes()
2041  {
2042  Resize_halo_nodes_not_required = false;
2043  }
2044 
2046  void disable_output_of_halo_elements()
2047  {
2048  Output_halo_elements = false;
2049  }
2050 
2052  void enable_output_of_halo_elements()
2053  {
2054  Output_halo_elements = true;
2055  }
2056 
2058  unsigned nshared_node()
2059  {
2060  unsigned n = 0;
2061  for (std::map<unsigned, Vector<Node*>>::iterator it =
2062  Shared_node_pt.begin();
2063  it != Shared_node_pt.end();
2064  it++)
2065  {
2066  n += it->second.size();
2067  }
2068  return n;
2069  }
2070 
2072  void doc_shared_nodes()
2073  {
2074  for (std::map<unsigned, Vector<Node*>>::iterator it =
2075  Shared_node_pt.begin();
2076  it != Shared_node_pt.end();
2077  it++)
2078  {
2079  unsigned n = it->second.size();
2080  for (unsigned j = 0; j < n; j++)
2081  {
2082  oomph_info << "Shared node with proc " << it->first << " ";
2083  Node* nod_pt = it->second[j];
2084  unsigned ndim = nod_pt->ndim();
2085  for (unsigned i = 0; i < ndim; i++)
2086  {
2087  oomph_info << nod_pt->x(i) << " ";
2088  }
2089  oomph_info << nod_pt->is_hanging() << " ";
2090  oomph_info << j << " " << nod_pt << std::endl;
2091  }
2092  }
2093  }
2094 
2097  unsigned nshared_node(const unsigned& p)
2098  {
2099  // Memory saving version of: return Shared_node_pt[p].size();
2100  std::map<unsigned, Vector<Node*>>::iterator it = Shared_node_pt.find(p);
2101  if (it == Shared_node_pt.end())
2102  {
2103  return 0;
2104  }
2105  return (*it).second.size();
2106  }
2107 
2110  Node* shared_node_pt(const unsigned& p, const unsigned& j)
2111  {
2112  return Shared_node_pt[p][j];
2113  }
2114 
2119  void get_shared_node_pt(const unsigned& p, Vector<Node*>& shared_node_pt)
2120  {
2121  unsigned np = nshared_node(p);
2122  shared_node_pt.resize(np);
2123  for (unsigned j = 0; j < np; j++)
2124  {
2125  shared_node_pt[j] = Shared_node_pt[p][j];
2126  }
2127  }
2128 
2129 
2133  void add_shared_node_pt(const unsigned& p, Node*& nod_pt)
2134  {
2135  Shared_node_pt[p].push_back(nod_pt);
2136  }
2137 
2142  void get_halo_node_stats(double& av_number,
2143  unsigned& max_number,
2144  unsigned& min_number);
2145 
2150  void get_haloed_node_stats(double& av_number,
2151  unsigned& max_number,
2152  unsigned& min_number);
2153 
2154  // External halo(ed) elements are "source/other" elements which are
2155  // on different processes to the element for which they are the source
2156 
2158  void output_external_halo_elements(std::ostream& outfile,
2159  const unsigned& n_plot = 5)
2160  {
2161  for (std::map<unsigned, Vector<GeneralisedElement*>>::iterator it =
2162  External_halo_element_pt.begin();
2163  it != External_halo_element_pt.end();
2164  it++)
2165  {
2166  unsigned p = (*it).first;
2167  output_external_halo_elements(p, outfile, n_plot);
2168  }
2169  }
2170 
2172  void output_external_halo_elements(const unsigned& p,
2173  std::ostream& outfile,
2174  const unsigned& n_plot = 5)
2175  {
2176  unsigned nel = External_halo_element_pt[p].size();
2177  for (unsigned e = 0; e < nel; e++)
2178  {
2179  FiniteElement* fe_pt =
2180  dynamic_cast<FiniteElement*>(External_halo_element_pt[p][e]);
2181  if (fe_pt != 0)
2182  {
2183  fe_pt->output(outfile, n_plot);
2184  }
2185  }
2186  }
2187 
2188 
2190  void output_external_haloed_elements(std::ostream& outfile,
2191  const unsigned& n_plot = 5)
2192  {
2193  for (std::map<unsigned, Vector<GeneralisedElement*>>::iterator it =
2194  External_haloed_element_pt.begin();
2195  it != External_haloed_element_pt.end();
2196  it++)
2197  {
2198  unsigned p = (*it).first;
2199  output_external_haloed_elements(p, outfile, n_plot);
2200  }
2201  }
2202 
2204  void output_external_haloed_elements(const unsigned& p,
2205  std::ostream& outfile,
2206  const unsigned& n_plot = 5)
2207  {
2208  unsigned nel = External_haloed_element_pt[p].size();
2209  for (unsigned e = 0; e < nel; e++)
2210  {
2211  FiniteElement* fe_pt =
2212  dynamic_cast<FiniteElement*>(External_haloed_element_pt[p][e]);
2213  if (fe_pt != 0)
2214  {
2215  fe_pt->output(outfile, n_plot);
2216  }
2217  }
2218  }
2219 
2220 
2222  unsigned nexternal_halo_element()
2223  {
2224  unsigned n = 0;
2225  for (std::map<unsigned, Vector<GeneralisedElement*>>::iterator it =
2226  External_halo_element_pt.begin();
2227  it != External_halo_element_pt.end();
2228  it++)
2229  {
2230  n += it->second.size();
2231  }
2232  return n;
2233  }
2234 
2237  unsigned nexternal_halo_element(const unsigned& p)
2238  {
2239  // Memory saving version of: return External_halo_element_pt[p].size();
2240  std::map<unsigned, Vector<GeneralisedElement*>>::iterator it =
2241  External_halo_element_pt.find(p);
2242  if (it == External_halo_element_pt.end())
2243  {
2244  return 0;
2245  }
2246  return (*it).second.size();
2247  }
2248 
2251  GeneralisedElement*& external_halo_element_pt(const unsigned& p,
2252  const unsigned& e)
2253  {
2254  return External_halo_element_pt[p][e];
2255  }
2256 
2259  void add_external_halo_element_pt(const unsigned& p,
2260  GeneralisedElement*& el_pt)
2261  {
2262  External_halo_element_pt[p].push_back(el_pt);
2263  el_pt->set_halo(p);
2264  }
2265 
2267  unsigned nexternal_haloed_element()
2268  {
2269  unsigned n = 0;
2270  for (std::map<unsigned, Vector<GeneralisedElement*>>::iterator it =
2271  External_haloed_element_pt.begin();
2272  it != External_haloed_element_pt.end();
2273  it++)
2274  {
2275  n += it->second.size();
2276  }
2277  return n;
2278  }
2279 
2282  unsigned nexternal_haloed_element(const unsigned& p)
2283  {
2284  // Memory saving version of: return External_haloed_element_pt[p].size();
2285  std::map<unsigned, Vector<GeneralisedElement*>>::iterator it =
2286  External_haloed_element_pt.find(p);
2287  if (it == External_haloed_element_pt.end())
2288  {
2289  return 0;
2290  }
2291  return (*it).second.size();
2292  }
2293 
2296  GeneralisedElement*& external_haloed_element_pt(const unsigned& p,
2297  const unsigned& e)
2298  {
2299  return External_haloed_element_pt[p][e];
2300  }
2301 
2304  unsigned add_external_haloed_element_pt(const unsigned& p,
2305  GeneralisedElement*& el_pt);
2306 
2308  unsigned nexternal_halo_node()
2309  {
2310  unsigned n = 0;
2311  for (std::map<unsigned, Vector<Node*>>::iterator it =
2312  External_halo_node_pt.begin();
2313  it != External_halo_node_pt.end();
2314  it++)
2315  {
2316  n += it->second.size();
2317  }
2318  return n;
2319  }
2320 
2321 
2323  void get_external_halo_node_pt(Vector<Node*>& external_halo_node_pt)
2324  {
2325  unsigned n_total = nexternal_halo_node();
2326  external_halo_node_pt.reserve(n_total);
2327  for (std::map<unsigned, Vector<Node*>>::iterator it =
2328  External_halo_node_pt.begin();
2329  it != External_halo_node_pt.end();
2330  it++)
2331  {
2332  unsigned np = (it->second).size();
2333  for (unsigned j = 0; j < np; j++)
2334  {
2335  external_halo_node_pt.push_back((it->second)[j]);
2336  }
2337  }
2338 #ifdef PARANOID
2339  if (external_halo_node_pt.size() != n_total)
2340  {
2341  std::ostringstream error_stream;
2342  error_stream << "Total number of external halo nodes, " << n_total
2343  << " doesn't match number of entries \n in vector, "
2344  << external_halo_node_pt.size() << std::endl;
2345  throw OomphLibError(
2346  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2347  }
2348 #endif
2349  }
2350 
2351 
2354  unsigned nexternal_halo_node(const unsigned& p)
2355  {
2356  // Memory saving version of: return External_halo_node_pt[p].size();
2357  std::map<unsigned, Vector<Node*>>::iterator it =
2358  External_halo_node_pt.find(p);
2359  if (it == External_halo_node_pt.end())
2360  {
2361  return 0;
2362  }
2363  return (*it).second.size();
2364  }
2365 
2368  void add_external_halo_node_pt(const unsigned& p, Node*& nod_pt)
2369  {
2370  External_halo_node_pt[p].push_back(nod_pt);
2371  nod_pt->set_halo(p);
2372  }
2373 
2374 
2377  Node*& external_halo_node_pt(const unsigned& p, const unsigned& j)
2378  {
2379  return External_halo_node_pt[p][j];
2380  }
2381 
2384  Vector<Node*> external_halo_node_pt(const unsigned& p)
2385  {
2386  std::map<unsigned, Vector<Node*>>::iterator it =
2387  External_halo_node_pt.find(p);
2388  if (it == External_halo_node_pt.end())
2389  {
2390  Vector<Node*> tmp;
2391  return tmp;
2392  }
2393  return (*it).second;
2394  }
2395 
2398  void set_external_halo_node_pt(const unsigned& p,
2399  const Vector<Node*>& external_halo_node_pt)
2400  {
2401  External_halo_node_pt[p] = external_halo_node_pt;
2402  }
2403 
2405  void null_external_halo_node(const unsigned& p, Node* nod_pt);
2406 
2409  void remove_null_pointers_from_external_halo_node_storage();
2410 
2412  unsigned nexternal_haloed_node()
2413  {
2414  unsigned n = 0;
2415  for (std::map<unsigned, Vector<Node*>>::iterator it =
2416  External_haloed_node_pt.begin();
2417  it != External_haloed_node_pt.end();
2418  it++)
2419  {
2420  n += it->second.size();
2421  }
2422  return n;
2423  }
2424 
2427  unsigned nexternal_haloed_node(const unsigned& p)
2428  {
2429  // Memory saving version of: return External_haloed_node_pt[p].size();
2430  std::map<unsigned, Vector<Node*>>::iterator it =
2431  External_haloed_node_pt.find(p);
2432  if (it == External_haloed_node_pt.end())
2433  {
2434  return 0;
2435  }
2436  return (*it).second.size();
2437  }
2438 
2441  Node*& external_haloed_node_pt(const unsigned& p, const unsigned& j)
2442  {
2443  return External_haloed_node_pt[p][j];
2444  }
2445 
2448  unsigned add_external_haloed_node_pt(const unsigned& p, Node*& nod_pt);
2449 
2452  Vector<Node*> external_haloed_node_pt(const unsigned& p)
2453  {
2454  std::map<unsigned, Vector<Node*>>::iterator it =
2455  External_haloed_node_pt.find(p);
2456  if (it == External_haloed_node_pt.end())
2457  {
2458  Vector<Node*> tmp;
2459  return tmp;
2460  }
2461  return (*it).second;
2462  }
2463 
2466  void set_external_haloed_node_pt(
2467  const unsigned& p, const Vector<Node*>& external_haloed_node_pt)
2468  {
2469  External_haloed_node_pt[p] = external_haloed_node_pt;
2470  }
2471 
2475  std::set<int> external_halo_proc()
2476  {
2477  std::set<int> procs;
2478  for (std::map<unsigned, Vector<Node*>>::iterator it =
2479  External_halo_node_pt.begin();
2480  it != External_halo_node_pt.end();
2481  it++)
2482  {
2483  procs.insert((*it).first);
2484  }
2485  return procs;
2486  }
2487 
2490  virtual void create_shared_boundaries(
2491  OomphCommunicator* comm_pt,
2492  const Vector<unsigned>& element_domain,
2493  const Vector<GeneralisedElement*>& backed_up_el_pt,
2494  const Vector<FiniteElement*>& backed_up_f_el_pt,
2495  std::map<Data*, std::set<unsigned>>& processors_associated_with_data,
2496  const bool& overrule_keep_as_halo_element_status)
2497  {
2498  std::ostringstream error_stream;
2499  error_stream << "Empty default create_shared_boundaries() method"
2500  << "called.\n";
2501  error_stream << "This should be overloaded in a specific "
2502  << "TriangleMeshBase\n";
2503  throw OomphLibError(error_stream.str(),
2504  "Mesh::create_shared_boundaries()",
2506  }
2507 
2508  // Check if necessary to add the element as haloed or if it has been
2509  // previously added to the haloed scheme
2510  virtual unsigned try_to_add_root_haloed_element_pt(
2511  const unsigned& p, GeneralisedElement*& el_pt)
2512  {
2513  std::ostringstream error_stream;
2514  error_stream << "Empty default try_to_add_root_haloed_element_pt() method"
2515  << "called.\n";
2516  error_stream << "This should be overloaded in a specific "
2517  << "TriangleMeshBase\n";
2518  throw OomphLibError(error_stream.str(),
2519  "Mesh::try_to_add_root_haloed_element_pt()",
2521  }
2522 
2523  // Check if necessary to add the node as haloed or if it has been
2524  // previously added to the haloed scheme
2525  virtual unsigned try_to_add_haloed_node_pt(const unsigned& p, Node*& nod_pt)
2526  {
2527  std::ostringstream error_stream;
2528  error_stream << "Empty default try_to_add_haloed_node_pt() method"
2529  << "called.\n";
2530  error_stream << "This should be overloaded in a specific "
2531  << "TriangleMeshBase\n";
2532  throw OomphLibError(error_stream.str(),
2533  "Mesh::try_to_add_haloed_node_pt()",
2535  }
2536 
2537 #endif
2538 
2541  };
2542 
2543 
2547 
2548  class SolidICProblem;
2549 
2550  //========================================================================
2556  //
2557  // Needs to be derived from Mesh with virtual so that
2558  // solid meshes can be derived from general meshes, without
2559  // multiple copies of Mesh objects
2560  //========================================================================
2561  class SolidMesh : public virtual Mesh
2562  {
2563  public:
2566 
2568  SolidMesh(const SolidMesh& dummy) = delete;
2569 
2571  void operator=(const SolidMesh&) = delete;
2572 
2576  SolidMesh(const Vector<SolidMesh*>& sub_mesh_pt)
2577  {
2578 #ifdef OOMPH_HAS_MPI
2579  // Mesh hasn't been distributed: Null out pointer to communicator
2580  Comm_pt = 0;
2581 #endif
2582 
2583  unsigned n = sub_mesh_pt.size();
2584  Vector<Mesh*> sub_mesh_mesh_pt(n);
2585  for (unsigned i = 0; i < n; i++)
2586  {
2587  sub_mesh_mesh_pt[i] = static_cast<Mesh*>(sub_mesh_pt[i]);
2588  }
2589  merge_meshes(sub_mesh_mesh_pt);
2590  }
2591 
2593  // Can safely cast the nodes to SolidNodes
2594  SolidNode* node_pt(const unsigned long& n)
2595  {
2596 #ifdef PARANOID
2597  if (!dynamic_cast<SolidNode*>(Node_pt[n]))
2598  {
2599  std::ostringstream error_stream;
2600  error_stream << "Error: Node " << n << "is a "
2601  << typeid(Node_pt[n]).name() << ", not an SolidNode"
2602  << std::endl;
2603  throw OomphLibError(
2604  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2605  }
2606 #endif
2607  // Return a static cast to the Node_pt
2608  return (static_cast<SolidNode*>(Node_pt[n]));
2609  }
2610 
2612  SolidNode* boundary_node_pt(const unsigned& b, const unsigned& n)
2613  {
2614 #ifdef PARANOID
2615  if (!dynamic_cast<SolidNode*>(Mesh::boundary_node_pt(b, n)))
2616  {
2617  std::ostringstream error_stream;
2618  error_stream << "Error: Node " << n << "is a "
2619  << typeid(Mesh::boundary_node_pt(b, n)).name()
2620  << ", not an SolidNode" << std::endl;
2621  throw OomphLibError(
2622  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2623  }
2624 #endif
2625  return static_cast<SolidNode*>(Mesh::boundary_node_pt(b, n));
2626  }
2627 
2631  SolidNode* element_node_pt(const unsigned long& e, const unsigned& n)
2632  {
2633 #ifdef PARANOID
2634  // Try to cast to FiniteElement
2635  FiniteElement* el_pt = dynamic_cast<FiniteElement*>(Element_pt[e]);
2636  if (el_pt == 0)
2637  {
2638  // Error
2639  throw OomphLibError("Failed cast to FiniteElement* ",
2642  }
2643  if (!dynamic_cast<SolidNode*>(el_pt->node_pt(n)))
2644  {
2645  std::ostringstream error_message;
2646  Node* np = el_pt->node_pt(n);
2647  error_message << "Error: Node " << n << " of element " << e << "is a "
2648  << typeid(*np).name() << ", not an SolidNode"
2649  << std::endl;
2650 
2651  throw OomphLibError(error_message.str(),
2654  }
2655 #endif
2656  // Return a cast to an SolidNode
2657  return (static_cast<SolidNode*>(
2658  dynamic_cast<FiniteElement*>(Element_pt[e])->node_pt(n)));
2659  }
2660 
2665 
2666 
2669  void scale_mesh(const double& factor)
2670  {
2671  Mesh::scale_mesh(factor);
2672 
2673  // Re-assign the Lagrangian coordinates
2675  }
2680  };
2681 
2682 
2686 
2687 
2688  //===================================================
2690  //===================================================
2691  class Edge
2692  {
2693  public:
2696  {
2697  if (node1_pt == node2_pt)
2698  {
2699 #ifdef PARANOID
2700  std::ostringstream error_stream;
2701  error_stream << "Edge cannot have two identical vertex nodes\n";
2702  throw OomphLibError(
2703  error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2704 #endif
2705  }
2706 
2707 
2708  // Sort lexicographically based on pointer address of nodes
2709  if (node1_pt > node2_pt)
2710  {
2711  Node1_pt = node1_pt;
2712  Node2_pt = node2_pt;
2713  }
2714  else
2715  {
2716  Node1_pt = node2_pt;
2717  Node2_pt = node1_pt;
2718  }
2719  }
2720 
2721 
2723  Node* node1_pt() const
2724  {
2725  return Node1_pt;
2726  }
2727 
2729  Node* node2_pt() const
2730  {
2731  return Node2_pt;
2732  }
2733 
2735  bool operator==(const Edge& other) const
2736  {
2737  if ((Node1_pt == other.node1_pt()) && (Node2_pt == other.node2_pt()))
2738 
2739  {
2740  return true;
2741  }
2742  else
2743  {
2744  return false;
2745  }
2746  }
2747 
2748 
2750  bool operator<(const Edge& other) const
2751  {
2752  if (Node1_pt < other.node1_pt())
2753  {
2754  return true;
2755  }
2756  else if (Node1_pt == other.node1_pt())
2757  {
2758  if (Node2_pt < other.node2_pt())
2759  {
2760  return true;
2761  }
2762  else
2763  {
2764  return false;
2765  }
2766  }
2767  else
2768  {
2769  return false;
2770  }
2771  }
2772 
2775  bool is_on_boundary() const
2776  {
2777  return (Node1_pt->is_on_boundary() && Node2_pt->is_on_boundary());
2778  }
2779 
2780 
2783  bool is_boundary_edge() const
2784  {
2785  return ((dynamic_cast<BoundaryNodeBase*>(Node1_pt) != 0) &&
2786  (dynamic_cast<BoundaryNodeBase*>(Node2_pt) != 0));
2787  }
2788 
2789  private:
2792 
2795  };
2796 
2797 
2801 
2802 
2803  //=================================================================
2806  //=================================================================
2807  namespace MeshChecker
2808  {
2809  //=================================================================
2819  //=================================================================
2820  template<class GEOM_ELEMENT_BASE, class ELEMENT>
2821  void assert_geometric_element(const unsigned& dim,
2822  const unsigned& nnode_1d = 0)
2823  {
2824  // Only do tests in paranoia mode
2825 #ifndef PARANOID
2826  return;
2827 #endif
2828 
2829  // Instantiate element
2830  ELEMENT* el_pt = new ELEMENT;
2831 
2832  // Can we cast to required geometric element base type
2833  if (dynamic_cast<GEOM_ELEMENT_BASE*>(el_pt) == 0)
2834  {
2835  std::stringstream error_message;
2836  error_message << "You have specified an illegal element type! Element "
2837  "is of type \n\n"
2838  << typeid(el_pt).name()
2839  << "\n\nand cannot be cast to type \n\n "
2840  << typeid(GEOM_ELEMENT_BASE).name() << "\n\n";
2841  throw OomphLibError(error_message.str(),
2844  }
2845 
2846  // Does the dimension match?
2847  if (dim != el_pt->dim())
2848  {
2849  std::stringstream error_message;
2850  error_message << "You have specified an illegal element type! Element "
2851  "is of type \n\n"
2852  << typeid(el_pt).name()
2853  << "\n\nand has dimension = " << el_pt->dim()
2854  << " but we need dim = " << dim << std::endl;
2855  throw OomphLibError(error_message.str(),
2858  }
2859 
2860  // Does nnode_1d match?
2861  if (nnode_1d != 0)
2862  {
2863  if (nnode_1d != el_pt->nnode_1d())
2864  {
2865  std::stringstream error_message;
2866  error_message << "You have specified an illegal element type! "
2867  "Element is of type \n\n"
2868  << typeid(el_pt).name()
2869  << "\n\nand has nnode_1d = " << el_pt->nnode_1d()
2870  << " but we need nnode_1d = " << nnode_1d << std::endl;
2871  throw OomphLibError(error_message.str(),
2874  }
2875  }
2876 
2877  // Clean up
2878  delete el_pt;
2879  }
2880 
2881  } // namespace MeshChecker
2882 
2883 
2887 
2888 
2889  //=================paraview_helper=================================
2891  //=================================================================
2892  namespace ParaviewHelper
2893  {
2895  extern void write_pvd_header(std::ofstream& pvd_file);
2896 
2899  extern void write_pvd_information(std::ofstream& pvd_file,
2900  const std::string& output_filename,
2901  const double& time);
2902 
2904  extern void write_pvd_footer(std::ofstream& pvd_file);
2905 
2906  } // namespace ParaviewHelper
2907 
2911 
2912  namespace NodeOrdering
2913  {
2918  inline bool node_global_position_comparison(Node* nd1_pt, Node* nd2_pt)
2919  {
2920  unsigned ndim = nd1_pt->ndim();
2921 
2922  unsigned j;
2923  for (j = 0; j < ndim; j++)
2924  {
2925  if (std::abs(nd1_pt->x(j) - nd2_pt->x(j)) > 1e-10)
2926  {
2927  if (nd1_pt->x(j) < nd2_pt->x(j))
2928  {
2929  return true;
2930  }
2931  else
2932  {
2933  return false;
2934  }
2935  }
2936  // otherwise they are the same in this dimension, check next one.
2937  }
2938 
2939  std::string err = "Nodes are at the same point to ~ 1e-10!";
2940  err += " difference is " +
2941  StringConversion::to_string(std::abs(nd1_pt->x(j) - nd2_pt->x(j)));
2942  throw OomphLibError(
2944  }
2945  } // namespace NodeOrdering
2946 
2947 
2948 } // namespace oomph
2949 
2950 #endif
AnnoyingScalar abs(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:135
AnnoyingScalar sqrt(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:134
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.)
float * p
Definition: Tutorial_Map_using.cpp:9
Scalar Scalar int size
Definition: benchVecAdd.cpp:17
Scalar * b
Definition: benchVecAdd.cpp:17
Definition: nodes.h:1996
Definition: generalised_timesteppers.h:101
virtual bool is_a_copy() const
Definition: nodes.h:253
Definition: elements.h:5014
Edge class.
Definition: mesh.h:2692
Node * node2_pt() const
Access to the second vertex node.
Definition: mesh.h:2729
bool is_on_boundary() const
Definition: mesh.h:2775
Node * node1_pt() const
Access to the first vertex node.
Definition: mesh.h:2723
bool is_boundary_edge() const
Definition: mesh.h:2783
Node * Node1_pt
First vertex node.
Definition: mesh.h:2791
Edge(Node *node1_pt, Node *node2_pt)
Constructor: Pass in the two vertex nodes.
Definition: mesh.h:2695
bool operator<(const Edge &other) const
Less-than operator.
Definition: mesh.h:2750
Node * Node2_pt
Second vertex node.
Definition: mesh.h:2794
bool operator==(const Edge &other) const
Comparison operator.
Definition: mesh.h:2735
double interpolated_x(const Vector< double > &s, const unsigned &i) const
Definition: elements.h:4528
void set_boundary_number_in_bulk_mesh(const unsigned &b)
Set function for the boundary number in bulk mesh.
Definition: elements.h:4482
Definition: elements.h:1313
void interpolated_zeta(const Vector< double > &s, Vector< double > &zeta) const
Definition: elements.cc:4675
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2175
double size() const
Definition: elements.cc:4290
virtual std::string tecplot_zone_string(const unsigned &nplot) const
Definition: elements.h:3161
virtual void compute_error(FiniteElement::SteadyExactSolutionFctPt exact_soln_pt, double &error, double &norm)
Calculate the norm of the error and that of the exact solution.
Definition: elements.h:3198
void(* SteadyExactSolutionFctPt)(const Vector< double > &, Vector< double > &)
Definition: elements.h:1759
virtual void get_s_plot(const unsigned &i, const unsigned &nplot, Vector< double > &s, const bool &shifted_to_interior=false) const
Definition: elements.h:3148
virtual unsigned nplot_points(const unsigned &nplot) const
Definition: elements.h:3186
virtual void write_tecplot_zone_footer(std::ostream &outfile, const unsigned &nplot) const
Definition: elements.h:3174
void(* UnsteadyExactSolutionFctPt)(const double &, const Vector< double > &, Vector< double > &)
Definition: elements.h:1765
Definition: elements.h:73
virtual void compute_norm(Vector< double > &norm)
Definition: elements.h:1128
Definition: mesh.h:67
void add_boundary_node(const unsigned &b, Node *const &node_pt)
Add a (pointer to) a node to the b-th boundary.
Definition: mesh.cc:243
unsigned long nboundary_node(const unsigned &ibound) const
Return number of nodes on a particular boundary.
Definition: mesh.h:833
void(FiniteElement::* SteadyExactSolutionFctPt)(const Vector< double > &x, Vector< double > &soln)
Definition: mesh.h:223
Vector< Node * > Node_pt
Vector of pointers to nodes.
Definition: mesh.h:183
Node * boundary_node_pt(const unsigned &b, const unsigned &n) const
Return pointer to node n on boundary b.
Definition: mesh.h:499
static Steady< 0 > Default_TimeStepper
The Steady Timestepper.
Definition: mesh.h:75
bool does_pointer_correspond_to_mesh_data(double *const &parameter_pt)
Does the double pointer correspond to any mesh data.
Definition: mesh.cc:2471
virtual void compute_error(std::ostream &outfile, FiniteElement::UnsteadyExactSolutionFctPt exact_soln_pt, const double &time, Vector< double > &error, Vector< double > &norm)
Definition: mesh.h:1351
unsigned ndof_types() const
Return number of dof types in mesh.
Definition: mesh.cc:8764
void remove_boundary_node(const unsigned &b, Node *const &node_pt)
Remove a node from the boundary b.
Definition: mesh.cc:221
bool is_mesh_distributed() const
Boolean to indicate if Mesh has been distributed.
Definition: mesh.h:1588
void max_and_min_element_size(double &max_size, double &min_size)
Definition: mesh.h:692
Vector< Vector< FiniteElement * > > Boundary_element_pt
Definition: mesh.h:91
unsigned nodal_dimension() const
Return number of nodal dimension in mesh.
Definition: mesh.cc:9055
virtual void compute_norm(double &norm)
Definition: mesh.h:1068
bool Lookup_for_elements_next_boundary_is_setup
Definition: mesh.h:87
void flush_element_and_node_storage()
Definition: mesh.h:407
OomphCommunicator * communicator_pt() const
Definition: mesh.h:1600
void flush_element_storage()
Definition: mesh.h:423
GeneralisedElement * element_pt(const unsigned long &e) const
Return pointer to element e (const version)
Definition: mesh.h:454
void output(const std::string &output_filename)
Output for all elements.
Definition: mesh.h:975
std::vector< bool > Boundary_coordinate_exists
Definition: mesh.h:190
virtual void setup_boundary_element_info(std::ostream &outfile)
Definition: mesh.h:281
Node * node_pt(const unsigned long &n) const
Return pointer to global node n (const version)
Definition: mesh.h:442
FiniteElement * finite_element_pt(const unsigned &e) const
Definition: mesh.h:473
void(FiniteElement::* UnsteadyExactSolutionFctPt)(const double &time, const Vector< double > &x, Vector< double > &soln)
Definition: mesh.h:228
virtual void set_mesh_level_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Definition: mesh.cc:2402
void describe_local_dofs(std::ostream &out, const std::string &current_string) const
Definition: mesh.cc:746
void check_inverted_elements(bool &mesh_has_inverted_elements)
Definition: mesh.h:742
int face_index_at_boundary(const unsigned &b, const unsigned &e) const
Definition: mesh.h:896
Vector< Vector< int > > Face_index_at_boundary
Definition: mesh.h:95
void set_nboundary(const unsigned &nbound)
Set the number of boundaries in the mesh.
Definition: mesh.h:505
Vector< GeneralisedElement * > & element_pt()
Return reference to the Vector of elements.
Definition: mesh.h:466
void copy_boundary_node_data_from_nodes()
Definition: mesh.h:526
void set_elemental_internal_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Definition: mesh.cc:2535
void doc_boundary_coordinates(const unsigned &b, std::ofstream &the_file)
Definition: mesh.h:303
unsigned nboundary_element(const unsigned &b) const
Return number of finite elements that are adjacent to boundary b.
Definition: mesh.h:878
void set_nodal_and_elemental_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Definition: mesh.h:1032
virtual void setup_boundary_element_info()
Definition: mesh.h:275
unsigned elemental_dimension() const
Return number of elemental dimension in mesh.
Definition: mesh.cc:8917
void check_inverted_elements(bool &mesh_has_inverted_elements, std::ofstream &inverted_element_file)
Definition: mesh.cc:870
virtual void compute_norm(Vector< double > &norm)
Definition: mesh.h:1099
void output_fct(std::ostream &outfile, const unsigned &n_plot, FiniteElement::SteadyExactSolutionFctPt)
Output a given Vector function at f(n_plot) points in each element.
Definition: mesh.cc:2199
virtual void compute_error(std::ostream &outfile, FiniteElement::UnsteadyExactSolutionFctPt exact_soln_pt, const double &time, double &error, double &norm)
Definition: mesh.h:1140
virtual void scale_mesh(const double &factor)
Definition: mesh.h:373
void shift_time_values()
Definition: mesh.cc:2326
virtual void reorder_nodes(const bool &use_old_ordering=true)
Definition: mesh.cc:508
void calculate_predictions()
Definition: mesh.cc:2366
void output_boundaries(const std::string &output_filename)
Definition: mesh.h:1009
unsigned nboundary() const
Return number of boundaries.
Definition: mesh.h:827
void describe_dofs(std::ostream &out, const std::string &current_string) const
Definition: mesh.cc:711
FiniteElement * boundary_element_pt(const unsigned &b, const unsigned &e) const
Return pointer to e-th finite element on boundary b.
Definition: mesh.h:840
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
Definition: mesh.h:448
void output_fct_paraview(std::ofstream &file_out, const unsigned &nplot, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt) const
Definition: mesh.cc:1491
void remove_boundary_nodes()
Clear all pointers to boundary nodes.
Definition: mesh.cc:204
void build_face_mesh(const unsigned &b, Mesh *const &face_mesh_pt)
Definition: mesh.h:653
unsigned long nnode() const
Return number of nodes in the mesh.
Definition: mesh.h:596
virtual void compute_error(std::ostream &outfile, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt, double &error, double &norm)
Definition: mesh.h:1186
virtual void node_update(const bool &update_all_solid_nodes=false)
Definition: mesh.cc:287
void delete_all_external_storage()
Wipe the storage for all externally-based elements.
Definition: mesh.cc:9190
virtual void compute_error(FiniteElement::UnsteadyExactSolutionFctPt exact_soln_pt, const double &time, Vector< double > &error, Vector< double > &norm)
Definition: mesh.h:1525
Mesh()
Default constructor.
Definition: mesh.h:236
unsigned check_for_repeated_nodes(const double &epsilon=1.0e-12)
Definition: mesh.h:752
void convert_to_boundary_node(Node *&node_pt, const Vector< FiniteElement * > &finite_element_pt)
Definition: mesh.cc:2590
void output(std::ostream &outfile)
Output for all elements.
Definition: mesh.cc:2027
virtual void compute_error(std::ostream &outfile, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt, Vector< double > &error, Vector< double > &norm)
Definition: mesh.h:1417
void add_element_pt(GeneralisedElement *const &element_pt)
Add a (pointer to) an element to the mesh.
Definition: mesh.h:617
void operator=(const Mesh &)=delete
Broken assignment operator.
void assign_initial_values_impulsive()
Assign initial values for an impulsive start.
Definition: mesh.cc:2288
const Vector< GeneralisedElement * > & element_pt() const
Return reference to the Vector of elements.
Definition: mesh.h:460
Node *& node_pt(const unsigned long &n)
Return pointer to global node n.
Definition: mesh.h:436
void flush_node_storage()
Definition: mesh.h:430
void assign_local_eqn_numbers(const bool &store_local_dof_pt)
Assign local equation numbers in all elements.
Definition: mesh.cc:765
Vector< Vector< Node * > > Boundary_node_pt
Definition: mesh.h:83
virtual ~Mesh()
Virtual Destructor to clean up all memory.
Definition: mesh.cc:650
void add_node_pt(Node *const &node_pt)
Add a (pointer to a) node to the mesh.
Definition: mesh.h:611
virtual void read(std::ifstream &restart_file)
Read solution from restart file.
Definition: mesh.cc:1130
void set_nodal_time_stepper(TimeStepper *const &time_stepper_pt, const bool &preserve_existing_data)
Set the timestepper associated with the nodal data in the mesh.
Definition: mesh.cc:2516
virtual void reset_boundary_element_info(Vector< unsigned > &ntmp_boundary_elements, Vector< Vector< unsigned >> &ntmp_boundary_elements_in_region, Vector< FiniteElement * > &deleted_elements)
Virtual function to perform the reset boundary elements info rutines.
Definition: mesh.h:284
unsigned self_test()
Self-test: Check elements and nodes. Return 0 for OK.
Definition: mesh.cc:778
void set_consistent_pinned_values_for_continuation(ContinuationStorageScheme *const &continuation_stepper_pt)
Set consistent values for pinned data in continuation.
Definition: mesh.cc:2436
Vector< Node * > prune_dead_nodes()
Definition: mesh.cc:966
void output(const std::string &output_filename, const unsigned &n_plot)
Output at f(n_plot) points in each element.
Definition: mesh.h:984
Node *& boundary_node_pt(const unsigned &b, const unsigned &n)
Return pointer to node n on boundary b.
Definition: mesh.h:493
Vector< GeneralisedElement * > Element_pt
Vector of pointers to generalised elements.
Definition: mesh.h:186
virtual void compute_error(FiniteElement::SteadyExactSolutionFctPt exact_soln_pt, Vector< double > &error, Vector< double > &norm)
Definition: mesh.h:1279
bool boundary_coordinate_exists(const unsigned &i) const
Indicate whether the i-th boundary has an intrinsic coordinate.
Definition: mesh.h:565
static bool Suppress_warning_about_empty_mesh_level_time_stepper_function
Static boolean flag to control warning about mesh level timesteppers.
Definition: mesh.h:233
Node * get_some_non_boundary_node() const
Definition: mesh.h:859
unsigned long assign_global_eqn_numbers(Vector< double * > &Dof_pt)
Assign (global) equation numbers to the nodes.
Definition: mesh.cc:677
virtual void compute_error(FiniteElement::SteadyExactSolutionFctPt exact_soln_pt, double &error, double &norm)
Definition: mesh.h:1231
Mesh(const Mesh &dummy)=delete
Broken copy constructor.
virtual void compute_error(FiniteElement::UnsteadyExactSolutionFctPt exact_soln_pt, const double &time, double &error, double &norm)
Returns the norm of the error and that of the exact solution.
Definition: mesh.h:1479
unsigned long nelement() const
Return number of elements in the mesh.
Definition: mesh.h:590
virtual void get_node_reordering(Vector< Node * > &reordering, const bool &use_old_ordering=true) const
Definition: mesh.cc:532
void merge_meshes(const Vector< Mesh * > &sub_mesh_pt)
Definition: mesh.cc:65
void output_paraview(std::ofstream &file_out, const unsigned &nplot) const
Definition: mesh.cc:1225
void output_boundaries(std::ostream &outfile)
Output the nodes on the boundaries (into separate tecplot zones)
Definition: mesh.cc:1064
virtual void dump(std::ofstream &dump_file, const bool &use_old_ordering=true) const
Dump the data in the mesh into a file for restart.
Definition: mesh.cc:1088
double total_size()
Definition: mesh.h:708
void dump(const std::string &dump_file_name, const bool &use_old_ordering=true) const
Dump the data in the mesh into a file for restart.
Definition: mesh.h:915
Mesh(const Vector< Mesh * > &sub_mesh_pt)
Definition: mesh.h:257
Definition: nodes.h:906
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition: nodes.h:1060
virtual bool is_on_boundary() const
Definition: nodes.h:1373
virtual void get_boundaries_pt(std::set< unsigned > *&boundaries_pt)
Definition: nodes.h:1365
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
Definition: nodes.h:1054
Definition: communicator.h:54
Definition: oomph_definitions.h:222
Definition: problem.h:151
Definition: elastic_problems.h:88
Definition: mesh.h:2562
void operator=(const SolidMesh &)=delete
Broken assignment operator.
SolidMesh()
Default constructor.
Definition: mesh.h:2565
static SolidICProblem Solid_IC_problem
Definition: mesh.h:2679
void scale_mesh(const double &factor)
Definition: mesh.h:2669
SolidMesh(const Vector< SolidMesh * > &sub_mesh_pt)
Definition: mesh.h:2576
SolidNode * node_pt(const unsigned long &n)
Return a pointer to the n-th global SolidNode.
Definition: mesh.h:2594
SolidNode * element_node_pt(const unsigned long &e, const unsigned &n)
Definition: mesh.h:2631
void set_lagrangian_nodal_coordinates()
Definition: mesh.cc:9564
SolidNode * boundary_node_pt(const unsigned &b, const unsigned &n)
Return n-th SolidNodes on b-th boundary.
Definition: mesh.h:2612
SolidMesh(const SolidMesh &dummy)=delete
Broken copy constructor.
Definition: nodes.h:1686
Definition: timesteppers.h:231
Definition: oomph-lib/src/generic/Vector.h:58
void initialise(const _Tp &__value)
Iterate over all values and set to the desired value.
Definition: oomph-lib/src/generic/Vector.h:167
#define min(a, b)
Definition: datatypes.h:22
#define max(a, b)
Definition: datatypes.h:23
RealScalar s
Definition: level1_cplx_impl.h:130
char char char int int * k
Definition: level2_impl.h:374
Eigen::Matrix< Scalar, Dynamic, Dynamic, ColMajor > tmp
Definition: level3_impl.h:365
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 pow(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:625
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
int error
Definition: calibrate.py:297
std::string string(const unsigned &i)
Definition: oomph_definitions.cc:286
void assert_geometric_element(const unsigned &dim, const unsigned &nnode_1d=0)
Definition: mesh.h:2821
bool node_global_position_comparison(Node *nd1_pt, Node *nd2_pt)
Definition: mesh.h:2918
void write_pvd_footer(std::ofstream &pvd_file)
Write the pvd file footer.
Definition: mesh.cc:9639
void write_pvd_header(std::ofstream &pvd_file)
Write the pvd file header.
Definition: mesh.cc:9615
void write_pvd_information(std::ofstream &pvd_file, const std::string &output_filename, const double &time)
Definition: mesh.cc:9624
double epsilon
Definition: osc_ring_sarah_asymptotics.h:43
std::string to_string(T object, unsigned float_precision=8)
Definition: oomph_utilities.h:189
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
Definition: AnisotropicHookean.h:10
OomphInfo oomph_info
Definition: oomph_definitions.cc:319
list x
Definition: plotDoE.py:28
string name
Definition: plotDoE.py:33
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86
std::ofstream out("Result.txt")
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2