pml_meshes.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// Version 1.0; svn revision $LastChangedRevision$
7 //LIC//
8 //LIC// $LastChangedDate$
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 #ifndef OOMPH_PML_MESH_HEADER
31 #define OOMPH_PML_MESH_HEADER
32 
33 // Config header generated by autoconfig
34 #ifdef HAVE_CONFIG_H
35 #include <oomph-lib-config.h>
36 #endif
37 
38 #include "mesh.h"
39 #include "../meshes/rectangular_quadmesh.template.h"
40 #include "../meshes/rectangular_quadmesh.template.cc"
41 #include "pml_elements.h"
42 
43 
44 namespace oomph
45 {
46 
47 //===================================================================
48 /// \short All helper routines for 2D bulk boundary mesh usage in order to
49 /// generate PML meshes aligned to the main mesh
50 //===================================================================
51  namespace TwoDimensionalPMLHelper
52  {
53  /// helper function for sorting the right boundary nodes
54  extern bool sorter_right_boundary(Node* nod_i_pt, Node* nod_j_pt);
55 
56  /// helper function for sorting the top boundary nodes
57  extern bool sorter_top_boundary(Node* nod_i_pt, Node* nod_j_pt);
58 
59  /// helper function for sorting the left boundary nodes
60  extern bool sorter_left_boundary(Node* nod_i_pt, Node* nod_j_pt);
61 
62  /// helper function for sorting the bottom boundary nodes
63  extern bool sorter_bottom_boundary(Node* nod_i_pt, Node* nod_j_pt);
64 
65  }
66 
67 //////////////////////////////////////////////////////////////////
68 //////////////////////////////////////////////////////////////////
69 //////////////////////////////////////////////////////////////////
70 
71 //====================================================================
72 /// PML mesh base class. Contains a pure virtual locate_zeta function
73 /// to be uploaded in PMLQuadMesh and PMLBrickMesh (once the code for
74 /// it has been written)
75 //====================================================================
77  {
78  public:
79 
80  /// \short Pure virtual function to provide an optimised version of
81  /// the locate_zeta function for PML meshes. As the PML meshes are
82  /// rectangular (in 2D, or rectangular prisms in 3D) the location of
83  /// a point in the mesh is simpler than in a more complex mesh
84  virtual void pml_locate_zeta(const Vector<double>& x,
85  FiniteElement*& el_pt)=0;
86  };
87 
88 //====================================================================
89 /// PML mesh class. Policy class for 2D PML meshes
90 //====================================================================
91  template<class ELEMENT>
92  class PMLQuadMeshBase : public RectangularQuadMesh<ELEMENT>,
93  public PMLMeshBase
94  {
95  public:
96 
97  /// \short Constructor: Create the underlying rectangular quad mesh
98  PMLQuadMeshBase(const unsigned& n_pml_x, const unsigned& n_pml_y,
99  const double& x_pml_start, const double& x_pml_end,
100  const double& y_pml_start, const double& y_pml_end,
101  TimeStepper* time_stepper_pt=&Mesh::Default_TimeStepper) :
102  RectangularQuadMesh<ELEMENT>(n_pml_x,n_pml_y,
103  x_pml_start,x_pml_end,
104  y_pml_start,y_pml_end,
105  time_stepper_pt)
106  {}
107 
108  /// \short Overloaded function to allow the user to locate an element
109  /// in mesh given the (Eulerian) position of a point. Note, the result
110  /// may be nonunique if the given point lies on the boundary of two
111  /// elements in the mesh. Additionally, we assume that the PML mesh is
112  /// axis aligned when deciding if the given point lies inside the mesh
114  FiniteElement*& coarse_mesh_el_pt)
115  {
116  //------------------------------------------
117  // Make sure the point lies inside the mesh:
118  //------------------------------------------
119  // Get the lower x limit of the mesh
120  const double x_min=this->x_min();
121 
122  // Get the upper x limit of the mesh
123  const double x_max=this->x_max();
124 
125  // Get the lower y limit of the mesh
126  const double y_min=this->y_min();
127 
128  // Get the upper y limit of the mesh
129  const double y_max=this->y_max();
130 
131  // Due to roundoff error we will choose a small tolerance which will be
132  // used to determine whether or not the point lies in the mesh
133  double tol=1.0e-12;
134 
135  // Assuming the mesh is axis-aligned we merely need to check if the
136  // x-coordinate of the input lies in the range [x_min,x_max] and the
137  // y-coordinate of the input lies in the range [y_min,y_max]
138  if ((x[0]<x_min-tol)||(x[0]>x_max+tol)||(x[1]<y_min-tol)||(x[1]>y_max+tol))
139  {
140  // Open an output string stream
141  std::ostringstream error_message_stream;
142 
143  // Create an error message
144  error_message_stream << "Point does not lie in the mesh." << std::endl;
145 
146  // Throw the error message
147  throw OomphLibError(error_message_stream.str(),
148  OOMPH_CURRENT_FUNCTION,
149  OOMPH_EXCEPTION_LOCATION);
150  }
151 
152  //-----------------------------------------
153  // Collect some information about the mesh:
154  //-----------------------------------------
155  // Find out how many elements there are in the x-direction
156  const unsigned nx=this->nx();
157 
158  // Find out how many elements there are in the y-direction
159  const unsigned ny=this->ny();
160 
161  // Find out how many nodes there are in one direction in each element
162  unsigned nnode_1d=this->finite_element_pt(0)->nnode_1d();
163 
164  // Find out how many nodes there are in each element
165  unsigned nnode=this->finite_element_pt(0)->nnode();
166 
167  // Create a pointer to store the element pointer as a FiniteElement
168  FiniteElement* el_pt=0;
169 
170  // Vector to store the coordinate of each element corner node which
171  // lies on the bottom boundary of the mesh and varies, i.e. if we're
172  // on the bottom boundary of the PML mesh then the y-coordinate will
173  // be fixed therefore we need only store the x-coordinates of the
174  // corner nodes of each element attached to this boundary
175  Vector<double> bottom_boundary_x_coordinates(nx+1,0.0);
176 
177  // Vector to store the coordinate of each element corner node which lies
178  // on the right boundary of the mesh and varies
179  Vector<double> right_boundary_y_coordinates(ny+1,0.0);
180 
181  // Recall, we already know the start and end coordinates of the mesh
182  // in the x-direction so we can assign these entries straight away.
183  // Note, these values are exactly the same as those had we instead
184  // considered the upper boundary so it is only necessary to store
185  // the information of the one of these boundaries. A similar argument
186  // holds for the left and right boundaries.
187 
188  // The first entry of bottom_boundary_x_coordinates is:
189  bottom_boundary_x_coordinates[0]=x_min;
190 
191  // The last entry is:
192  bottom_boundary_x_coordinates[nx]=x_max;
193 
194  // The first entry of right_boundary_y_coordinates is:
195  right_boundary_y_coordinates[0]=y_min;
196 
197  // The last entry is:
198  right_boundary_y_coordinates[ny]=y_max;
199 
200  // To collect the remaining entries we need to loop over all of the
201  // elements on the bottom boundary and collect the x-coordinate of
202  // the bottom right node in the element. To avoid assigning the
203  // last entry twice we ignore the last element.
204 
205  // Store the lower boundary ID
206  unsigned lower_boundary_id=0;
207 
208  // Store the right boundary ID
209  unsigned right_boundary_id=1;
210 
211  // Loop over the elements on the bottom boundary
212  for (unsigned i=0;i<nx;i++)
213  {
214  // Assign the element pointer
215  el_pt=this->boundary_element_pt(lower_boundary_id,i);
216 
217  // Store the x-coordinate of the bottom right node in this element
218  bottom_boundary_x_coordinates[i+1]=el_pt->node_pt(nnode_1d-1)->x(0);
219  }
220 
221  // To collect the remaining entries we need to loop over all of the
222  // elements on the right boundary and collect the y-coordinate of
223  // the top right node in the element. To avoid assigning the
224  // last entry twice we ignore the last element.
225 
226  // Loop over the elements on the bottom boundary
227  for (unsigned i=0;i<ny;i++)
228  {
229  // Assign the element pointer
230  el_pt=this->boundary_element_pt(right_boundary_id,i);
231 
232  // Store the y-coordinate of the top right node in this element
233  right_boundary_y_coordinates[i+1]=el_pt->node_pt(nnode-1)->x(1);
234  }
235 
236  //---------------------------
237  // Find the matching element:
238  //---------------------------
239  // Boolean variable to indicate that the ID of the element in the
240  // x-direction has been found. Note, the value of this ID must lie
241  // in the range [0,nx]
242  bool element_x_id_has_been_found=false;
243 
244  // Boolean variable to indicate that the ID of the element in the
245  // y-direction has been found. Note, the value of this ID must lie
246  // in the range [0,ny]
247  bool element_y_id_has_been_found=false;
248 
249  // Initialise the ID of the element in the x-direction
250  unsigned element_x_id=0;
251 
252  // Initialise the ID of the element in the y-direction
253  unsigned element_y_id=0;
254 
255  // Loop over all of the entries in bottom_boundary_x_coordinates
256  for (unsigned i=0;i<nx;i++)
257  {
258  // Check if the x-coordinate of the input lies in this interval
259  if ((x[0]>=bottom_boundary_x_coordinates[i])&&
260  (x[0]<=bottom_boundary_x_coordinates[i+1]))
261  {
262  // The point lies in the i-th interval so the element ID is i
263  element_x_id=i;
264 
265  // Indicate that the element ID has been found
266  element_x_id_has_been_found=true;
267  }
268  } // for (unsigned i=0;i<nx;i++)
269 
270  // If the element ID hasn't been found
271  if (!element_x_id_has_been_found)
272  {
273  // Open an output string stream
274  std::ostringstream error_message_stream;
275 
276  // Create an error message
277  error_message_stream << "The ID of the element in the x-direction "
278  << "has not been found." << std::endl;
279 
280  // Throw the error message
281  throw OomphLibError(error_message_stream.str(),
282  OOMPH_CURRENT_FUNCTION,
283  OOMPH_EXCEPTION_LOCATION);
284  }
285 
286  // Loop over all of the entries in right_boundary_y_coordinates
287  for (unsigned i=0;i<ny;i++)
288  {
289  // Check if the y-coordinate of the input lies in this interval
290  if ((x[1]>=right_boundary_y_coordinates[i])&&
291  (x[1]<=right_boundary_y_coordinates[i+1]))
292  {
293  // The point lies in the i-th interval so the element ID is i
294  element_y_id=i;
295 
296  // Indicate that the element ID has been found
297  element_y_id_has_been_found=true;
298  }
299  } // for (unsigned i=0;i<ny;i++)
300 
301  // If the element ID hasn't been found
302  if (!element_y_id_has_been_found)
303  {
304  // Open an output string stream
305  std::ostringstream error_message_stream;
306 
307  // Create an error message
308  error_message_stream << "The ID of the element in the y-direction "
309  << "has not been found." << std::endl;
310 
311  // Throw the error message
312  throw OomphLibError(error_message_stream.str(),
313  OOMPH_CURRENT_FUNCTION,
314  OOMPH_EXCEPTION_LOCATION);
315  }
316 
317  // Calculate the element number in the mesh
318  unsigned el_id=element_y_id*nx+element_x_id;
319 
320  // Set the pointer to this element
321  coarse_mesh_el_pt=dynamic_cast<FiniteElement*>(this->element_pt(el_id));
322  } // End of pml_locate_zeta
323  };
324 
325 //====================================================================
326 /// PML mesh, derived from RectangularQuadMesh.
327 //====================================================================
328  template<class ELEMENT>
329  class PMLQuadMesh : public PMLQuadMeshBase<ELEMENT>
330  {
331 
332  public:
333 
334  /// \short Constructor: Pass pointer to "bulk" mesh,
335  /// the boundary ID of axis aligned boundary to which the
336  /// mesh is supposed to be attached and the boundary ID in the
337  /// rectangular quad mesh that contains the pml elements.
338  /// 0: constant y, bulk mesh below;
339  /// 1: constant x, bulk mesh to the right;
340  /// 2: constant y, bulk mesh above;
341  /// 3: constant x, bulk mesh to left.
342  PMLQuadMesh(Mesh* bulk_mesh_pt,
343  const unsigned& boundary_id, const unsigned& quad_boundary_id,
344  const unsigned& n_pml_x, const unsigned& n_pml_y,
345  const double& x_pml_start, const double& x_pml_end,
346  const double& y_pml_start, const double& y_pml_end,
347  TimeStepper* time_stepper_pt=&Mesh::Default_TimeStepper) :
348  PMLQuadMeshBase<ELEMENT>(n_pml_x,n_pml_y,
349  x_pml_start,x_pml_end,
350  y_pml_start,y_pml_end,
351  time_stepper_pt)
352  {
353  unsigned n_boundary_node = bulk_mesh_pt -> nboundary_node(boundary_id);
354 
355  // Create a vector of ordered boundary nodes
356  Vector<Node*> ordered_boundary_node_pt(n_boundary_node);
357 
358  // Fill the vector with the nodes on the respective boundary
359  for (unsigned n=0; n<n_boundary_node; n++)
360  {
361  ordered_boundary_node_pt[n] =
362  bulk_mesh_pt -> boundary_node_pt(boundary_id, n);
363  }
364 
365  /// Sort them depending on the boundary being used
366 
367  // Right boundary
368  if (quad_boundary_id == 3)
369  {
370  std::sort(ordered_boundary_node_pt.begin(),
371  ordered_boundary_node_pt.end(),
373  }
374 
375  /// Top boundary
376  if (quad_boundary_id == 0)
377  {
378  std::sort(ordered_boundary_node_pt.begin(),
379  ordered_boundary_node_pt.end(),
381  }
382 
383  /// Left boundary
384  if (quad_boundary_id == 1)
385  {
386  std::sort(ordered_boundary_node_pt.begin(),
387  ordered_boundary_node_pt.end(),
389  }
390 
391  /// Bottom boundary
392  if (quad_boundary_id == 2)
393  {
394  std::sort(ordered_boundary_node_pt.begin(),
395  ordered_boundary_node_pt.end(),
397  }
398 
399  unsigned nnode_1d = this->finite_element_pt(0)->nnode_1d();
400 
401  /// \short Simple interior node numbering helpers
402  /// to be precomputed before the main loop
403 
404  /// Top left node in element
405  unsigned interior_node_nr_helper_1 = nnode_1d * (nnode_1d - 1);
406  /// Lower right node in element
407  unsigned interior_node_nr_helper_2 = nnode_1d - 1;
408  /// Used to find nodes in top row
409  unsigned interior_node_nr_helper_3 = nnode_1d * (nnode_1d - 1) - 1;
410 
411  /// \short Set all nodes from the PML mesh that must disappear
412  /// after merging as obsolete
413  unsigned nnod = this -> nboundary_node(quad_boundary_id);
414  for (unsigned j=0;j<nnod;j++)
415  {
416  this -> boundary_node_pt(quad_boundary_id,j)->set_obsolete();
417  }
418 
419  // Kill the obsolete nodes
420  this -> prune_dead_nodes();
421 
422  // Find the number of elements inside the PML mesh
423  unsigned n_pml_element = this -> nelement();
424 
425  /// Simple interior element numbering helpers
426 
427  /// Last element in mesh (top right)
428  unsigned interior_element_nr_helper_1 = n_pml_element-1;
429 
430 
431  // Connect the elements in the pml mesh to the ones
432  // in the triangular mesh at element level
433  unsigned count = 0;
434 
435  // Each boundary requires a specific treatment
436  // Right boundary
437  if (quad_boundary_id == 3) {
438  for(unsigned e=0; e<n_pml_element; e++)
439  {
440  // If element is on the right boundary
441  if ((e % n_pml_x) == 0)
442  {
443  // Upcast from GeneralisedElement to bulk element
444  ELEMENT *el_pt = dynamic_cast<ELEMENT* >(
445  this -> element_pt(e));
446 
447  // Loop over all nodes in element
448  unsigned n_node = el_pt -> nnode();
449  for (unsigned inod = 0; inod<n_node; inod++)
450  {
451  if (inod % nnode_1d == 0 )
452  {
453  // Get the pointer from the triangular mesh
454  el_pt->node_pt(inod) = ordered_boundary_node_pt[count];
455  count++;
456 
457  // Node between two elements
458  if (inod == interior_node_nr_helper_1) {count--;}
459  }
460  }
461  }
462  }
463  }
464 
465  // Top boundary
466  if (quad_boundary_id == 0) {
467  for(unsigned e=0; e<n_pml_element; e++)
468  {
469  // If element is on the right boundary
470  if ((int)(e / n_pml_x) == 0)
471  {
472  // Upcast from GeneralisedElement to bulk element
473  ELEMENT *el_pt = dynamic_cast<ELEMENT* >(
474  this -> element_pt(e));
475 
476  // Loop over all nodes in element
477  unsigned n_node = el_pt -> nnode();
478  for (unsigned inod = 0; inod<n_node; inod++)
479  {
480  if ((int) (inod / nnode_1d) == 0 )
481  {
482  // Get the pointer from the triangular mesh
483  el_pt->node_pt(inod) = ordered_boundary_node_pt[count];
484  count++;
485 
486  // Node between two elements
487  if (inod == interior_node_nr_helper_2) {count--;}
488  }
489  }
490  }
491  }
492  }
493 
494  // Left boundary
495  if (quad_boundary_id == 1) {
496  for(unsigned e=interior_element_nr_helper_1; e < n_pml_element; e--)
497  {
498  // If element is on the right boundary
499  if ((e % n_pml_x) == (n_pml_x-1))
500  {
501  // Upcast from GeneralisedElement to bulk element
502  ELEMENT *el_pt = dynamic_cast<ELEMENT* >(
503  this -> element_pt(e));
504 
505  // Loop over all nodes in element
506  unsigned n_node = el_pt -> nnode();
507  unsigned starter = n_node-1;
508  for (unsigned inod = starter; inod<=starter; inod--)
509  {
510  if (inod % nnode_1d == interior_node_nr_helper_2 )
511  {
512  // Get the pointer from the triangular mesh
513  el_pt->node_pt(inod) = ordered_boundary_node_pt[count];
514  count++;
515 
516  // Node between two elements
517  if (inod == interior_node_nr_helper_2) {count--;}
518  }
519  }
520  }
521  }
522  }
523 
524  // Bottom boundary
525  if (quad_boundary_id == 2) {
526  for(unsigned e=interior_element_nr_helper_1; e < n_pml_element; e--)
527  {
528  // If element is on the top boundary
529  if (e >= (n_pml_x*(n_pml_y-1)))
530  {
531  // Upcast from GeneralisedElement to bulk element
532  ELEMENT *el_pt = dynamic_cast<ELEMENT* >(
533  this -> element_pt(e));
534 
535  // Loop over all nodes in element
536  unsigned n_node = el_pt -> nnode();
537  unsigned starter = n_node-1;
538  for (unsigned inod = starter; inod<=starter; inod--)
539  {
540  if (inod > interior_node_nr_helper_3 )
541  {
542  // Get the pointer from the triangular mesh
543  el_pt->node_pt(inod) = ordered_boundary_node_pt[count];
544  count++;
545 
546  // Node between two elements
547  if (inod == interior_node_nr_helper_1) {count--;}
548  }
549  }
550  }
551  }
552  }
553 
554  /// \short The alignment is done individually for each boundary
555  /// and depends on the ordering of the nodes, in this case of the
556  /// RectangularQuadMesh<2,3> for each boundary. There are operations
557  /// with mod and div 3 necessary in this case, as well as specific
558  /// mechanisms to loop over the boundary in a certain way in order
559  /// to obtain the convenient coordinates.
560 
561  // Loop over all elements and make sure the coordinates are aligned
562  for(unsigned e=0; e<n_pml_element; e++)
563  {
564  // Upcast from GeneralisedElement to bulk element
565  ELEMENT *el_pt =
566  dynamic_cast<ELEMENT* >(this -> element_pt(e));
567  unsigned n_node = el_pt -> nnode();
568 
569  // Loop over all nodes in element
570  double temp_coordinate = 0.0;
571  for (unsigned inod = 0; inod<n_node; inod++)
572  {
573  // Check if we are looking at the left boundary of the quad mesh
574  if (quad_boundary_id == 3) {
575  // If it is one of the ones on the left boundary
576  if (inod % nnode_1d == 0)
577  {
578  // Get the y-coordinate of the leftmost node in that element
579  temp_coordinate = el_pt -> node_pt(inod) -> x(1);
580  }
581 
582  // Each node's y-coordinate is reset to be the one of the leftmost
583  // node in that element on its x-coordinate
584  el_pt -> node_pt(inod) -> x(1) = temp_coordinate;
585  }
586  // End of left quad boundary check
587 
588  // Check if we are looking at the top boundary of the quad mesh
589  if (quad_boundary_id == 0) {
590  // If it is one of the ones on the bottom boundary
591  if (inod > interior_node_nr_helper_2)
592  {
593  // Get the y-coordinate of the leftmost node in that element
594  el_pt -> node_pt(inod) -> x(0) =
595  el_pt -> node_pt(inod - nnode_1d) -> x(0);
596  }
597  }
598  // End of top quad boundary check
599  }
600  }
601 
602  for(unsigned e=interior_element_nr_helper_1; e<n_pml_element; e--)
603  {
604  // Upcast from GeneralisedElement to bulk element
605  ELEMENT *el_pt =
606  dynamic_cast<ELEMENT* >(this -> element_pt(e));
607  unsigned n_node = el_pt -> nnode();
608 
609  // Loop over all nodes in element
610  double temp_coordinate = 0.0;
611  unsigned starter = n_node-1;
612  for (unsigned inod = starter; inod <= starter; inod--)
613  {
614  // Check if we are looking at the right boundary of the quad mesh
615  if (quad_boundary_id == 1) {
616  // If it is one of the ones on the left boundary
617  if (inod % nnode_1d == interior_node_nr_helper_2)
618  {
619  // Get the y-coordinate of the leftmost node in that element
620  temp_coordinate = el_pt -> node_pt(inod) -> x(1);
621  }
622 
623  // Each node's y-coordinate is reset to be the one of the leftmost
624  // node in that element on its x-coordinate
625  el_pt -> node_pt(inod) -> x(1) = temp_coordinate;
626  }
627  // End of right quad boundary check
628 
629  // Check if we are looking at the top boundary of the quad mesh
630  if (quad_boundary_id == 2) {
631  // If it is one of the ones on the bottom boundary
632  if (inod < interior_node_nr_helper_1)
633  {
634  // Get the y-coordinate of the leftmost node in that element
635  el_pt -> node_pt(inod) -> x(0) =
636  el_pt -> node_pt(inod + nnode_1d) -> x(0);
637  }
638 
639  }
640  // End of top quad boundary check
641  }
642  }
643  // End of alignment
644  }
645  };
646 
647 
648 
649 //////////////////////////////////////////////////////////////////////
650 //////////////////////////////////////////////////////////////////////
651 //////////////////////////////////////////////////////////////////////
652 
653 
654 //====================================================================
655 /// PML mesh, derived from RectangularQuadMesh.
656 //====================================================================
657  template<class ELEMENT>
658  class PMLCornerQuadMesh : public PMLQuadMeshBase<ELEMENT>
659  {
660  public:
661 
662  /// \short Constructor: Pass pointer to "bulk" mesh
663  /// and the two existing PML meshes in order to construct the corner
664  /// PML mesh in between them based on their element number
665  /// and coordinates.
666  PMLCornerQuadMesh(Mesh* PMLQuad_mesh_x_pt,
667  Mesh* PMLQuad_mesh_y_pt,
668  Mesh* bulk_mesh_pt,
669  Node* special_corner_node_pt,
670  const unsigned& parent_boundary_x_id,
671  const unsigned& parent_boundary_y_id,
672  const unsigned& current_boundary_x_id,
673  const unsigned& current_boundary_y_id,
674  const unsigned& n_pml_x, const unsigned& n_pml_y,
675  const double& x_pml_start, const double& x_pml_end,
676  const double& y_pml_start, const double& y_pml_end,
677  TimeStepper* time_stepper_pt=&Mesh::Default_TimeStepper) :
678  PMLQuadMeshBase<ELEMENT>(n_pml_x,n_pml_y,
679  x_pml_start,x_pml_end,
680  y_pml_start,y_pml_end,
681  time_stepper_pt)
682  {
683  unsigned nnode_1d = this->finite_element_pt(0)->nnode_1d();
684 
685  /// \short Simple interior node numbering helpers
686  /// to be precomputed before the main loop
687 
688  /// Top left node in element
689  unsigned interior_node_nr_helper_1 = nnode_1d * (nnode_1d - 1);
690  /// Lower right node in element
691  unsigned interior_node_nr_helper_2 = nnode_1d - 1;
692  /// Top right node in element
693  unsigned interior_node_nr_helper_3 = nnode_1d * nnode_1d - 1;
694 
695  // Set up top right corner element
696  //--------------------------------
697  if ((parent_boundary_x_id == 2) && (parent_boundary_y_id == 1)){
698 
699  // Get the number of nodes to be connected on the horizontal boundary
700  unsigned n_boundary_x_node =
701  PMLQuad_mesh_x_pt -> nboundary_node(parent_boundary_x_id);
702 
703  // Create a vector of ordered boundary nodes
704  Vector<Node*> ordered_boundary_x_node_pt(n_boundary_x_node);
705 
706  // Fill the vector with the nodes on the respective boundary
707  for (unsigned n=0; n<n_boundary_x_node; n++)
708  {
709  ordered_boundary_x_node_pt[n] =
710  PMLQuad_mesh_x_pt -> boundary_node_pt(parent_boundary_x_id, n);
711  }
712 
713  // Sort them from lowest to highest (in x coordinate)
714  if (parent_boundary_x_id == 2)
715  {
716  std::sort(ordered_boundary_x_node_pt.begin(),
717  ordered_boundary_x_node_pt.end(),
719  }
720 
721  // Get the number of nodes to be connected on the vertical boundary
722  unsigned n_boundary_y_node =
723  PMLQuad_mesh_y_pt -> nboundary_node(parent_boundary_y_id);
724 
725  // Create a vector of ordered boundary nodes
726  Vector<Node*> ordered_boundary_y_node_pt(n_boundary_y_node);
727 
728  // Fill the vector with the nodes on the respective boundary
729  for (unsigned n=0; n<n_boundary_y_node; n++)
730  {
731  ordered_boundary_y_node_pt[n] =
732  PMLQuad_mesh_y_pt -> boundary_node_pt(parent_boundary_y_id, n);
733  }
734 
735  // Sort them
736  if (parent_boundary_y_id == 1)
737  {
738  std::sort(ordered_boundary_y_node_pt.begin(),
739  ordered_boundary_y_node_pt.end(),
741  }
742 
743  unsigned x_nnod = this -> nboundary_node(current_boundary_x_id);
744  for (unsigned j=0;j<x_nnod;j++)
745  {
746  this -> boundary_node_pt(current_boundary_x_id,j)->set_obsolete();
747  }
748 
749  unsigned y_nnod = this -> nboundary_node(current_boundary_y_id);
750  for (unsigned j=0;j<y_nnod;j++)
751  {
752  this -> boundary_node_pt(current_boundary_y_id,j)->set_obsolete();
753  }
754 
755  // Kill the obsolete nodes
756  this -> prune_dead_nodes();
757 
758  unsigned n_pml_element = this -> nelement();
759 
760  // Connect the elements in the pml mesh to the ones
761  // in the triangular mesh at element level
762  unsigned count = 0;
763 
764  if (parent_boundary_y_id == 1) {
765  for(unsigned e=0; e<n_pml_element; e++)
766  {
767  // If element is on the right boundary
768  if ((e % n_pml_x) == 0)
769  {
770  // Upcast from GeneralisedElement to bulk element
771  ELEMENT *el_pt = dynamic_cast<ELEMENT* >(
772  this -> element_pt(e));
773 
774  // Loop over all nodes in element
775  unsigned n_node = el_pt -> nnode();
776  for (unsigned inod = 0; inod<n_node; inod++)
777  {
778  // If it is one of the ones on the left boundary
779  if (e==0)
780  {
781  if (inod==0) el_pt->node_pt(inod) = special_corner_node_pt;
782  if ((inod % nnode_1d == 0) && (inod>0)) {
783 
784  // Get the pointer from the triangular mesh
785  el_pt->node_pt(inod) = ordered_boundary_y_node_pt[count];
786  count++;
787 
788  // Node between two elements
789  if (inod == interior_node_nr_helper_1) {count--;}
790  }
791  }
792  else
793  {
794  if ((inod % nnode_1d) == 0){
795  // Get the pointer from the triangular mesh
796  el_pt->node_pt(inod) = ordered_boundary_y_node_pt[count];
797  count++;
798 
799  // Node between two elements
800  if (inod == interior_node_nr_helper_1) {count--;}
801  }
802  }
803  }
804  }
805  }
806  }
807 
808  count = 0;
809 
810  if (parent_boundary_x_id == 2) {
811  for(unsigned e=0; e<n_pml_element; e++)
812  {
813  // If element is on the right boundary
814  if ((int)(e / n_pml_x) == 0)
815  {
816  // Upcast from GeneralisedElement to bulk element
817  ELEMENT *el_pt = dynamic_cast<ELEMENT* >(
818  this -> element_pt(e));
819 
820  // Loop over all nodes in element
821  unsigned n_node = el_pt -> nnode();
822  for (unsigned inod = 0; inod<n_node; inod++)
823  {
824  if (e==0){
825  if (((int) (inod / nnode_1d) == 0 ) && (inod > 0))
826  {
827  // Get the pointer from the triangular mesh
828  el_pt->node_pt(inod) = ordered_boundary_x_node_pt[count];
829  count++;
830 
831  // Node between two elements
832  if (inod == interior_node_nr_helper_2) {count--;}
833  }
834  } else
835  {
836  if ((int) (inod / nnode_1d) == 0 )
837  {
838  // Get the pointer from the triangular mesh
839  el_pt->node_pt(inod) = ordered_boundary_x_node_pt[count];
840  count++;
841 
842  // Node between two elements
843  if (inod == interior_node_nr_helper_2) {count--;}
844  }
845  }
846  }
847  }
848  }
849  }
850  }
851 
852  // Set up bottom right corner element
853  //--------------------------------
854  if ((parent_boundary_x_id == 0) && (parent_boundary_y_id == 1)){
855  // Get the number of nodes to be connected on the horizontal boundary
856  unsigned n_boundary_x_node =
857  PMLQuad_mesh_x_pt -> nboundary_node(parent_boundary_x_id);
858 
859  // Create a vector of ordered boundary nodes
860  Vector<Node*> ordered_boundary_x_node_pt(n_boundary_x_node);
861 
862  // Fill the vector with the nodes on the respective boundary
863  for (unsigned n=0; n<n_boundary_x_node; n++)
864  {
865  ordered_boundary_x_node_pt[n] =
866  PMLQuad_mesh_x_pt -> boundary_node_pt(parent_boundary_x_id, n);
867  }
868 
869  // Sort them from lowest to highest (in x coordinate)
870  if (parent_boundary_x_id == 0)
871  {
872  std::sort(ordered_boundary_x_node_pt.begin(),
873  ordered_boundary_x_node_pt.end(),
875  }
876 
877  // Get the number of nodes to be connected on the vertical boundary
878  unsigned n_boundary_y_node =
879  PMLQuad_mesh_y_pt -> nboundary_node(parent_boundary_y_id);
880 
881  // Create a vector of ordered boundary nodes
882  Vector<Node*> ordered_boundary_y_node_pt(n_boundary_y_node);
883 
884  // Fill the vector with the nodes on the respective boundary
885  for (unsigned n=0; n<n_boundary_y_node; n++)
886  {
887  ordered_boundary_y_node_pt[n] =
888  PMLQuad_mesh_y_pt -> boundary_node_pt(parent_boundary_y_id, n);
889  }
890 
891  // Sort them
892  if (parent_boundary_y_id == 1)
893  {
894  std::sort(ordered_boundary_y_node_pt.begin(),
895  ordered_boundary_y_node_pt.end(),
897  }
898 
899  unsigned x_nnod = this -> nboundary_node(current_boundary_x_id);
900  for (unsigned j=0;j<x_nnod;j++)
901  {
902  this -> boundary_node_pt(current_boundary_x_id,j)->set_obsolete();
903  }
904 
905  unsigned y_nnod = this -> nboundary_node(current_boundary_y_id);
906  for (unsigned j=0;j<y_nnod;j++)
907  {
908  this -> boundary_node_pt(current_boundary_y_id,j)->set_obsolete();
909  }
910 
911  // Kill the obsolete nodes
912  this -> prune_dead_nodes();
913 
914  // Get the number of elements in the PML mesh
915  unsigned n_pml_element = this -> nelement();
916 
917  // Connect the elements in the pml mesh to the ones
918  // in the triangular mesh at element level
919  unsigned count = 0;
920 
921  if (parent_boundary_y_id == 1) {
922  for(unsigned e=0; e<n_pml_element; e++)
923  {
924  // If element is on the right boundary
925  if ((e % n_pml_x) == 0)
926  {
927  // Upcast from GeneralisedElement to bulk element
928  ELEMENT *el_pt = dynamic_cast<ELEMENT* >(
929  this -> element_pt(e));
930 
931  // Loop over all nodes in element
932  unsigned n_node = el_pt -> nnode();
933  for (unsigned inod = 0; inod<n_node; inod++)
934  {
935  if (e==((n_pml_x) * (n_pml_y-1)))
936  {
937 
938  if (inod==interior_node_nr_helper_1) {
939  el_pt->node_pt(inod) = special_corner_node_pt;
940  }
941  if ((inod%nnode_1d == 0) && (inod<interior_node_nr_helper_1) ) {
942  // Get the pointer from the triangular mesh
943  el_pt->node_pt(inod) = ordered_boundary_y_node_pt[count];
944  count++;
945 
946  // Node between two elements
947  if (inod == interior_node_nr_helper_1) {count--;}
948  }
949  }
950  else
951  {
952  if ((inod % nnode_1d) == 0){
953  // Get the pointer from the triangular mesh
954  el_pt->node_pt(inod) = ordered_boundary_y_node_pt[count];
955  count++;
956 
957  // Node between two elements
958  if (inod == interior_node_nr_helper_1) {count--;}
959  }
960  }
961  }
962  }
963  }
964  }
965 
966  count = 0;
967 
968  if (parent_boundary_x_id == 0) {
969  for(unsigned e=0; e<n_pml_element; e++)
970  {
971  // If element is on the right boundary
972  if (e>=((n_pml_x-0) * (n_pml_y-1)))
973  {
974  // Upcast from GeneralisedElement to bulk element
975  ELEMENT *el_pt = dynamic_cast<ELEMENT* >(
976  this -> element_pt(e));
977 
978  // Loop over all nodes in element
979  unsigned n_node = el_pt -> nnode();
980  for (unsigned inod = 0; inod<n_node; inod++)
981  {
982  if (e==((n_pml_x) * (n_pml_y-1))){
983  if (((unsigned) (inod / nnode_1d) == interior_node_nr_helper_2 )
984  && (inod > interior_node_nr_helper_1))
985  {
986  // Get the pointer from the triangular mesh
987  el_pt->node_pt(inod) = ordered_boundary_x_node_pt[count];
988  count++;
989 
990  // Node between two elements
991  if (inod == interior_node_nr_helper_3) {count--;}
992  }
993  } else
994  {
995  if ((unsigned) (inod / nnode_1d) == interior_node_nr_helper_2 )
996  {
997  // Get the pointer from the triangular mesh
998  el_pt->node_pt(inod) = ordered_boundary_x_node_pt[count];
999  count++;
1000 
1001  // Node between two elements
1002  if (inod == interior_node_nr_helper_3) {count--;}
1003  }
1004  }
1005  }
1006  }
1007  }
1008  }
1009  }
1010 
1011  // Set up top left corner element
1012  //--------------------------------
1013  if ((parent_boundary_x_id == 2) && (parent_boundary_y_id == 3)){
1014  // Get the number of nodes to be connected on the horizontal boundary
1015  unsigned n_boundary_x_node =
1016  PMLQuad_mesh_x_pt -> nboundary_node(parent_boundary_x_id);
1017 
1018  // Create a vector of ordered boundary nodes
1019  Vector<Node*> ordered_boundary_x_node_pt(n_boundary_x_node);
1020 
1021  // Fill the vector with the nodes on the respective boundary
1022  for (unsigned n=0; n<n_boundary_x_node; n++)
1023  {
1024  ordered_boundary_x_node_pt[n] =
1025  PMLQuad_mesh_x_pt -> boundary_node_pt(parent_boundary_x_id, n);
1026  }
1027 
1028  // Sort them from lowest to highest (in x coordinate)
1029  if (parent_boundary_x_id == 2)
1030  {
1031  std::sort(ordered_boundary_x_node_pt.begin(),
1032  ordered_boundary_x_node_pt.end(),
1034  }
1035 
1036  // Get the number of nodes to be connected on the vertical boundary
1037  unsigned n_boundary_y_node =
1038  PMLQuad_mesh_y_pt -> nboundary_node(parent_boundary_y_id);
1039 
1040  // Create a vector of ordered boundary nodes
1041  Vector<Node*> ordered_boundary_y_node_pt(n_boundary_y_node);
1042 
1043  // Fill the vector with the nodes on the respective boundary
1044  for (unsigned n=0; n<n_boundary_y_node; n++)
1045  {
1046  ordered_boundary_y_node_pt[n] =
1047  PMLQuad_mesh_y_pt -> boundary_node_pt(parent_boundary_y_id, n);
1048  }
1049 
1050  // Sort them from lowest to highest (in x coordinate)
1051  if (parent_boundary_y_id == 1)
1052  {
1053  std::sort(ordered_boundary_y_node_pt.begin(),
1054  ordered_boundary_y_node_pt.end(),
1056  }
1057 
1058  unsigned x_nnod = this -> nboundary_node(current_boundary_x_id);
1059  for (unsigned j=0;j<x_nnod;j++)
1060  {
1061  this -> boundary_node_pt(current_boundary_x_id,j)->set_obsolete();
1062  }
1063 
1064  unsigned y_nnod = this -> nboundary_node(current_boundary_y_id);
1065  for (unsigned j=0;j<y_nnod;j++)
1066  {
1067  this -> boundary_node_pt(current_boundary_y_id,j)->set_obsolete();
1068  }
1069 
1070  // Kill the obsolete nodes
1071  this -> prune_dead_nodes();
1072 
1073  // Get the number of elements in the PML mesh
1074  unsigned n_pml_element = this -> nelement();
1075 
1076  // Connect the elements in the pml mesh to the ones
1077  // in the triangular mesh at element level
1078  unsigned count = 0;
1079 
1080  if (parent_boundary_y_id == 3) {
1081  for(unsigned e=0; e<n_pml_element; e++)
1082  {
1083  // If element is on the right boundary
1084  if ((e % n_pml_x) == (n_pml_x-1))
1085  {
1086  // Upcast from GeneralisedElement to bulk element
1087  ELEMENT *el_pt = dynamic_cast<ELEMENT* >(
1088  this -> element_pt(e));
1089 
1090  // Loop over all nodes in element
1091  unsigned n_node = el_pt -> nnode();
1092  for (unsigned inod = 0; inod<n_node; inod++)
1093  {
1094  if (e==(n_pml_x-1))
1095  {
1096  if (inod == interior_node_nr_helper_2)
1097  el_pt->node_pt(inod) = special_corner_node_pt;
1098  if ((inod % nnode_1d == interior_node_nr_helper_2)
1099  && (inod > (nnode_1d - 1))) {
1100 
1101  // Get the pointer from the triangular mesh
1102  el_pt->node_pt(inod) = ordered_boundary_y_node_pt[count];
1103  count++;
1104 
1105  // Node between two elements
1106  if (inod == interior_node_nr_helper_3) {count--;}
1107  }
1108  }
1109  else
1110  {
1111  if ((inod % nnode_1d) == interior_node_nr_helper_2){
1112  // Get the pointer from the triangular mesh
1113  el_pt->node_pt(inod) = ordered_boundary_y_node_pt[count];
1114  count++;
1115 
1116  // Node between two elements
1117  if (inod == interior_node_nr_helper_3) {count--;}
1118  }
1119  }
1120  }
1121  }
1122  }
1123  }
1124 
1125  count = 0;
1126 
1127  if (parent_boundary_x_id == 2) {
1128  for(unsigned e=0; e<n_pml_element; e++)
1129  {
1130  // If element is on the right boundary
1131  if ((int)(e / n_pml_x) == 0)
1132  {
1133  // Upcast from GeneralisedElement to bulk element
1134  ELEMENT *el_pt = dynamic_cast<ELEMENT* >(
1135  this -> element_pt(e));
1136 
1137  // Loop over all nodes in element
1138  unsigned n_node = el_pt -> nnode();
1139  for (unsigned inod = 0; inod<n_node; inod++)
1140  {
1141  // If it is one of the ones on the left boundary
1142  if (e==(n_pml_x-1)){
1143  if (((int) (inod / nnode_1d) == 0 )
1144  && (inod < interior_node_nr_helper_2))
1145  {
1146  // Get the pointer from the triangular mesh
1147  el_pt->node_pt(inod) = ordered_boundary_x_node_pt[count];
1148  count++;
1149 
1150  // Node between two elements
1151  if (inod == (nnode_1d - 1)) {count--;}
1152  }
1153  } else
1154  {
1155  if ((int) (inod / nnode_1d) == 0 )
1156  {
1157  // Get the pointer from the triangular mesh
1158  el_pt->node_pt(inod) = ordered_boundary_x_node_pt[count];
1159  count++;
1160 
1161  // Node between two elements
1162  if (inod == interior_node_nr_helper_2) {count--;}
1163  }
1164  }
1165  }
1166  }
1167  }
1168  }
1169  }
1170 
1171  // Set up bottom left corner element
1172  //--------------------------------
1173  if ((parent_boundary_x_id == 0) && (parent_boundary_y_id == 3)){
1174  // Get the number of nodes to be connected on the horizontal boundary
1175  unsigned n_boundary_x_node =
1176  PMLQuad_mesh_x_pt -> nboundary_node(parent_boundary_x_id);
1177 
1178  // Create a vector of ordered boundary nodes
1179  Vector<Node*> ordered_boundary_x_node_pt(n_boundary_x_node);
1180 
1181  // Fill the vector with the nodes on the respective boundary
1182  for (unsigned n=0; n<n_boundary_x_node; n++)
1183  {
1184  ordered_boundary_x_node_pt[n] =
1185  PMLQuad_mesh_x_pt -> boundary_node_pt(parent_boundary_x_id, n);
1186  }
1187 
1188  // Sort them
1189  if (parent_boundary_x_id == 0)
1190  {
1191  std::sort(ordered_boundary_x_node_pt.begin(),
1192  ordered_boundary_x_node_pt.end(),
1194  }
1195 
1196  // Get the number of nodes to be connected on the vertical boundary
1197  unsigned n_boundary_y_node =
1198  PMLQuad_mesh_y_pt -> nboundary_node(parent_boundary_y_id);
1199 
1200  // Create a vector of ordered boundary nodes
1201  Vector<Node*> ordered_boundary_y_node_pt(n_boundary_y_node);
1202 
1203  // Fill the vector with the nodes on the respective boundary
1204  for (unsigned n=0; n<n_boundary_y_node; n++)
1205  {
1206  ordered_boundary_y_node_pt[n] =
1207  PMLQuad_mesh_y_pt -> boundary_node_pt(parent_boundary_y_id, n);
1208  }
1209 
1210  // Sort them
1211  if (parent_boundary_y_id == 3)
1212  {
1213  std::sort(ordered_boundary_y_node_pt.begin(),
1214  ordered_boundary_y_node_pt.end(),
1216  }
1217 
1218  unsigned x_nnod = this -> nboundary_node(current_boundary_x_id);
1219  for (unsigned j=0;j<x_nnod;j++)
1220  {
1221  this -> boundary_node_pt(current_boundary_x_id,j)->set_obsolete();
1222  }
1223 
1224  unsigned y_nnod = this -> nboundary_node(current_boundary_y_id);
1225  for (unsigned j=0;j<y_nnod;j++)
1226  {
1227  this -> boundary_node_pt(current_boundary_y_id,j)->set_obsolete();
1228  }
1229 
1230  // Kill the obsolete nodes
1231  this -> prune_dead_nodes();
1232 
1233  unsigned n_pml_element = this -> nelement();
1234 
1235  // Connect the elements in the pml mesh to the ones
1236  // in the triangular mesh at element level
1237  unsigned count = 0;
1238 
1239  if (parent_boundary_y_id == 3) {
1240  for(unsigned e=0; e<n_pml_element; e++)
1241  {
1242  // If element is on the right boundary
1243  if ((e % n_pml_x) == (n_pml_x-1))
1244  {
1245  // Upcast from GeneralisedElement to bulk element
1246  ELEMENT *el_pt = dynamic_cast<ELEMENT* >(
1247  this -> element_pt(e));
1248 
1249  // Loop over all nodes in element
1250  unsigned n_node = el_pt -> nnode();
1251  for (unsigned inod = 0; inod<n_node; inod++)
1252  {
1253  if (e==(n_pml_element-1))
1254  {
1255  if (inod == interior_node_nr_helper_3) {
1256  el_pt->node_pt(inod) = special_corner_node_pt;
1257  }
1258  if ((inod % nnode_1d == interior_node_nr_helper_2)
1259  && (inod < interior_node_nr_helper_3 )) {
1260 
1261  // Get the pointer from the triangular mesh
1262  el_pt->node_pt(inod) = ordered_boundary_y_node_pt[count];
1263  count++;
1264 
1265  // Node between two elements
1266  if (inod == interior_node_nr_helper_3) {count--;}
1267  }
1268  }
1269  else
1270  {
1271  if ((inod % nnode_1d) == interior_node_nr_helper_2){
1272  // Get the pointer from the triangular mesh
1273  el_pt->node_pt(inod) = ordered_boundary_y_node_pt[count];
1274  count++;
1275 
1276  // Node between two elements
1277  if (inod == interior_node_nr_helper_3) {count--;}
1278  }
1279  }
1280  }
1281  }
1282  }
1283  }
1284 
1285  count = 0;
1286 
1287  if (parent_boundary_x_id == 0) {
1288  for(unsigned e=0; e<n_pml_element; e++)
1289  {
1290  // If element is on the right boundary
1291  if (e>=((n_pml_x) * (n_pml_y-1)))
1292  {
1293  // Upcast from GeneralisedElement to bulk element
1294  ELEMENT *el_pt = dynamic_cast<ELEMENT* >(
1295  this -> element_pt(e));
1296 
1297  // Loop over all nodes in element
1298  unsigned n_node = el_pt -> nnode();
1299  for (unsigned inod = 0; inod<n_node; inod++)
1300  {
1301  if (e==(n_pml_element-1)){
1302  if (((unsigned) (inod / nnode_1d) == interior_node_nr_helper_2 )
1303  && (inod < interior_node_nr_helper_3))
1304  {
1305  // Get the pointer from the triangular mesh
1306  el_pt->node_pt(inod) = ordered_boundary_x_node_pt[count];
1307  count++;
1308 
1309  // Node between two elements
1310  if (inod == interior_node_nr_helper_3) {count--;}
1311  }
1312  } else
1313  {
1314  if ((unsigned) (inod / nnode_1d) == interior_node_nr_helper_2 )
1315  {
1316  // Get the pointer from the triangular mesh
1317  el_pt->node_pt(inod) = ordered_boundary_x_node_pt[count];
1318  count++;
1319 
1320  // Node between two elements
1321  if (inod == interior_node_nr_helper_3) {count--;}
1322  }
1323  }
1324  }
1325  }
1326  }
1327  }
1328  }
1329  }
1330  };
1331 
1332 ////////////////////////////////////////////////////////////////
1333 ////////////////////////////////////////////////////////////////
1334 ////////////////////////////////////////////////////////////////
1335 
1336 
1337 //===================================================================
1338 /// \short All helper routines for 2D bulk boundary mesh usage in order to
1339 /// generate PML meshes aligned to the main mesh
1340 //===================================================================
1341  namespace TwoDimensionalPMLHelper
1342  {
1343 
1344  //============================================================================
1345  /// "Constructor" for PML mesh,aligned with the right physical domain boundary
1346  //============================================================================
1347  template<class ASSOCIATED_PML_QUAD_ELEMENT>
1349  const unsigned& right_boundary_id,
1350  const unsigned& n_x_right_pml,
1351  const double& width_x_right_pml,
1352  TimeStepper* time_stepper_pt=
1354  {
1355  // Look at the right boundary of the triangular mesh
1356  unsigned n_right_boundary_node =
1357  bulk_mesh_pt -> nboundary_node(right_boundary_id);
1358 
1359  // Create a vector of ordered boundary nodes
1360  Vector<Node*> ordered_right_boundary_node_pt(n_right_boundary_node);
1361 
1362  // Fill the vector with the nodes on the respective boundary
1363  for (unsigned n=0; n<n_right_boundary_node; n++)
1364  {
1365  ordered_right_boundary_node_pt[n] =
1366  bulk_mesh_pt->boundary_node_pt(right_boundary_id,n);
1367  }
1368 
1369  // Sort them from lowest to highest (in y coordinate)
1370  std::sort(ordered_right_boundary_node_pt.begin(),
1371  ordered_right_boundary_node_pt.end(),
1373 
1374  // The number of elements in y is taken from the triangular mesh
1375  unsigned n_y_right_pml =
1376  bulk_mesh_pt -> nboundary_element(right_boundary_id);
1377 
1378  // Specific PML sizes needed, taken directly from physical domain
1379  double l_pml_right_x_start =
1380  ordered_right_boundary_node_pt[0] -> x(0);
1381  /// \short PML layer with added to the bulk mesh coordinate
1382  double l_pml_right_x_end =
1383  width_x_right_pml
1384  + ordered_right_boundary_node_pt[0] -> x(0);
1385  double l_pml_right_y_start =
1386  ordered_right_boundary_node_pt[0] -> x(1);
1387  double l_pml_right_y_end =
1388  ordered_right_boundary_node_pt[n_right_boundary_node-1] -> x(1);
1389 
1390  // Rectangular boundary id to be merged with triangular mesh
1391  unsigned right_quadPML_boundary_id = 3;
1392 
1393  // Create the mesh to be designated to the PML
1394  Mesh* pml_right_mesh_pt = 0;
1395 
1396  // Build the right one
1397  pml_right_mesh_pt=
1399  (bulk_mesh_pt, right_boundary_id, right_quadPML_boundary_id,
1400  n_x_right_pml, n_y_right_pml,
1401  l_pml_right_x_start, l_pml_right_x_end,
1402  l_pml_right_y_start, l_pml_right_y_end,
1403  time_stepper_pt);
1404 
1405  // Enable PML damping on the entire mesh
1406  unsigned n_element_pml_right = pml_right_mesh_pt->nelement();
1407  for(unsigned e=0;e<n_element_pml_right;e++)
1408  {
1409  // Upcast
1410  AxisAlignedPMLElement<2>* el_pt = dynamic_cast<AxisAlignedPMLElement<2>*>
1411  (pml_right_mesh_pt->element_pt(e));
1412  el_pt -> enable_pml(0, l_pml_right_x_start, l_pml_right_x_end);
1413  }
1414 
1415  // Get the values to be pinned from the first element (which we
1416  // assume exists!)
1417  AxisAlignedPMLElement<2>* el_pt = dynamic_cast<AxisAlignedPMLElement<2>*>
1418  (pml_right_mesh_pt->element_pt(0));
1419  Vector<unsigned> values_to_pin;
1420  el_pt->values_to_be_pinned_on_outer_pml_boundary(values_to_pin);
1421  unsigned npin=values_to_pin.size();
1422 
1423  // Exterior boundary needs to be set to Dirichlet 0
1424  // in both real and imaginary parts
1425  unsigned n_bound_pml_right = pml_right_mesh_pt->nboundary();
1426  for(unsigned b=0;b<n_bound_pml_right;b++)
1427  {
1428  unsigned n_node = pml_right_mesh_pt -> nboundary_node(b);
1429  for (unsigned n=0;n<n_node;n++)
1430  {
1431  Node* nod_pt=pml_right_mesh_pt -> boundary_node_pt(b,n);
1432  if (b==1)
1433  {
1434  for (unsigned j=0;j<npin;j++)
1435  {
1436  unsigned j_val=values_to_pin[j];
1437  nod_pt->pin(j_val);
1438  nod_pt->set_value(j_val,0.0);
1439  }
1440  }
1441  }
1442  }
1443 
1444  /// \short Return the finalized mesh, with PML enabled
1445  /// and boundary conditions added
1446  return pml_right_mesh_pt;
1447  }
1448 
1449  //===========================================================================
1450  /// "Constructor" for PML mesh, aligned with the top physical domain boundary
1451  //===========================================================================
1452  template<class ASSOCIATED_PML_QUAD_ELEMENT>
1454  const unsigned& top_boundary_id,
1455  const unsigned& n_y_top_pml,
1456  const double& width_y_top_pml,
1457  TimeStepper* time_stepper_pt=
1459  {
1460  // Look at the top boundary of the triangular mesh
1461  unsigned n_top_boundary_node =
1462  bulk_mesh_pt -> nboundary_node(top_boundary_id);
1463 
1464  // Create a vector of ordered boundary nodes
1465  Vector<Node*> ordered_top_boundary_node_pt(n_top_boundary_node);
1466 
1467  // Fill the vector with the nodes on the respective boundary
1468  for (unsigned n=0; n<n_top_boundary_node; n++)
1469  {
1470  ordered_top_boundary_node_pt[n] =
1471  bulk_mesh_pt->boundary_node_pt(top_boundary_id,n);
1472  }
1473 
1474  // Sort them from lowest to highest (in x coordinate)
1475  std::sort(ordered_top_boundary_node_pt.begin(),
1476  ordered_top_boundary_node_pt.end(),
1478 
1479  // The number of elements in x is taken from the triangular mesh
1480  unsigned n_x_top_pml = bulk_mesh_pt -> nboundary_element(top_boundary_id);
1481 
1482  // Specific PML sizes needed, taken directly from physical domain
1483  double l_pml_top_x_start =
1484  ordered_top_boundary_node_pt[0] -> x(0);
1485  double l_pml_top_x_end =
1486  ordered_top_boundary_node_pt[n_top_boundary_node-1] -> x(0);
1487  double l_pml_top_y_start =
1488  ordered_top_boundary_node_pt[0] -> x(1);
1489  /// \short PML layer width added to the bulk mesh coordinate
1490  double l_pml_top_y_end =
1491  width_y_top_pml
1492  + ordered_top_boundary_node_pt[0] -> x(1);
1493 
1494  unsigned top_quadPML_boundary_id = 0;
1495 
1496  // Create the mesh to be designated to the PML
1497  Mesh* pml_top_mesh_pt = 0;
1498 
1499  // Build the top PML mesh
1500  pml_top_mesh_pt=
1502  (bulk_mesh_pt, top_boundary_id, top_quadPML_boundary_id,
1503  n_x_top_pml, n_y_top_pml,
1504  l_pml_top_x_start, l_pml_top_x_end,
1505  l_pml_top_y_start, l_pml_top_y_end,
1506  time_stepper_pt);
1507 
1508  // Enable PML damping on the entire mesh
1509  unsigned n_element_pml_top = pml_top_mesh_pt->nelement();
1510  for(unsigned e=0;e<n_element_pml_top;e++)
1511  {
1512  // Upcast
1513  AxisAlignedPMLElement<2>* el_pt = dynamic_cast<AxisAlignedPMLElement<2>*>
1514  (pml_top_mesh_pt->element_pt(e));
1515  el_pt -> enable_pml(1, l_pml_top_y_start, l_pml_top_y_end);
1516  }
1517 
1518  // Get the values to be pinned from the first element (which we
1519  // assume exists!)
1520  AxisAlignedPMLElement<2>* el_pt = dynamic_cast<AxisAlignedPMLElement<2>*>
1521  (pml_top_mesh_pt->element_pt(0));
1522  Vector<unsigned> values_to_pin;
1523  el_pt->values_to_be_pinned_on_outer_pml_boundary(values_to_pin);
1524  unsigned npin=values_to_pin.size();
1525 
1526  // Exterior boundary needs to be set to Dirichlet 0
1527  // for both real and imaginary parts of all fields
1528  // in the problem
1529  unsigned n_bound_pml_top = pml_top_mesh_pt->nboundary();
1530  for(unsigned b=0;b<n_bound_pml_top;b++)
1531  {
1532  unsigned n_node = pml_top_mesh_pt -> nboundary_node(b);
1533  for (unsigned n=0;n<n_node;n++)
1534  {
1535  Node* nod_pt=pml_top_mesh_pt -> boundary_node_pt(b,n);
1536  if (b==2)
1537  {
1538  for (unsigned j=0;j<npin;j++)
1539  {
1540  unsigned j_val=values_to_pin[j];
1541  nod_pt->pin(j_val);
1542  nod_pt->set_value(j_val,0.0);
1543  }
1544  }
1545  }
1546  }
1547 
1548  /// \short Return the finalized mesh, with PML enabled
1549  /// and boundary conditions added
1550  return pml_top_mesh_pt;
1551  }
1552 
1553  //============================================================================
1554  /// "Constructor" for PML mesh, aligned with the left physical domain boundary
1555  //============================================================================
1556  template<class ASSOCIATED_PML_QUAD_ELEMENT>
1558  const unsigned& left_boundary_id,
1559  const unsigned& n_x_left_pml,
1560  const double& width_x_left_pml,
1561  TimeStepper* time_stepper_pt=
1563  {
1564  // Look at the left boundary of the triangular mesh
1565  unsigned n_left_boundary_node =
1566  bulk_mesh_pt -> nboundary_node(left_boundary_id);
1567 
1568  // Create a vector of ordered boundary nodes
1569  Vector<Node*> ordered_left_boundary_node_pt(n_left_boundary_node);
1570 
1571  // Fill the vector with the nodes on the respective boundary
1572  for (unsigned n=0; n<n_left_boundary_node; n++)
1573  {
1574  ordered_left_boundary_node_pt[n] =
1575  bulk_mesh_pt->boundary_node_pt(left_boundary_id,n);
1576  }
1577 
1578  // Sort them from lowest to highest (in y coordinate)
1579  std::sort(ordered_left_boundary_node_pt.begin(),
1580  ordered_left_boundary_node_pt.end(),
1582 
1583  // The number of elements in y is taken from the triangular mesh
1584  unsigned n_y_left_pml = bulk_mesh_pt -> nboundary_element(left_boundary_id);
1585 
1586  // Specific PML sizes needed, taken directly from physical domain
1587  /// \short PML layer width subtracted from left bulk mesh coordinate
1588  double l_pml_left_x_start =
1589  - width_x_left_pml
1590  + ordered_left_boundary_node_pt[n_left_boundary_node-1] -> x(0);
1591  double l_pml_left_x_end =
1592  ordered_left_boundary_node_pt[n_left_boundary_node-1] -> x(0);
1593  double l_pml_left_y_start =
1594  ordered_left_boundary_node_pt[n_left_boundary_node-1] -> x(1);
1595  double l_pml_left_y_end =
1596  ordered_left_boundary_node_pt[0] -> x(1);
1597 
1598  unsigned left_quadPML_boundary_id = 1;
1599 
1600  // Create the mesh to be designated to the PML
1601  Mesh* pml_left_mesh_pt = 0;
1602 
1603  // Build the left PML mesh
1604  pml_left_mesh_pt=
1606  (bulk_mesh_pt, left_boundary_id, left_quadPML_boundary_id,
1607  n_x_left_pml, n_y_left_pml,
1608  l_pml_left_x_start, l_pml_left_x_end,
1609  l_pml_left_y_start, l_pml_left_y_end,
1610  time_stepper_pt);
1611 
1612  // Enable PML damping on the entire mesh
1613  unsigned n_element_pml_left = pml_left_mesh_pt->nelement();
1614  for(unsigned e=0;e<n_element_pml_left;e++)
1615  {
1616  // Upcast
1617  AxisAlignedPMLElement<2>* el_pt = dynamic_cast<AxisAlignedPMLElement<2>*>
1618  (pml_left_mesh_pt->element_pt(e));
1619  el_pt -> enable_pml(0, l_pml_left_x_end, l_pml_left_x_start);
1620  }
1621 
1622  // Get the values to be pinned from the first element (which we
1623  // assume exists!)
1624  AxisAlignedPMLElement<2>* el_pt = dynamic_cast<AxisAlignedPMLElement<2>*>
1625  (pml_left_mesh_pt->element_pt(0));
1626  Vector<unsigned> values_to_pin;
1627  el_pt->values_to_be_pinned_on_outer_pml_boundary(values_to_pin);
1628  unsigned npin=values_to_pin.size();
1629 
1630  // Exterior boundary needs to be set to Dirichlet 0
1631  // for both real and imaginary parts of all fields
1632  // in the problem
1633  unsigned n_bound_pml_left = pml_left_mesh_pt->nboundary();
1634  for(unsigned b=0;b<n_bound_pml_left;b++)
1635  {
1636  unsigned n_node = pml_left_mesh_pt -> nboundary_node(b);
1637  for (unsigned n=0;n<n_node;n++)
1638  {
1639  Node* nod_pt=pml_left_mesh_pt -> boundary_node_pt(b,n);
1640  if (b==3)
1641  {
1642  for (unsigned j=0;j<npin;j++)
1643  {
1644  unsigned j_val=values_to_pin[j];
1645  nod_pt->pin(j_val);
1646  nod_pt->set_value(j_val,0.0);
1647  }
1648  }
1649  }
1650  }
1651 
1652  /// \short Return the finalized mesh, with PML enabled
1653  /// and boundary conditions added
1654  return pml_left_mesh_pt;
1655  }
1656 
1657  //============================================================================
1658  ///"Constructor" for PML mesh,aligned with the bottom physical domain boundary
1659  //============================================================================
1660  template<class ASSOCIATED_PML_QUAD_ELEMENT>
1662  const unsigned& bottom_boundary_id,
1663  const unsigned& n_y_bottom_pml,
1664  const double& width_y_bottom_pml,
1665  TimeStepper* time_stepper_pt=
1667  {
1668  // Look at the bottom boundary of the triangular mesh
1669  unsigned n_bottom_boundary_node =
1670  bulk_mesh_pt -> nboundary_node(bottom_boundary_id);
1671 
1672  // Create a vector of ordered boundary nodes
1673  Vector<Node*> ordered_bottom_boundary_node_pt(n_bottom_boundary_node);
1674 
1675  // Fill the vector with the nodes on the respective boundary
1676  for (unsigned n=0; n<n_bottom_boundary_node; n++)
1677  {
1678  ordered_bottom_boundary_node_pt[n] =
1679  bulk_mesh_pt->boundary_node_pt(bottom_boundary_id,n);
1680  }
1681 
1682  // Sort them from highest to lowest (in x coordinate)
1683  std::sort(ordered_bottom_boundary_node_pt.begin(),
1684  ordered_bottom_boundary_node_pt.end(),
1686 
1687  // The number of elements in y is taken from the triangular mesh
1688  unsigned n_x_bottom_pml =
1689  bulk_mesh_pt -> nboundary_element(bottom_boundary_id);
1690 
1691  // Specific PML sizes needed, taken directly from physical domain
1692  double l_pml_bottom_x_start =
1693  ordered_bottom_boundary_node_pt[n_bottom_boundary_node-1] -> x(0);
1694  double l_pml_bottom_x_end =
1695  ordered_bottom_boundary_node_pt[0] -> x(0);
1696  /// \short PML layer width subtracted from the bulk mesh lower
1697  /// boundary coordinate
1698  double l_pml_bottom_y_start =
1699  - width_y_bottom_pml
1700  + ordered_bottom_boundary_node_pt[0] -> x(1);
1701  double l_pml_bottom_y_end =
1702  ordered_bottom_boundary_node_pt[0] -> x(1);
1703 
1704  unsigned bottom_quadPML_boundary_id = 2;
1705 
1706  // Create the mesh to be designated to the PML
1707  Mesh* pml_bottom_mesh_pt = 0;
1708 
1709  // Build the bottom PML mesh
1710  pml_bottom_mesh_pt=
1712  (bulk_mesh_pt, bottom_boundary_id, bottom_quadPML_boundary_id,
1713  n_x_bottom_pml, n_y_bottom_pml,
1714  l_pml_bottom_x_start, l_pml_bottom_x_end,
1715  l_pml_bottom_y_start, l_pml_bottom_y_end,
1716  time_stepper_pt);
1717 
1718  // Enable PML damping on the entire mesh
1719  unsigned n_element_pml_bottom = pml_bottom_mesh_pt->nelement();
1720  for(unsigned e=0;e<n_element_pml_bottom;e++)
1721  {
1722  // Upcast
1723  AxisAlignedPMLElement<2>* el_pt = dynamic_cast<AxisAlignedPMLElement<2>*>
1724  (pml_bottom_mesh_pt->element_pt(e));
1725  el_pt -> enable_pml(1, l_pml_bottom_y_end, l_pml_bottom_y_start);
1726  }
1727 
1728  // Get the values to be pinned from the first element (which we
1729  // assume exists!)
1730  AxisAlignedPMLElement<2>* el_pt = dynamic_cast<AxisAlignedPMLElement<2>*>
1731  (pml_bottom_mesh_pt->element_pt(0));
1732  Vector<unsigned> values_to_pin;
1733  el_pt->values_to_be_pinned_on_outer_pml_boundary(values_to_pin);
1734  unsigned npin=values_to_pin.size();
1735 
1736  // Exterior boundary needs to be set to Dirichlet 0
1737  // for both real and imaginary parts of all fields
1738  // in the problem
1739  unsigned n_bound_pml_bottom = pml_bottom_mesh_pt->nboundary();
1740  for(unsigned b=0;b<n_bound_pml_bottom;b++)
1741  {
1742  unsigned n_node = pml_bottom_mesh_pt -> nboundary_node(b);
1743  for (unsigned n=0;n<n_node;n++)
1744  {
1745  Node* nod_pt=pml_bottom_mesh_pt -> boundary_node_pt(b,n);
1746  if (b==0)
1747  {
1748  for (unsigned j=0;j<npin;j++)
1749  {
1750  unsigned j_val=values_to_pin[j];
1751  nod_pt->pin(j_val);
1752  nod_pt->set_value(j_val,0.0);
1753  }
1754  }
1755  }
1756  }
1757 
1758  /// \short Return the finalized mesh, with PML enabled
1759  /// and boundary conditions added
1760  return pml_bottom_mesh_pt;
1761  }
1762 
1763 //==========================================================================
1764 /// \short "Constructor" for PML top right corner mesh,
1765 /// aligned with the existing PML meshes
1766 //==========================================================================
1767  template<class ASSOCIATED_PML_QUAD_ELEMENT>
1768  Mesh* create_top_right_pml_mesh(Mesh* pml_right_mesh_pt,
1769  Mesh* pml_top_mesh_pt,
1770  Mesh* bulk_mesh_pt,
1771  const unsigned& right_boundary_id,
1772  TimeStepper* time_stepper_pt=
1774  {
1775 
1776  /// \short Relevant boundary id's to be used in construction
1777  /// Parent id refers to already existing PML meshes
1778  unsigned parent_boundary_x_id = 2;
1779  unsigned parent_boundary_y_id = 1;
1780  // Current id refers to the mesh that is to be constructed
1781  unsigned current_boundary_x_id = 0;
1782  unsigned current_boundary_y_id = 3;
1783 
1784  // Look at the right boundary of the triangular mesh
1785  unsigned n_right_boundary_node =
1786  bulk_mesh_pt -> nboundary_node(right_boundary_id);
1787 
1788  // Create a vector of ordered boundary nodes
1789  Vector<Node*> ordered_right_boundary_node_pt(n_right_boundary_node);
1790 
1791  // Fill the vector with the nodes on the respective boundary
1792  for (unsigned n=0; n<n_right_boundary_node; n++)
1793  {
1794  ordered_right_boundary_node_pt[n] =
1795  bulk_mesh_pt->boundary_node_pt(right_boundary_id,n);
1796  }
1797 
1798  // Sort them from lowest to highest (in y coordinate)
1799  std::sort(ordered_right_boundary_node_pt.begin(),
1800  ordered_right_boundary_node_pt.end(),
1802 
1803  /// \short Number of elements and boundary nodes to be acted upon during
1804  /// construction are extracted from the 'parent' PML meshes
1805  unsigned n_x_right_pml =
1806  pml_right_mesh_pt -> nboundary_element(parent_boundary_x_id);
1807  unsigned n_y_top_pml =
1808  pml_top_mesh_pt -> nboundary_element(parent_boundary_y_id);
1809  unsigned n_x_boundary_nodes =
1810  pml_right_mesh_pt -> nboundary_node(parent_boundary_x_id);
1811  unsigned n_y_boundary_nodes =
1812  pml_top_mesh_pt -> nboundary_node(parent_boundary_y_id);
1813 
1814  /// \short Specific PML sizes needed, taken directly from physical domain
1815  /// and existing PML meshes
1816  double l_pml_right_x_start =
1817  ordered_right_boundary_node_pt[n_right_boundary_node-1] -> x(0);
1818  double l_pml_right_x_end =
1819  pml_right_mesh_pt ->
1820  boundary_node_pt(parent_boundary_x_id, n_x_boundary_nodes-1)-> x(0);
1821  double l_pml_top_y_start =
1822  ordered_right_boundary_node_pt[n_right_boundary_node-1] -> x(1);
1823  double l_pml_top_y_end =
1824  pml_top_mesh_pt ->
1825  boundary_node_pt(parent_boundary_y_id, n_y_boundary_nodes-1)-> x(1);
1826 
1827  // Create the mesh to be designated to the PML
1828  Mesh* pml_top_right_mesh_pt = 0;
1829 
1830  // Build the top right corner PML mesh
1831  pml_top_right_mesh_pt = new PMLCornerQuadMesh<ASSOCIATED_PML_QUAD_ELEMENT>
1832  (pml_right_mesh_pt, pml_top_mesh_pt, bulk_mesh_pt,
1833  ordered_right_boundary_node_pt[n_right_boundary_node-1],
1834  parent_boundary_x_id, parent_boundary_y_id,
1835  current_boundary_x_id, current_boundary_y_id,
1836  n_x_right_pml, n_y_top_pml,
1837  l_pml_right_x_start, l_pml_right_x_end,
1838  l_pml_top_y_start, l_pml_top_y_end,
1839  time_stepper_pt);
1840 
1841  // Enable PML damping on the entire mesh
1842  /// \short The enabling must be perfromed in both x- and y-directions
1843  /// as this is a corner PML mesh
1844  unsigned n_element_pml_top_right = pml_top_right_mesh_pt->nelement();
1845  for(unsigned e=0;e<n_element_pml_top_right;e++)
1846  {
1847  // Upcast
1848  AxisAlignedPMLElement<2>* el_pt = dynamic_cast<AxisAlignedPMLElement<2>*>
1849  (pml_top_right_mesh_pt->element_pt(e));
1850  el_pt -> enable_pml(0, l_pml_right_x_start, l_pml_right_x_end);
1851  el_pt -> enable_pml(1, l_pml_top_y_start, l_pml_top_y_end);
1852  }
1853 
1854  // Get the values to be pinned from the first element (which we
1855  // assume exists!)
1856  AxisAlignedPMLElement<2>* el_pt = dynamic_cast<AxisAlignedPMLElement<2>*>
1857  (pml_top_right_mesh_pt->element_pt(0));
1858  Vector<unsigned> values_to_pin;
1859  el_pt->values_to_be_pinned_on_outer_pml_boundary(values_to_pin);
1860  unsigned npin=values_to_pin.size();
1861 
1862  // Exterior boundary needs to be set to Dirichlet 0
1863  // for both real and imaginary parts of all fields
1864  // in the problem
1865  unsigned n_bound_pml_top_right = pml_top_right_mesh_pt->nboundary();
1866  for(unsigned b=0;b<n_bound_pml_top_right;b++)
1867  {
1868  unsigned n_node = pml_top_right_mesh_pt -> nboundary_node(b);
1869  for (unsigned n=0;n<n_node;n++)
1870  {
1871  Node* nod_pt=pml_top_right_mesh_pt -> boundary_node_pt(b,n);
1872  if ((b==1)||(b==2))
1873  {
1874  for (unsigned j=0;j<npin;j++)
1875  {
1876  unsigned j_val=values_to_pin[j];
1877  nod_pt->pin(j_val);
1878  nod_pt->set_value(j_val,0.0);
1879  }
1880  }
1881  }
1882  }
1883 
1884  /// \short Return the finalized mesh, with PML enabled
1885  /// and boundary conditions added
1886  return pml_top_right_mesh_pt;
1887  }
1888 
1889  //==========================================================================
1890  /// \short "Constructor" for PML bottom right corner mesh,
1891  /// aligned with the existing PML meshes
1892  //==========================================================================
1893  template<class ASSOCIATED_PML_QUAD_ELEMENT>
1895  Mesh* pml_bottom_mesh_pt,
1896  Mesh* bulk_mesh_pt,
1897  const unsigned& right_boundary_id,
1898  TimeStepper* time_stepper_pt=
1900  {
1901 
1902  /// \short Relevant boundary id's to be used in construction
1903  /// Parent id refers to already existing PML meshes
1904  unsigned parent_boundary_x_id = 0;
1905  unsigned parent_boundary_y_id = 1;
1906  // Current id refers to the mesh that is to be constructed
1907  unsigned current_boundary_x_id = 2;
1908  unsigned current_boundary_y_id = 3;
1909 
1910  // Look at the right boundary of the triangular mesh
1911  unsigned n_right_boundary_node =
1912  bulk_mesh_pt -> nboundary_node(right_boundary_id);
1913 
1914  // Create a vector of ordered boundary nodes
1915  Vector<Node*> ordered_right_boundary_node_pt(n_right_boundary_node);
1916 
1917  // Fill the vector with the nodes on the respective boundary
1918  for (unsigned n=0; n<n_right_boundary_node; n++)
1919  {
1920  ordered_right_boundary_node_pt[n] =
1921  bulk_mesh_pt->boundary_node_pt(right_boundary_id,n);
1922  }
1923 
1924  // Sort them from lowest to highest (in y coordinate)
1925  std::sort(ordered_right_boundary_node_pt.begin(),
1926  ordered_right_boundary_node_pt.end(),
1928 
1929  /// \short Number of elements and boundary nodes to be acted upon during
1930  /// construction are extracted from the 'parent' PML meshes
1931  unsigned n_x_right_pml =
1932  pml_right_mesh_pt -> nboundary_element(parent_boundary_x_id);
1933  unsigned n_y_bottom_pml =
1934  pml_bottom_mesh_pt -> nboundary_element(parent_boundary_y_id);
1935  unsigned n_x_boundary_nodes =
1936  pml_right_mesh_pt -> nboundary_node(parent_boundary_x_id);
1937 
1938  /// \short Specific PML sizes needed, taken directly from physical domain
1939  /// and existing PML meshes
1940  double l_pml_right_x_start =
1941  ordered_right_boundary_node_pt[0] -> x(0);
1942  double l_pml_right_x_end =
1943  pml_right_mesh_pt ->
1944  boundary_node_pt(parent_boundary_x_id, n_x_boundary_nodes-1)-> x(0);
1945  double l_pml_bottom_y_start =
1946  pml_bottom_mesh_pt -> boundary_node_pt(parent_boundary_y_id, 0)-> x(1);
1947  double l_pml_bottom_y_end =
1948  ordered_right_boundary_node_pt[0] -> x(1);
1949 
1950  // Create the mesh to be designated to the PML
1951  Mesh* pml_bottom_right_mesh_pt = 0;
1952 
1953  // Build the bottom right corner PML mesh
1954  pml_bottom_right_mesh_pt=
1956  (pml_right_mesh_pt, pml_bottom_mesh_pt, bulk_mesh_pt,
1957  ordered_right_boundary_node_pt[0],
1958  parent_boundary_x_id, parent_boundary_y_id,
1959  current_boundary_x_id, current_boundary_y_id,
1960  n_x_right_pml, n_y_bottom_pml,
1961  l_pml_right_x_start, l_pml_right_x_end,
1962  l_pml_bottom_y_start, l_pml_bottom_y_end,
1963  time_stepper_pt);
1964 
1965  // Enable PML damping on the entire mesh
1966  /// \short The enabling must be perfromed in both x- and y-directions
1967  /// as this is a corner PML mesh
1968  unsigned n_element_pml_bottom_right =
1969  pml_bottom_right_mesh_pt->nelement();
1970 
1971  for(unsigned e=0;e<n_element_pml_bottom_right;e++)
1972  {
1973  // Upcast
1974  AxisAlignedPMLElement<2>* el_pt = dynamic_cast<AxisAlignedPMLElement<2>*>
1975  (pml_bottom_right_mesh_pt->element_pt(e));
1976  el_pt -> enable_pml(0, l_pml_right_x_start, l_pml_right_x_end);
1977  el_pt -> enable_pml(1, l_pml_bottom_y_end, l_pml_bottom_y_start);
1978  }
1979 
1980  // Get the values to be pinned from the first element (which we
1981  // assume exists!)
1982  AxisAlignedPMLElement<2>* el_pt = dynamic_cast<AxisAlignedPMLElement<2>*>
1983  (pml_bottom_right_mesh_pt->element_pt(0));
1984  Vector<unsigned> values_to_pin;
1985  el_pt->values_to_be_pinned_on_outer_pml_boundary(values_to_pin);
1986  unsigned npin=values_to_pin.size();
1987 
1988  // Exterior boundary needs to be set to Dirichlet 0
1989  // for both real and imaginary parts of all fields
1990  // in the problem
1991  unsigned n_bound_pml_bottom_right = pml_bottom_right_mesh_pt->nboundary();
1992  for(unsigned b=0;b<n_bound_pml_bottom_right;b++)
1993  {
1994  unsigned n_node = pml_bottom_right_mesh_pt -> nboundary_node(b);
1995  for (unsigned n=0;n<n_node;n++)
1996  {
1997  Node* nod_pt=pml_bottom_right_mesh_pt -> boundary_node_pt(b,n);
1998  if ((b==0)||(b==1))
1999  {
2000  for (unsigned j=0;j<npin;j++)
2001  {
2002  unsigned j_val=values_to_pin[j];
2003  nod_pt->pin(j_val);
2004  nod_pt->set_value(j_val,0.0);
2005  }
2006  }
2007  }
2008  }
2009 
2010  /// \short Return the finalized mesh, with PML enabled
2011  /// and boundary conditions added
2012  return pml_bottom_right_mesh_pt;
2013  }
2014 
2015  //==========================================================================
2016  /// \short "Constructor" for PML top left corner mesh,
2017  /// aligned with the existing PML meshes
2018  //==========================================================================
2019  template<class ASSOCIATED_PML_QUAD_ELEMENT>
2020  Mesh* create_top_left_pml_mesh(Mesh* pml_left_mesh_pt,
2021  Mesh* pml_top_mesh_pt,
2022  Mesh* bulk_mesh_pt,
2023  const unsigned& left_boundary_id,
2024  TimeStepper* time_stepper_pt=
2026  {
2027 
2028  /// \short Relevant boundary id's to be used in construction
2029  /// Parent id refers to already existing PML meshes
2030  unsigned parent_boundary_x_id = 2;
2031  unsigned parent_boundary_y_id = 3;
2032  // Current id refers to the mesh that is to be constructed
2033  unsigned current_boundary_x_id = 0;
2034  unsigned current_boundary_y_id = 1;
2035 
2036  // Look at the left boundary of the triangular mesh
2037  unsigned n_left_boundary_node =
2038  bulk_mesh_pt -> nboundary_node(left_boundary_id);
2039 
2040  // Create a vector of ordered boundary nodes
2041  Vector<Node*> ordered_left_boundary_node_pt(n_left_boundary_node);
2042 
2043  // Fill the vector with the nodes on the respective boundary
2044  for (unsigned n=0; n<n_left_boundary_node; n++)
2045  {
2046  ordered_left_boundary_node_pt[n] =
2047  bulk_mesh_pt->boundary_node_pt(left_boundary_id,n);
2048  }
2049 
2050  /// \short Sort them from lowest to highest (in y coordinate)
2051  /// sorter_right_boundary is still functional, as the sorting
2052  /// is performed by the same criterion
2053  std::sort(ordered_left_boundary_node_pt.begin(),
2054  ordered_left_boundary_node_pt.end(),
2056 
2057  /// \short Number of elements and boundary nodes to be acted upon during
2058  /// construction are extracted from the 'parent' PML meshes
2059  unsigned n_x_left_pml =
2060  pml_left_mesh_pt -> nboundary_element(parent_boundary_x_id);
2061  unsigned n_y_top_pml =
2062  pml_top_mesh_pt -> nboundary_element(parent_boundary_y_id);
2063  unsigned n_y_boundary_nodes =
2064  pml_top_mesh_pt -> nboundary_node(parent_boundary_y_id);
2065 
2066  /// \short Specific PML sizes needed, taken directly from physical domain
2067  /// and existing PML meshes
2068  double l_pml_left_x_start =
2069  pml_left_mesh_pt -> boundary_node_pt(parent_boundary_x_id, 0)-> x(0);
2070  double l_pml_left_x_end =
2071  ordered_left_boundary_node_pt[n_left_boundary_node-1] -> x(0);
2072  double l_pml_top_y_start =
2073  ordered_left_boundary_node_pt[n_left_boundary_node-1] -> x(1);
2074  double l_pml_top_y_end =
2075  pml_top_mesh_pt ->
2076  boundary_node_pt(parent_boundary_y_id, n_y_boundary_nodes-1)-> x(1);
2077 
2078  // Create the mesh to be designated to the PML
2079  Mesh* pml_top_left_mesh_pt = 0;
2080 
2081  // Build the top left corner PML mesh
2082  pml_top_left_mesh_pt=
2084  (pml_left_mesh_pt, pml_top_mesh_pt, bulk_mesh_pt,
2085  ordered_left_boundary_node_pt[n_left_boundary_node-1],
2086  parent_boundary_x_id, parent_boundary_y_id,
2087  current_boundary_x_id, current_boundary_y_id,
2088  n_x_left_pml, n_y_top_pml,
2089  l_pml_left_x_start, l_pml_left_x_end,
2090  l_pml_top_y_start, l_pml_top_y_end,
2091  time_stepper_pt);
2092 
2093  // Enable PML damping on the entire mesh
2094  /// \short The enabling must be perfromed in both x- and y-directions
2095  /// as this is a corner PML mesh
2096  unsigned n_element_pml_top_left = pml_top_left_mesh_pt->nelement();
2097 
2098  for(unsigned e=0;e<n_element_pml_top_left;e++)
2099  {
2100  // Upcast
2101  AxisAlignedPMLElement<2>* el_pt = dynamic_cast<AxisAlignedPMLElement<2>*>
2102  (pml_top_left_mesh_pt->element_pt(e));
2103  el_pt -> enable_pml(0, l_pml_left_x_end, l_pml_left_x_start);
2104  el_pt -> enable_pml(1, l_pml_top_y_start, l_pml_top_y_end);
2105  }
2106 
2107  // Get the values to be pinned from the first element (which we
2108  // assume exists!)
2109  AxisAlignedPMLElement<2>* el_pt = dynamic_cast<AxisAlignedPMLElement<2>*>
2110  (pml_top_left_mesh_pt->element_pt(0));
2111  Vector<unsigned> values_to_pin;
2112  el_pt->values_to_be_pinned_on_outer_pml_boundary(values_to_pin);
2113  unsigned npin=values_to_pin.size();
2114 
2115  // Exterior boundary needs to be set to Dirichlet 0
2116  // for both real and imaginary parts of all fields
2117  // in the problem
2118  unsigned n_bound_pml_top_left = pml_top_left_mesh_pt->nboundary();
2119  for(unsigned b=0;b<n_bound_pml_top_left;b++)
2120  {
2121  unsigned n_node = pml_top_left_mesh_pt -> nboundary_node(b);
2122  for (unsigned n=0;n<n_node;n++)
2123  {
2124  Node* nod_pt=pml_top_left_mesh_pt -> boundary_node_pt(b,n);
2125  if ((b==2)||(b==3))
2126  {
2127  for (unsigned j=0;j<npin;j++)
2128  {
2129  unsigned j_val=values_to_pin[j];
2130  nod_pt->pin(j_val);
2131  nod_pt->set_value(j_val,0.0);
2132  }
2133  }
2134  }
2135  }
2136 
2137  /// \short Return the finalized mesh, with PML enabled
2138  /// and boundary conditions added
2139  return pml_top_left_mesh_pt;
2140  }
2141 
2142  //==========================================================================
2143  /// \short "Constructor" for PML bottom left corner mesh,
2144  /// aligned with the existing PML meshes
2145  //==========================================================================
2146  template<class ASSOCIATED_PML_QUAD_ELEMENT>
2148  Mesh* pml_bottom_mesh_pt,
2149  Mesh* bulk_mesh_pt,
2150  const unsigned& left_boundary_id,
2151  TimeStepper* time_stepper_pt=
2153  {
2154 
2155  /// \short Relevant boundary id's to be used in construction
2156  /// Parent id refers to already existing PML meshes
2157  unsigned parent_boundary_x_id = 0;
2158  unsigned parent_boundary_y_id = 3;
2159  // Current id refers to the mesh that is to be constructed
2160  unsigned current_boundary_x_id = 2;
2161  unsigned current_boundary_y_id = 1;
2162 
2163  // Look at the left boundary of the triangular mesh
2164  unsigned n_left_boundary_node =
2165  bulk_mesh_pt -> nboundary_node(left_boundary_id);
2166 
2167  // Create a vector of ordered boundary nodes
2168  Vector<Node*> ordered_left_boundary_node_pt(n_left_boundary_node);
2169 
2170  // Fill the vector with the nodes on the respective boundary
2171  for (unsigned n=0; n<n_left_boundary_node; n++)
2172  {
2173  ordered_left_boundary_node_pt[n] =
2174  bulk_mesh_pt->boundary_node_pt(left_boundary_id,n);
2175  }
2176 
2177  /// \short Sort them from lowest to highest (in y coordinate)
2178  /// sorter_right_boundary is still functional, as the sorting
2179  /// is performed by the same criterion
2180  std::sort(ordered_left_boundary_node_pt.begin(),
2181  ordered_left_boundary_node_pt.end(),
2183 
2184  /// \short Number of elements and boundary nodes to be acted upon during
2185  /// construction are extracted from the 'parent' PML meshes
2186  unsigned n_x_left_pml =
2187  pml_left_mesh_pt -> nboundary_element(parent_boundary_x_id);
2188  unsigned n_y_bottom_pml =
2189  pml_bottom_mesh_pt -> nboundary_element(parent_boundary_y_id);
2190 
2191  /// \short Specific PML sizes needed, taken directly from physical domain
2192  /// and existing PML meshes
2193  double l_pml_left_x_start =
2194  pml_left_mesh_pt -> boundary_node_pt(parent_boundary_x_id, 0)-> x(0);
2195  double l_pml_left_x_end =
2196  ordered_left_boundary_node_pt[n_left_boundary_node-1] -> x(0);
2197  double l_pml_bottom_y_start =
2198  pml_bottom_mesh_pt -> boundary_node_pt(parent_boundary_y_id, 0)-> x(1);
2199  double l_pml_bottom_y_end =
2200  ordered_left_boundary_node_pt[0] -> x(1);
2201 
2202  // Create the mesh to be designated to the PML
2203  Mesh* pml_bottom_left_mesh_pt = 0;
2204 
2205  // Build the bottom left corner PML mesh
2206  pml_bottom_left_mesh_pt=
2208  (pml_left_mesh_pt, pml_bottom_mesh_pt, bulk_mesh_pt,
2209  ordered_left_boundary_node_pt[0],
2210  parent_boundary_x_id, parent_boundary_y_id,
2211  current_boundary_x_id, current_boundary_y_id,
2212  n_x_left_pml, n_y_bottom_pml,
2213  l_pml_left_x_start, l_pml_left_x_end,
2214  l_pml_bottom_y_start, l_pml_bottom_y_end,
2215  time_stepper_pt);
2216 
2217  //Enable PML damping on the entire mesh
2218  /// \short The enabling must be perfromed in both x- and y-directions
2219  /// as this is a corner PML mesh
2220  unsigned n_element_pml_bottom_left = pml_bottom_left_mesh_pt->nelement();
2221  for(unsigned e=0;e<n_element_pml_bottom_left;e++)
2222  {
2223  // Upcast
2224  AxisAlignedPMLElement<2>* el_pt = dynamic_cast<AxisAlignedPMLElement<2>*>
2225  (pml_bottom_left_mesh_pt->element_pt(e));
2226  el_pt -> enable_pml(0, l_pml_left_x_end, l_pml_left_x_start);
2227  el_pt -> enable_pml(1, l_pml_bottom_y_end, l_pml_bottom_y_start);
2228  }
2229 
2230  // Get the values to be pinned from the first element (which we
2231  // assume exists!)
2232  AxisAlignedPMLElement<2>* el_pt = dynamic_cast<AxisAlignedPMLElement<2>*>
2233  (pml_bottom_left_mesh_pt->element_pt(0));
2234  Vector<unsigned> values_to_pin;
2235  el_pt->values_to_be_pinned_on_outer_pml_boundary(values_to_pin);
2236  unsigned npin=values_to_pin.size();
2237 
2238  // Exterior boundary needs to be set to Dirichlet 0
2239  // for both real and imaginary parts of all fields
2240  // in the problem
2241  unsigned n_bound_pml_bottom_left = pml_bottom_left_mesh_pt->nboundary();
2242  for(unsigned b=0;b<n_bound_pml_bottom_left;b++)
2243  {
2244  unsigned n_node = pml_bottom_left_mesh_pt -> nboundary_node(b);
2245  for (unsigned n=0;n<n_node;n++)
2246  {
2247  Node* nod_pt=pml_bottom_left_mesh_pt -> boundary_node_pt(b,n);
2248  if ((b==0)||(b==3))
2249  {
2250  for (unsigned j=0;j<npin;j++)
2251  {
2252  unsigned j_val=values_to_pin[j];
2253  nod_pt->pin(j_val);
2254  nod_pt->set_value(j_val,0.0);
2255  }
2256  }
2257  }
2258  }
2259 
2260  /// \short Return the finalized mesh, with PML enabled
2261  /// and boundary conditions added
2262  return pml_bottom_left_mesh_pt;
2263  }
2264 
2265  }
2266 
2267 //////////////////////////////////////////////////////////////////////
2268 //////////////////////////////////////////////////////////////////////
2269 //////////////////////////////////////////////////////////////////////
2270 
2271 }
2272 
2273 #endif
void pml_locate_zeta(const Vector< double > &x, FiniteElement *&coarse_mesh_el_pt)
Overloaded function to allow the user to locate an element in mesh given the (Eulerian) position of a...
Definition: pml_meshes.h:113
bool sorter_left_boundary(Node *nod_i_pt, Node *nod_j_pt)
helper function for sorting the left boundary nodes
Definition: pml_meshes.cc:56
Node *& boundary_node_pt(const unsigned &b, const unsigned &n)
Return pointer to node n on boundary b.
Definition: mesh.h:497
static Steady< 0 > Default_TimeStepper
Default Steady Timestepper, to be used in default arguments to Mesh constructors. ...
Definition: mesh.h:85
bool sorter_bottom_boundary(Node *nod_i_pt, Node *nod_j_pt)
helper function for sorting the bottom boundary nodes
Definition: pml_meshes.cc:62
cstr elem_len * i
Definition: cfortran.h:607
A general Finite Element class.
Definition: elements.h:1274
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:852
e
Definition: cfortran.h:575
Mesh * create_top_pml_mesh(Mesh *bulk_mesh_pt, const unsigned &top_boundary_id, const unsigned &n_y_top_pml, const double &width_y_top_pml, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
"Constructor" for PML mesh, aligned with the top physical domain boundary
Definition: pml_meshes.h:1453
void pin(const unsigned &i)
Pin the i-th stored variable.
Definition: nodes.h:383
double size() const
Definition: elements.cc:4207
PML mesh, derived from RectangularQuadMesh.
Definition: pml_meshes.h:329
unsigned long nelement() const
Return number of elements in the mesh.
Definition: mesh.h:587
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition: nodes.h:995
virtual void values_to_be_pinned_on_outer_pml_boundary(Vector< unsigned > &values_to_pin)=0
Pure virtual function in which we have to specify the values to be pinned (and set to zero) on the ou...
GeneralisedElement *& element_pt(const unsigned long &e)
Return pointer to element e.
Definition: mesh.h:462
unsigned nboundary() const
Return number of boundaries.
Definition: mesh.h:806
void set_value(const unsigned &i, const double &value_)
Set the i-th stored data value to specified value. The only reason that we require an explicit set fu...
Definition: nodes.h:267
bool sorter_right_boundary(Node *nod_i_pt, Node *nod_j_pt)
helper function for sorting the right boundary nodes
Definition: pml_meshes.cc:44
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2109
Mesh * create_top_left_pml_mesh(Mesh *pml_left_mesh_pt, Mesh *pml_top_mesh_pt, Mesh *bulk_mesh_pt, const unsigned &left_boundary_id, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
"Constructor" for PML top left corner mesh, aligned with the existing PML meshes
Definition: pml_meshes.h:2020
PMLCornerQuadMesh(Mesh *PMLQuad_mesh_x_pt, Mesh *PMLQuad_mesh_y_pt, Mesh *bulk_mesh_pt, Node *special_corner_node_pt, const unsigned &parent_boundary_x_id, const unsigned &parent_boundary_y_id, const unsigned &current_boundary_x_id, const unsigned &current_boundary_y_id, const unsigned &n_pml_x, const unsigned &n_pml_y, const double &x_pml_start, const double &x_pml_end, const double &y_pml_start, const double &y_pml_end, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor: Pass pointer to "bulk" mesh and the two existing PML meshes in order to construct the co...
Definition: pml_meshes.h:666
bool sorter_top_boundary(Node *nod_i_pt, Node *nod_j_pt)
helper function for sorting the top boundary nodes
Definition: pml_meshes.cc:50
Mesh * create_bottom_pml_mesh(Mesh *bulk_mesh_pt, const unsigned &bottom_boundary_id, const unsigned &n_y_bottom_pml, const double &width_y_bottom_pml, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
"Constructor" for PML mesh,aligned with the bottom physical domain boundary
Definition: pml_meshes.h:1661
Mesh * create_left_pml_mesh(Mesh *bulk_mesh_pt, const unsigned &left_boundary_id, const unsigned &n_x_left_pml, const double &width_x_left_pml, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
"Constructor" for PML mesh, aligned with the left physical domain boundary
Definition: pml_meshes.h:1557
PMLQuadMeshBase(const unsigned &n_pml_x, const unsigned &n_pml_y, const double &x_pml_start, const double &x_pml_end, const double &y_pml_start, const double &y_pml_end, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor: Create the underlying rectangular quad mesh.
Definition: pml_meshes.h:98
PML mesh class. Policy class for 2D PML meshes.
Definition: pml_meshes.h:92
Mesh * create_bottom_right_pml_mesh(Mesh *pml_right_mesh_pt, Mesh *pml_bottom_mesh_pt, Mesh *bulk_mesh_pt, const unsigned &right_boundary_id, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
"Constructor" for PML bottom right corner mesh, aligned with the existing PML meshes ...
Definition: pml_meshes.h:1894
Mesh * create_right_pml_mesh(Mesh *bulk_mesh_pt, const unsigned &right_boundary_id, const unsigned &n_x_right_pml, const double &width_x_right_pml, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
"Constructor" for PML mesh,aligned with the right physical domain boundary
Definition: pml_meshes.h:1348
PMLQuadMesh(Mesh *bulk_mesh_pt, const unsigned &boundary_id, const unsigned &quad_boundary_id, const unsigned &n_pml_x, const unsigned &n_pml_y, const double &x_pml_start, const double &x_pml_end, const double &y_pml_start, const double &y_pml_end, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor: Pass pointer to "bulk" mesh, the boundary ID of axis aligned boundary to which the mesh ...
Definition: pml_meshes.h:342
Mesh * create_bottom_left_pml_mesh(Mesh *pml_left_mesh_pt, Mesh *pml_bottom_mesh_pt, Mesh *bulk_mesh_pt, const unsigned &left_boundary_id, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
"Constructor" for PML bottom left corner mesh, aligned with the existing PML meshes ...
Definition: pml_meshes.h:2147
PML mesh, derived from RectangularQuadMesh.
Definition: pml_meshes.h:658
Mesh * create_top_right_pml_mesh(Mesh *pml_right_mesh_pt, Mesh *pml_top_mesh_pt, Mesh *bulk_mesh_pt, const unsigned &right_boundary_id, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
"Constructor" for PML top right corner mesh, aligned with the existing PML meshes ...
Definition: pml_meshes.h:1768
Base class for time-stepping schemes. Timestepper provides an approximation of the temporal derivativ...
Definition: timesteppers.h:219
A general mesh class.
Definition: mesh.h:74