quad_mesh.cc
Go to the documentation of this file.
1 // LIC// ====================================================================
2 // LIC// This file forms part of oomph-lib, the object-oriented,
3 // LIC// multi-physics finite-element library, available
4 // LIC// at http://www.oomph-lib.org.
5 // LIC//
6 // LIC// Copyright (C) 2006-2023 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 #include <algorithm>
27 #include "map_matrix.h"
28 #include "quad_mesh.h"
29 
30 
31 namespace oomph
32 {
33  //================================================================
34  /// Setup lookup schemes which establish which elements are located
35  /// next to which boundaries (Doc to outfile if it's open).
36  //================================================================
37  void QuadMeshBase::setup_boundary_element_info(std::ostream& outfile)
38  {
39  bool doc = false;
40  if (outfile) doc = true;
41 
42  // Number of boundaries
43  unsigned nbound = nboundary();
44 
45  // Wipe/allocate storage for arrays
46  Boundary_element_pt.clear();
47  Face_index_at_boundary.clear();
48  Boundary_element_pt.resize(nbound);
49  Face_index_at_boundary.resize(nbound);
50 
51  // Temporary vector of vectors to pointers to elements on the boundaries:
52  // This is not a set to ensure UNIQUE ordering
53  Vector<Vector<FiniteElement*>> vector_of_boundary_element_pt;
54  vector_of_boundary_element_pt.resize(nbound);
55 
56  // Matrix map for working out the fixed local coord for elements on boundary
58 
59 
60  // Loop over elements
61  //-------------------
62  unsigned nel = nelement();
63  for (unsigned e = 0; e < nel; e++)
64  {
65  // Get pointer to element
67 
68  if (doc) outfile << "Element: " << e << " " << fe_pt << std::endl;
69 
70  // Only include 2D elements! Some meshes contain interface elements too.
71  if (fe_pt->dim() == 2)
72  {
73  // Loop over the element's nodes and find out which boundaries they're
74  // on
75  // ----------------------------------------------------------------------
76  unsigned nnode_1d = fe_pt->nnode_1d();
77 
78  // Loop over nodes in order
79  for (unsigned i0 = 0; i0 < nnode_1d; i0++)
80  {
81  for (unsigned i1 = 0; i1 < nnode_1d; i1++)
82  {
83  // Local node number
84  unsigned j = i0 + i1 * nnode_1d;
85 
86  // Get pointer to vector of boundaries that this
87  // node lives on
88  std::set<unsigned>* boundaries_pt = 0;
89  fe_pt->node_pt(j)->get_boundaries_pt(boundaries_pt);
90 
91  // If the node lives on some boundaries....
92  if (boundaries_pt != 0)
93  {
94  // Loop over boundaries
95  // unsigned nbound=(*boundaries_pt).size();
96  for (std::set<unsigned>::iterator it = boundaries_pt->begin();
97  it != boundaries_pt->end();
98  ++it)
99  {
100  // Add pointer to finite element to vector for the appropriate
101  // boundary
102 
103  // Does the pointer already exits in the vector
105  std::find(vector_of_boundary_element_pt[*it].begin(),
106  vector_of_boundary_element_pt[*it].end(),
107  fe_pt);
108  // Only insert if we have not found it (i.e. got to the end)
109  if (b_el_it == vector_of_boundary_element_pt[*it].end())
110  {
111  vector_of_boundary_element_pt[*it].push_back(fe_pt);
112  }
113 
114  // For the current element/boundary combination, create
115  // a vector that stores an indicator which element boundaries
116  // the node is located (boundary_identifier=-/+1 for nodes
117  // on the left/right boundary; boundary_identifier=-/+2 for
118  // nodes on the lower/upper boundary. We determine these indices
119  // for all corner nodes of the element and add them to a vector
120  // to a vector. This allows us to decide which face of the
121  // element coincides with the boundary since the (quad!) element
122  // must have exactly two corner nodes on the boundary.
123  if (boundary_identifier(*it, fe_pt) == 0)
124  {
125  boundary_identifier(*it, fe_pt) = new Vector<int>;
126  }
127 
128  // Are we at a corner node?
129  if (((i0 == 0) || (i0 == nnode_1d - 1)) &&
130  ((i1 == 0) || (i1 == nnode_1d - 1)))
131  {
132  // Create index to represent position relative to s_0
133  (*boundary_identifier(*it, fe_pt))
134  .push_back(1 * (2 * i0 / (nnode_1d - 1) - 1));
135 
136  // Create index to represent position relative to s_1
137  (*boundary_identifier(*it, fe_pt))
138  .push_back(2 * (2 * i1 / (nnode_1d - 1) - 1));
139  }
140  }
141  }
142  // else
143  // {
144  // oomph_info << "...does not live on any boundaries " <<
145  // std::endl;
146  // }
147  }
148  }
149  }
150  // else
151  //{
152  // oomph_info << "Element " << e << " does not qualify" << std::endl;
153  //}
154  }
155 
156  // Now copy everything across into permanent arrays
157  //-------------------------------------------------
158 
159  // Note: vector_of_boundary_element_pt contains all elements
160  // that have (at least) one corner node on a boundary -- can't copy
161  // them across into Boundary_element_pt
162  // yet because some of them might have only one node on the
163  // the boundary in which case they don't qualify as
164  // boundary elements!
165 
166  // Loop over boundaries
167  //---------------------
168  for (unsigned i = 0; i < nbound; i++)
169  {
170  // Number of elements on this boundary
171  // nel is unused, so I've commented it out - RWhite.
172  // unsigned nel=vector_of_boundary_element_pt[i].size();
173 
174  // Allocate storage for the face identifiers
175  // Face_index_at_boundary[i].resize(nel);
176 
177  // Loop over elements that have at least one corner node on this boundary
178  //-----------------------------------------------------------------------
179  // unsigned e_count=0;
181  for (IT it = vector_of_boundary_element_pt[i].begin();
182  it != vector_of_boundary_element_pt[i].end();
183  it++)
184  {
185  // Recover pointer to element
186  FiniteElement* fe_pt = *it;
187 
188  // Initialise count for boundary identiers (-2,-1,1,2)
189  std::map<int, unsigned> count;
190 
191  // Loop over coordinates
192  for (unsigned ii = 0; ii < 2; ii++)
193  {
194  // Loop over upper/lower end of coordinates
195  for (int sign = -1; sign < 3; sign += 2)
196  {
197  count[(ii + 1) * sign] = 0;
198  }
199  }
200 
201  // Loop over boundary indicators for this element/boundary
202  unsigned n_indicators = (*boundary_identifier(i, fe_pt)).size();
203  for (unsigned j = 0; j < n_indicators; j++)
204  {
205  count[(*boundary_identifier(i, fe_pt))[j]]++;
206  }
207  delete boundary_identifier(i, fe_pt);
208 
209  // Determine the correct boundary indicator by checking that it
210  // occurs twice (since two corner nodes of the element's boundary
211  // need to be located on the domain boundary
212  int indicator = -10;
213 
214  // Check that we're finding exactly one boundary indicator
215  // bool found=false;
216 
217  // Loop over coordinates
218  for (unsigned ii = 0; ii < 2; ii++)
219  {
220  // Loop over upper/lower end of coordinates
221  for (int sign = -1; sign < 3; sign += 2)
222  {
223  // If an index occurs twice then that face is on the boundary
224  // But we can have multiple faces on the same boundary id, so just
225  // add all the ones that we have
226  if (count[(ii + 1) * sign] == 2)
227  {
228  // Check that we haven't found multiple boundaries
229  /*if (found)
230  {
231  std::string error_message=
232  "Trouble: Multiple boundary identifiers!\n";
233  error_message +=
234  "Elements should only have at most 2 corner ";
235  error_message +=
236  "nodes on any one boundary.\n";
237 
238  throw OomphLibError(
239  error_message,
240  OOMPH_CURRENT_FUNCTION,
241  OOMPH_EXCEPTION_LOCATION);
242  }
243  found=true;*/
244  indicator = (ii + 1) * sign;
245 
246  // Copy into the data structure
247  Boundary_element_pt[i].push_back(*it);
248  Face_index_at_boundary[i].push_back(indicator);
249  }
250  }
251  }
252 
253  // Element has exactly two corner nodes on boundary
254  /*if (found)
255  {
256  // Add to permanent storage
257  Boundary_element_pt[i].push_back(fe_pt);
258 
259  // Now convert boundary indicator into information required
260  // for FaceElements
261  switch (indicator)
262  {
263  //South face
264  case -2:
265 
266  // s_1 is fixed at -1.0:
267  Face_index_at_boundary[i][e_count] = -2;
268  break;
269 
270  //West face
271  case -1:
272 
273  // s_0 is fixed at -1.0:
274  Face_index_at_boundary[i][e_count] = -1;
275  break;
276 
277  //East face
278  case 1:
279 
280  // s_0 is fixed at 1.0:
281  Face_index_at_boundary[i][e_count] = 1;
282  break;
283 
284  //North face
285  case 2:
286 
287  // s_1 is fixed at 1.0:
288  Face_index_at_boundary[i][e_count] = 2;
289  break;
290 
291  default:
292 
293  throw OomphLibError("Never get here",
294  OOMPH_CURRENT_FUNCTION,
295  OOMPH_EXCEPTION_LOCATION);
296  }
297 
298  // Increment counter
299  e_count++;
300  }*/
301  }
302  }
303 
304 
305  // Doc?
306  //-----
307  if (doc)
308  {
309  // Loop over boundaries
310  for (unsigned i = 0; i < nbound; i++)
311  {
312  unsigned nel = Boundary_element_pt[i].size();
313  outfile << "Boundary: " << i << " is adjacent to " << nel << " elements"
314  << std::endl;
315 
316  // Loop over elements on given boundary
317  for (unsigned e = 0; e < nel; e++)
318  {
320  outfile << "Boundary element:" << fe_pt
321  << " Face index on boundary is "
322  << Face_index_at_boundary[i][e] << std::endl;
323  }
324  }
325  }
326 
327 
328  // Lookup scheme has now been setup
330  }
331 
332 } // namespace oomph
e
Definition: cfortran.h:571
cstr elem_len * i
Definition: cfortran.h:603
A general Finite Element class.
Definition: elements.h:1313
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2175
unsigned dim() const
Return the spatial dimension of the element, i.e. the number of local coordinates required to paramet...
Definition: elements.h:2611
virtual unsigned nnode_1d() const
Return the number of nodes along one edge of the element Default is to return zero — must be overload...
Definition: elements.h:2218
MapMatrixMixed is a generalised, STL-map-based, sparse(ish) matrix class with mixed indices.
Definition: map_matrix.h:109
Vector< Vector< FiniteElement * > > Boundary_element_pt
Vector of Vector of pointers to elements on the boundaries: Boundary_element_pt(b,...
Definition: mesh.h:91
bool Lookup_for_elements_next_boundary_is_setup
Flag to indicate that the lookup schemes for elements that are adjacent to the boundaries has been se...
Definition: mesh.h:87
FiniteElement * finite_element_pt(const unsigned &e) const
Upcast (downcast?) to FiniteElement (needed to access FiniteElement member functions).
Definition: mesh.h:473
Vector< Vector< int > > Face_index_at_boundary
For the e-th finite element on boundary b, this is the index of the face that lies along that boundar...
Definition: mesh.h:95
unsigned nboundary() const
Return number of boundaries.
Definition: mesh.h:827
unsigned long nelement() const
Return number of elements in the mesh.
Definition: mesh.h:590
virtual void get_boundaries_pt(std::set< unsigned > *&boundaries_pt)
Return a pointer to set of mesh boundaries that this node occupies; this will be overloaded by Bounda...
Definition: nodes.h:1365
void setup_boundary_element_info()
Setup lookup schemes which establish whic elements are located next to mesh's boundaries (wrapper to ...
Definition: quad_mesh.h:73
A slight extension to the standard template vector class so that we can include "graceful" array rang...
Definition: Vector.h:58
//////////////////////////////////////////////////////////////////// ////////////////////////////////...