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-2022 Matthias Heil and Andrew Hazel
7// LIC//
8// LIC// This library is free software; you can redistribute it and/or
9// LIC// modify it under the terms of the GNU Lesser General Public
10// LIC// License as published by the Free Software Foundation; either
11// LIC// version 2.1 of the License, or (at your option) any later version.
12// LIC//
13// LIC// This library is distributed in the hope that it will be useful,
14// LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// LIC// Lesser General Public License for more details.
17// LIC//
18// LIC// You should have received a copy of the GNU Lesser General Public
19// LIC// License along with this library; if not, write to the Free Software
20// LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21// LIC// 02110-1301 USA.
22// LIC//
23// LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24// LIC//
25// LIC//====================================================================
26#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
39namespace oomph
40{
41 //=======================================================================
42 /// Refineable version of QuadElements that add functionality for spectral
43 /// Elements.
44 //=======================================================================
45 template<>
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
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:1885
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
//////////////////////////////////////////////////////////////////// ////////////////////////////////...