1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2020 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 
18 // Local Includes
19 #include "libmesh/libmesh_config.h"
20 
21 #ifdef LIBMESH_ENABLE_PERIODIC
22 
23 #include "libmesh/periodic_boundaries.h"
24 
25 #include "libmesh/boundary_info.h"
26 #include "libmesh/elem.h"
27 #include "libmesh/mesh_base.h"
28 #include "libmesh/periodic_boundary.h"
29 #include "libmesh/point_locator_base.h"
30 #include "libmesh/remote_elem.h"
31 
32 namespace libMesh
33 {
34 
~PeriodicBoundaries()35 PeriodicBoundaries::~PeriodicBoundaries()
36 {
37   for (auto & pr : *this)
38     delete pr.second;
39 }
40 
41 
42 
boundary(boundary_id_type id)43 PeriodicBoundaryBase * PeriodicBoundaries::boundary(boundary_id_type id)
44 {
45   iterator i = this->find(id);
46   if (i == this->end())
47     return nullptr;
48   return i->second;
49 }
50 
51 
52 
boundary(boundary_id_type id)53 const PeriodicBoundaryBase * PeriodicBoundaries::boundary(boundary_id_type id) const
54 {
55   const_iterator i = this->find(id);
56   if (i == this->end())
57     return nullptr;
58   return i->second;
59 }
60 
61 
62 
63 
neighbor(boundary_id_type boundary_id,const PointLocatorBase & point_locator,const Elem * e,unsigned int side,unsigned int * neigh_side)64 const Elem * PeriodicBoundaries::neighbor(boundary_id_type boundary_id,
65                                           const PointLocatorBase & point_locator,
66                                           const Elem * e,
67                                           unsigned int side,
68                                           unsigned int * neigh_side) const
69 {
70   std::unique_ptr<const Elem> neigh_side_proxy;
71 
72   // Find a point on that side (and only that side)
73   Point p = e->build_side_ptr(side)->centroid();
74 
75   const PeriodicBoundaryBase * b = this->boundary(boundary_id);
76   libmesh_assert (b);
77   p = b->get_corresponding_pos(p);
78 
79   std::set<const Elem *> candidate_elements;
80   point_locator.operator()(p, candidate_elements);
81 
82   // We might have found multiple elements, e.g. if two distinct periodic
83   // boundaries are overlapping (see systems_of_equations_ex9, for example).
84   // As a result, we need to search for the element that has boundary_id.
85   const MeshBase & mesh = point_locator.get_mesh();
86   for(const Elem * elem_it : candidate_elements)
87     {
88       std::vector<unsigned int> neigh_sides =
89         mesh.get_boundary_info().sides_with_boundary_id(elem_it, b->pairedboundary);
90 
91       for (auto ns : neigh_sides)
92         {
93           if (neigh_side)
94             {
95               elem_it->build_side_ptr(neigh_side_proxy, ns);
96               if (neigh_side_proxy->contains_point(p))
97                 {
98                   *neigh_side = ns;
99                   return elem_it;
100                 }
101             }
102           else
103             // checking contains_point is too expensive if we don't
104             // definitely need it to find neigh_side
105             return elem_it;
106         }
107     }
108 
109   // If we should have found a periodic neighbor but didn't then
110   // either we're on a ghosted element with a remote periodic neighbor
111   // or we're on a mesh with an inconsistent periodic boundary.
112   libmesh_assert_msg(!mesh.is_serial() &&
113                      (e->processor_id() != mesh.processor_id()),
114                      "Periodic boundary neighbor not found");
115   if (neigh_side)
116     *neigh_side = libMesh::invalid_uint;
117   return remote_elem;
118 }
119 
120 } // namespace libMesh
121 
122 
123 
124 
125 
126 #endif // LIBMESH_ENABLE_PERIODIC
127