refineable_quad_spectral_element.h
Go to the documentation of this file.
1 // LIC// ====================================================================
2 // LIC// This file forms part of oomph-lib, the object-oriented,
3 // LIC// multi-physics finite-element library, available
4 // LIC// at http://www.oomph-lib.org.
5 // LIC//
6 // LIC// Copyright (C) 2006-2024 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 #ifndef OOMPH_REFINEABLE_QUAD_SPECTRAL_ELEMENT_HEADER
27 #define OOMPH_REFINEABLE_QUAD_SPECTRAL_ELEMENT_HEADER
28 
29 
30 // Config header generated by autoconfig
31 #ifdef HAVE_CONFIG_H
32 #include <oomph-lib-config.h>
33 #endif
34 
35 
36 // oomph-lib headers
38 
39 namespace oomph
40 {
41  //=======================================================================
42  /// Refineable version of QuadElements that add functionality for spectral
43  /// Elements.
44  //=======================================================================
45  template<>
46  class RefineableQSpectralElement<2> : public virtual RefineableQElement<2>
47  {
48  public:
49  /// Constructor
51  {
52 #ifdef LEAK_CHECK
53  LeakCheckNames::RefineableQSpectralElement<2> _build += 1;
54 #endif
55  }
56 
57 
58  /// Broken copy constructor
60  delete;
61 
62  /// Broken assignment operator
63  // Commented out broken assignment operator because this can lead to a
64  // conflict warning when used in the virtual inheritence hierarchy.
65  // Essentially the compiler doesn't realise that two separate
66  // implementations of the broken function are the same and so, quite
67  // rightly, it shouts.
68  /*void operator=(const RefineableQSpectralElement<2>&) = delete;*/
69 
70  /// Destructor
72  {
73 #ifdef LEAK_CHECK
74  LeakCheckNames::RefineableQSpectralElement<2> _build -= 1;
75 #endif
76  }
77 
78  /// The only thing to add is rebuild from sons
79  void rebuild_from_sons(Mesh*& mesh_pt)
80  {
81  // The timestepper should be the same for all nodes and node 0 should
82  // never be deleted.
83  if (this->node_pt(0) == 0)
84  {
85  throw OomphLibError("The Corner node (0) does not exist",
86  OOMPH_CURRENT_FUNCTION,
87  OOMPH_EXCEPTION_LOCATION);
88  }
89 
90  TimeStepper* time_stepper_pt = this->node_pt(0)->time_stepper_pt();
91  unsigned ntstorage = time_stepper_pt->ntstorage();
92 
93  unsigned jnod = 0;
94  Vector<double> s_fraction(2), s(2);
95  // Loop over the nodes in the element
96  unsigned n_p = this->nnode_1d();
97  for (unsigned i0 = 0; i0 < n_p; i0++)
98  {
99  // Get the fractional position of the node
100  s_fraction[0] = this->local_one_d_fraction_of_node(i0, 0);
101  // Local coordinate
102  s[0] = -1.0 + 2.0 * s_fraction[0];
103 
104  for (unsigned i1 = 0; i1 < n_p; i1++)
105  {
106  // Get the fractional position of the node in the direction of s[1]
107  s_fraction[1] = this->local_one_d_fraction_of_node(i1, 1);
108  // Local coordinate in father element
109  s[1] = -1.0 + 2.0 * s_fraction[1];
110 
111  // Set the local node number
112  jnod = i0 + n_p * i1;
113 
114  // If the node has not been built
115  if (this->node_pt(jnod) == 0)
116  {
117  // Has the node been created by one of its neighbours
118  bool is_periodic = false;
119  Node* created_node_pt =
120  this->node_created_by_neighbour(s_fraction, is_periodic);
121 
122  // If it has set the pointer
123  if (created_node_pt != 0)
124  {
125  // If the node is periodic
126  if (is_periodic)
127  {
128  throw OomphLibError("Cannot handle periodic nodes in "
129  "refineable spectral elements yet",
130  OOMPH_CURRENT_FUNCTION,
131  OOMPH_EXCEPTION_LOCATION);
132  }
133  // Non-periodic case, just set the pointer
134  else
135  {
136  this->node_pt(jnod) = created_node_pt;
137  }
138  }
139  // Otherwise, we need to build it
140  else
141  {
142  // First, find the son element in which the node should live
143 
144  // Find coordinates in the sons
145  Vector<double> s_in_son(2);
146  using namespace QuadTreeNames;
147  int son = -10;
148  // If negative on the west side
149  if (s_fraction[0] < 0.5)
150  {
151  // On the south side
152  if (s_fraction[1] < 0.5)
153  {
154  // It's the southwest son
155  son = SW;
156  s_in_son[0] = -1.0 + 4.0 * s_fraction[0];
157  s_in_son[1] = -1.0 + 4.0 * s_fraction[1];
158  }
159  // On the north side
160  else
161  {
162  // It's the northwest son
163  son = NW;
164  s_in_son[0] = -1.0 + 4.0 * s_fraction[0];
165  s_in_son[1] = -1.0 + 4.0 * (s_fraction[1] - 0.5);
166  }
167  }
168  else
169  {
170  // On the south side
171  if (s_fraction[1] < 0.5)
172  {
173  // It's the southeast son
174  son = SE;
175  s_in_son[0] = -1.0 + 4.0 * (s_fraction[0] - 0.5);
176  s_in_son[1] = -1.0 + 4.0 * s_fraction[1];
177  }
178  // On the north side
179  else
180  {
181  // It's the northeast son
182  son = NE;
183  s_in_son[0] = -1.0 + 4.0 * (s_fraction[0] - 0.5);
184  s_in_son[1] = -1.0 + 4.0 * (s_fraction[1] - 0.5);
185  }
186  }
187 
188  // Get the pointer to the son element in which the new node
189  // would live
190  RefineableQSpectralElement<2>* son_el_pt =
191  dynamic_cast<RefineableQSpectralElement<2>*>(
192  this->tree_pt()->son_pt(son)->object_pt());
193 
194  // If we are rebuilding, then worry about the boundary conditions
195  // Find the boundary of the node
196  // Initially none
197  int boundary = Tree::OMEGA;
198  // If we are on the western boundary
199  if (i0 == 0)
200  {
201  boundary = W;
202  }
203  // If we are on the eastern boundary
204  else if (i0 == n_p - 1)
205  {
206  boundary = E;
207  }
208 
209  // If we are on the southern boundary
210  if (i1 == 0)
211  {
212  // If we already have already set the boundary, we're on a
213  // corner
214  switch (boundary)
215  {
216  case W:
217  boundary = SW;
218  break;
219  case E:
220  boundary = SE;
221  break;
222  // Boundary not set
223  default:
224  boundary = S;
225  break;
226  }
227  }
228  // If we are the northern bounadry
229  else if (i1 == n_p - 1)
230  {
231  // If we already have a boundary
232  switch (boundary)
233  {
234  case W:
235  boundary = NW;
236  break;
237  case E:
238  boundary = NE;
239  break;
240  default:
241  boundary = N;
242  break;
243  }
244  }
245 
246  // set of boundaries that this edge in the son lives on
247  std::set<unsigned> boundaries;
248 
249  // Now get the boundary conditions from the son
250  // The boundaries will be common to the son because there can be
251  // no rotations here
252  if (boundary != Tree::OMEGA)
253  {
254  son_el_pt->get_boundaries(boundary, boundaries);
255  }
256 
257  // If the node lives on a boundary:
258  // Construct a boundary node,
259  // Get boundary conditions and
260  // update all lookup schemes
261  if (boundaries.size() > 0)
262  {
263  // Construct the new node
264  this->node_pt(jnod) =
265  this->construct_boundary_node(jnod, time_stepper_pt);
266 
267  // Get the boundary conditions from the son
268  Vector<int> bound_cons(ncont_interpolated_values());
269  son_el_pt->get_bcs(boundary, bound_cons);
270 
271  // Loop over the values and pin if necessary
272  unsigned nval = this->node_pt(jnod)->nvalue();
273  for (unsigned k = 0; k < nval; k++)
274  {
275  if (bound_cons[k])
276  {
277  this->node_pt(jnod)->pin(k);
278  }
279  }
280 
281  // Solid node? If so, deal with the positional boundary
282  // conditions:
283  SolidNode* solid_node_pt =
284  dynamic_cast<SolidNode*>(this->node_pt(jnod));
285  if (solid_node_pt != 0)
286  {
287  // Get the positional boundary conditions from the father:
288  unsigned n_dim = this->node_pt(jnod)->ndim();
289  Vector<int> solid_bound_cons(n_dim);
290  RefineableSolidQElement<2>* son_solid_el_pt =
291  dynamic_cast<RefineableSolidQElement<2>*>(son_el_pt);
292 #ifdef PARANOID
293  if (son_solid_el_pt == 0)
294  {
295  std::string error_message =
296  "We have a SolidNode outside a refineable SolidElement\n";
297  error_message +=
298  "during mesh refinement -- this doesn't make sense\n";
299 
300  throw OomphLibError(error_message,
301  OOMPH_CURRENT_FUNCTION,
302  OOMPH_EXCEPTION_LOCATION);
303  }
304 #endif
305  son_solid_el_pt->get_solid_bcs(boundary, solid_bound_cons);
306 
307  // Loop over the positions and pin, if necessary
308  for (unsigned k = 0; k < n_dim; k++)
309  {
310  if (solid_bound_cons[k])
311  {
312  solid_node_pt->pin_position(k);
313  }
314  }
315  }
316 
317  // Next we update the boundary look-up schemes
318  // Loop over the boundaries stored in the set
319  for (std::set<unsigned>::iterator it = boundaries.begin();
320  it != boundaries.end();
321  ++it)
322  {
323  // Add the node to the boundary
324  mesh_pt->add_boundary_node(*it, this->node_pt(jnod));
325 
326  // If we have set an intrinsic coordinate on this
327  // mesh boundary then it must also be interpolated on
328  // the new node
329  // Now interpolate the intrinsic boundary coordinate
330  if (mesh_pt->boundary_coordinate_exists(*it) == true)
331  {
332  Vector<double> zeta(1);
333  son_el_pt->interpolated_zeta_on_edge(
334  *it, boundary, s_in_son, zeta);
335 
336  this->node_pt(jnod)->set_coordinates_on_boundary(*it, zeta);
337  }
338  }
339  }
340  // Otherwise the node is not on a Mesh boundary
341  // and we create a normal "bulk" node
342  else
343  {
344  // Construct the new node
345  this->node_pt(jnod) =
346  this->construct_node(jnod, time_stepper_pt);
347  }
348 
349  // Now we set the position and values at the newly created node
350 
351  // In the first instance use macro element or FE representation
352  // to create past and present nodal positions.
353  // (THIS STEP SHOULD NOT BE SKIPPED FOR ALGEBRAIC
354  // ELEMENTS AS NOT ALL OF THEM NECESSARILY IMPLEMENT
355  // NONTRIVIAL NODE UPDATE FUNCTIONS. CALLING
356  // THE NODE UPDATE FOR SUCH ELEMENTS/NODES WILL LEAVE
357  // THEIR NODAL POSITIONS WHERE THEY WERE (THIS IS APPROPRIATE
358  // ONCE THEY HAVE BEEN GIVEN POSITIONS) BUT WILL
359  // NOT ASSIGN SENSIBLE INITIAL POSITONS!
360 
361  // Loop over # of history values
362  // Loop over # of history values
363  for (unsigned t = 0; t < ntstorage; t++)
364  {
365  using namespace QuadTreeNames;
366  // Get the position from the son
367  Vector<double> x_prev(2);
368 
369  // Now let's fill in the value
370  son_el_pt->get_x(t, s_in_son, x_prev);
371  for (unsigned i = 0; i < 2; i++)
372  {
373  this->node_pt(jnod)->x(t, i) = x_prev[i];
374  }
375  }
376 
377  // Now set up the values
378  // Loop over all history values
379  for (unsigned t = 0; t < ntstorage; t++)
380  {
381  // Get values from father element
382  // Note: get_interpolated_values() sets Vector size itself.
383  Vector<double> prev_values;
384  son_el_pt->get_interpolated_values(t, s_in_son, prev_values);
385 
386  // Initialise the values at the new node
387  for (unsigned k = 0; k < this->node_pt(jnod)->nvalue(); k++)
388  {
389  this->node_pt(jnod)->set_value(t, k, prev_values[k]);
390  }
391  }
392 
393  // Add the node to the mesh
394  mesh_pt->add_node_pt(this->node_pt(jnod));
395 
396  } // End of the case when we build the node ourselvesx
397 
398  // Algebraic stuff here
399  // Check whether the element is an algebraic element
400  AlgebraicElementBase* alg_el_pt =
401  dynamic_cast<AlgebraicElementBase*>(this);
402 
403  // If we do have an algebraic element
404  if (alg_el_pt != 0)
405  {
406  std::string error_message =
407  "Have not implemented rebuilding from sons for";
408  error_message += "Algebraic Spectral elements yet\n";
409 
410  throw OomphLibError(
411  error_message,
412  "RefineableQSpectralElement::rebuild_from_sons()",
413  OOMPH_EXCEPTION_LOCATION);
414  }
415  }
416  }
417  }
418  }
419 
420 
421  /// Overload the nodes built function
422  virtual bool nodes_built()
423  {
424  unsigned n_node = this->nnode();
425  for (unsigned n = 0; n < n_node; n++)
426  {
427  if (node_pt(n) == 0)
428  {
429  return false;
430  }
431  }
432  // If we get to here, OK
433  return true;
434  }
435  };
436 
437 } // namespace oomph
438 
439 #endif
static char t char * s
Definition: cfortran.h:568
cstr elem_len * i
Definition: cfortran.h:603
char t
Definition: cfortran.h:568
////////////////////////////////////////////////////////////////////
void get_x(const Vector< double > &s, Vector< double > &x) const
Global coordinates as function of local coordinates. Either via FE representation or via macro-elemen...
Definition: elements.h:1889
A general mesh class.
Definition: mesh.h:67
void add_boundary_node(const unsigned &b, Node *const &node_pt)
Add a (pointer to) a node to the b-th boundary.
Definition: mesh.cc:243
void add_node_pt(Node *const &node_pt)
Add a (pointer to a) node to the mesh.
Definition: mesh.h:611
bool boundary_coordinate_exists(const unsigned &i) const
Indicate whether the i-th boundary has an intrinsic coordinate.
Definition: mesh.h:565
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:906
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
Definition: nodes.h:1054
An OomphLibError object which should be thrown when an run-time error is encountered....
RefineableElements are FiniteElements that may be subdivided into children to provide a better local ...
virtual void get_interpolated_values(const Vector< double > &s, Vector< double > &values)
Get all continously interpolated function values in this element as a Vector. Note: Vector sets is ow...
void get_boundaries(const int &edge, std::set< unsigned > &boundaries) const
Determine set of (mesh) boundaries that the element edge/vertex lives on.
void get_bcs(int bound, Vector< int > &bound_cons) const
Determine Vector of boundary conditions along edge (or on vertex) bound (S/W/N/E/SW/SE/NW/NE): For va...
void interpolated_zeta_on_edge(const unsigned &boundary, const int &edge, const Vector< double > &s, Vector< double > &zeta)
Return the value of the intrinsic boundary coordinate interpolated along the edge (S/W/N/E)
A class that is used to template the refineable Q elements by dimension. It's really nothing more tha...
Definition: Qelements.h:2259
Refineable version of QuadElements that add functionality for spectral Elements.
virtual ~RefineableQSpectralElement()
Broken assignment operator.
virtual bool nodes_built()
Overload the nodes built function.
void rebuild_from_sons(Mesh *&mesh_pt)
The only thing to add is rebuild from sons.
RefineableQSpectralElement(const RefineableQSpectralElement< 2 > &dummy)=delete
Broken copy constructor.
A class that is used to template the refineable Q spectral elements by dimension. It's really nothing...
Refineable version of Solid quad elements.
void get_solid_bcs(int bound, Vector< int > &solid_bound_cons) const
Determine vector of solid (positional) boundary conditions along edge (or on vertex) bound (S/W/N/E/S...
A Class for nodes that deform elastically (i.e. position is an unknown in the problem)....
Definition: nodes.h:1686
void pin_position(const unsigned &i)
Pin the nodal position.
Definition: nodes.h:1816
////////////////////////////////////////////////////////////////////// //////////////////////////////...
Definition: timesteppers.h:231
unsigned ntstorage() const
Return the number of doubles required to represent history (one for steady)
Definition: timesteppers.h:601
static const int OMEGA
Default value for an unassigned neighbour.
Definition: tree.h:262
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
long RefineableQElement< 2 > _build
//////////////////////////////////////////////////////////////////// ////////////////////////////////...