hp_refineable_elements.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-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 // Non-inline member functions for hp-refineable elements
27 
28 // oomph-lib includes
29 #include "algebraic_elements.h"
31 #include "hp_refineable_elements.h"
32 //#include "shape.h"
33 
34 namespace oomph
35 {
36  /// /////////////////////////////////////////////////////////////
37  // 1D PRefineableQElements
38  /// /////////////////////////////////////////////////////////////
39 
40  /// Get local coordinates of node j in the element; vector sets its own size
41  template<unsigned INITIAL_NNODE_1D>
43  const unsigned& n, Vector<double>& s) const
44  {
45  s.resize(1);
46 
47  switch (this->nnode_1d())
48  {
49  case 2:
52  break;
53  case 3:
56  break;
57  case 4:
60  break;
61  case 5:
64  break;
65  case 6:
68  break;
69  case 7:
72  break;
73  default:
74  oomph_info << "\n ERROR: Exceeded maximum polynomial order for";
75  oomph_info << "\n shape functions." << std::endl;
76  break;
77  }
78  }
79 
80  /// Get the local fractino of node j in the element
81  template<unsigned INITIAL_NNODE_1D>
83  const unsigned& n, Vector<double>& s_fraction)
84  {
85  this->local_coordinate_of_node(n, s_fraction);
86  s_fraction[0] = 0.5 * (s_fraction[0] + 1.0);
87  }
88 
89  template<unsigned INITIAL_NNODE_1D>
91  const unsigned& n1d, const unsigned& i)
92  {
93  switch (this->nnode_1d())
94  {
95  case 2:
97  return 0.5 *
99  case 3:
101  return 0.5 *
103  case 4:
105  return 0.5 *
107  case 5:
109  return 0.5 *
111  case 6:
113  return 0.5 *
115  case 7:
117  return 0.5 *
119  default:
120  std::ostringstream error_message;
121  error_message << "\nERROR: Exceeded maximum polynomial order for";
122  error_message << "\n shape functions.\n";
123  throw OomphLibError(error_message.str(),
124  OOMPH_CURRENT_FUNCTION,
125  OOMPH_EXCEPTION_LOCATION);
126  return 0.0;
127  }
128  }
129 
130 
131  //==================================================================
132  /// Return the node at the specified local coordinate
133  //==================================================================
134  template<unsigned INITIAL_NNODE_1D>
136  const Vector<double>& s) const
137  {
138  // Load the tolerance into a local variable
140  // There is one possible index.
141  Vector<int> index(1);
142 
143  // Determine the index
144  // -------------------
145 
146  // If we are at the lower limit, the index is zero
147  if (std::fabs(s[0] + 1.0) < tol)
148  {
149  index[0] = 0;
150  }
151  // If we are at the upper limit, the index is the number of nodes minus 1
152  else if (std::fabs(s[0] - 1.0) < tol)
153  {
154  index[0] = this->nnode_1d() - 1;
155  }
156  // Otherwise, we have to calculate the index in general
157  else
158  {
159  // Compute Gauss-Lobatto-Legendre node positions
160  Vector<double> z;
161  Orthpoly::gll_nodes(this->nnode_1d(), z);
162  // Loop over possible internal nodal positions
163  for (unsigned n = 1; n < this->nnode_1d() - 1; n++)
164  {
165  if (std::fabs(z[n] - s[0]) < tol)
166  {
167  index[0] = n;
168  break;
169  }
170  }
171  // No matching nodes
172  return 0;
173  }
174  // If we've got here we have a node, so let's return a pointer to it
175  return this->node_pt(index[0]);
176  }
177 
178  //===================================================================
179  /// If a neighbouring element's son has already created a node at
180  /// a position corresponding to the local fractional position within the
181  /// present element, s_fraction, return
182  /// a pointer to that node. If not, return NULL (0). If the node is
183  /// periodic the flag is_periodic will be true
184  //===================================================================
185  template<unsigned INITIAL_NNODE_1D>
188  bool& is_periodic)
189  {
190  // Not possible in 1D case, so return null pointer
191  return 0;
192  }
193 
194  //==================================================================
195  /// Set the correct p-order of the element based on that of its
196  /// father. Then construct an integration scheme of the correct order.
197  /// If an adopted father is specified, information from this is
198  /// used instead of using the father found from the tree.
199  //==================================================================
200  template<unsigned INITIAL_NNODE_1D>
202  Tree* const& adopted_father_pt, const unsigned& initial_p_order)
203  {
204  // Storage for pointer to my father (in binarytree impersonation)
205  BinaryTree* father_pt = 0;
206 
207  // Check if an adopted father has been specified
208  if (adopted_father_pt != 0)
209  {
210  // Get pointer to my father (in binarytree impersonation)
211  father_pt = dynamic_cast<BinaryTree*>(adopted_father_pt);
212  }
213  // Check if element is in a tree
214  else if (Tree_pt != 0)
215  {
216  // Get pointer to my father (in binarytree impersonation)
217  father_pt = dynamic_cast<BinaryTree*>(binary_tree_pt()->father_pt());
218  }
219  // else
220  // {
221  // throw OomphLibError(
222  // "Element not in a tree, and no adopted father has been
223  // specified!", OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
224  // }
225 
226  // Check if element has father
227  if (father_pt != 0 || initial_p_order != 0)
228  {
229  if (father_pt != 0)
230  {
233  father_pt->object_pt());
234  if (father_el_pt != 0)
235  {
236  unsigned father_p_order = father_el_pt->p_order();
237  // Set p-order to that of father
238  P_order = father_p_order;
239  }
240  }
241  else
242  {
243  P_order = initial_p_order;
244  }
245 
246  // Now sort out the element...
247  // (has p nodes)
248  unsigned new_n_node = P_order;
249 
250  // Allocate new space for Nodes (at the element level)
251  this->set_n_node(new_n_node);
252 
253  // Set integration scheme
254  delete this->integral_pt();
255  switch (P_order)
256  {
257  case 2:
258  this->set_integration_scheme(new GaussLobattoLegendre<1, 2>);
259  break;
260  case 3:
261  this->set_integration_scheme(new GaussLobattoLegendre<1, 3>);
262  break;
263  case 4:
264  this->set_integration_scheme(new GaussLobattoLegendre<1, 4>);
265  break;
266  case 5:
267  this->set_integration_scheme(new GaussLobattoLegendre<1, 5>);
268  break;
269  case 6:
270  this->set_integration_scheme(new GaussLobattoLegendre<1, 6>);
271  break;
272  case 7:
273  this->set_integration_scheme(new GaussLobattoLegendre<1, 7>);
274  break;
275  default:
276  std::ostringstream error_message;
277  error_message << "\nERROR: Exceeded maximum polynomial order for";
278  error_message << "\n integration scheme.\n";
279  throw OomphLibError(error_message.str(),
280  OOMPH_CURRENT_FUNCTION,
281  OOMPH_EXCEPTION_LOCATION);
282  }
283  }
284  }
285 
286  //==================================================================
287  /// Check the father element for any required nodes which
288  /// already exist
289  //==================================================================
290  template<unsigned INITIAL_NNODE_1D>
292  Mesh*& mesh_pt, Vector<Node*>& new_node_pt)
293  {
294  /*
295  //Pointer to my father (in binarytree impersonation)
296  BinaryTree* father_pt =
297  dynamic_cast<BinaryTree*>(binary_tree_pt()->father_pt());
298 
299  // Check if element has father
300  if (father_pt!=0)
301  {
302  PRefineableQElement<1>* father_el_pt =
303  dynamic_cast<PRefineableQElement<1>*>
304  (this->tree_pt()->father_pt()->object_pt());
305  if (father_el_pt!=0)
306  {
307  // Pre-build actions
308  //??
309  }
310  else
311  {
312  std::ostringstream error_message;
313  error_message <<"\nERROR: Dynamic cast failed!\n";
314  throw OomphLibError(error_message.str(),
315  OOMPH_CURRENT_FUNCTION,
316  OOMPH_EXCEPTION_LOCATION);
317  }
318  }
319  */
320  }
321 
322  //==================================================================
323  /// p-refine the element inc times. (If inc<0 then p-unrefinement
324  /// is performed.)
325  //==================================================================
326  template<unsigned INITIAL_NNODE_1D>
328  const int& inc, Mesh* const& mesh_pt, GeneralisedElement* const& clone_pt)
329  {
330  // Cast clone to correct type
332  dynamic_cast<PRefineableQElement<1, INITIAL_NNODE_1D>*>(clone_pt);
333 
334  // Check if we can use it
335  if (clone_el_pt == 0)
336  {
337  throw OomphLibError(
338  "Cloned copy must be a PRefineableQElement<1,INITIAL_NNODE_1D>!",
339  OOMPH_CURRENT_FUNCTION,
340  OOMPH_EXCEPTION_LOCATION);
341  }
342 #ifdef PARANOID
343  // Clone exists, so check that it is infact a copy of me
344  else
345  {
346  // Flag to keep track of check
347  bool clone_is_ok = true;
348 
349  // Does the clone have the correct p-order?
350  clone_is_ok = clone_is_ok && (clone_el_pt->p_order() == this->p_order());
351 
352  if (!clone_is_ok)
353  {
354  std::ostringstream err_stream;
355  err_stream << "Clone element has a different p-order from me,"
356  << std::endl
357  << "but it is supposed to be a copy!" << std::endl;
358 
359  throw OomphLibError(
360  err_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
361  }
362 
363  // Does the clone have the same number of nodes as me?
364  clone_is_ok = clone_is_ok && (clone_el_pt->nnode() == this->nnode());
365 
366  if (!clone_is_ok)
367  {
368  std::ostringstream err_stream;
369  err_stream << "Clone element has a different number of nodes from me,"
370  << std::endl
371  << "but it is supposed to be a copy!" << std::endl;
372 
373  throw OomphLibError(
374  err_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
375  }
376 
377  // Does the clone have the same nodes as me?
378  for (unsigned n = 0; n < this->nnode(); n++)
379  {
380  clone_is_ok =
381  clone_is_ok && (clone_el_pt->node_pt(n) == this->node_pt(n));
382  }
383 
384  if (!clone_is_ok)
385  {
386  std::ostringstream err_stream;
387  err_stream << "The nodes belonging to the clone element are different"
388  << std::endl
389  << "from mine, but it is supposed to be a copy!"
390  << std::endl;
391 
392  throw OomphLibError(
393  err_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
394  }
395 
396  // If we get to here then the clone has all the information we require
397  }
398 #endif
399 
400  // Currently we can't handle the case of generalised coordinates
401  // since we haven't established how they should be interpolated.
402  // Buffer this case:
403  if (clone_el_pt->node_pt(0)->nposition_type() != 1)
404  {
405  throw OomphLibError("Can't handle generalised nodal positions (yet).",
406  OOMPH_CURRENT_FUNCTION,
407  OOMPH_EXCEPTION_LOCATION);
408  }
409 
410  // Timestepper should be the same for all nodes -- use it
411  // to create timesteppers for new nodes
412  TimeStepper* time_stepper_pt = this->node_pt(0)->time_stepper_pt();
413 
414  // Get number of history values (incl. present)
415  unsigned ntstorage = time_stepper_pt->ntstorage();
416 
417  // Increment p-order of the element
418  P_order += inc;
419 
420  // Change integration scheme
421  delete this->integral_pt();
422  switch (P_order)
423  {
424  case 2:
425  this->set_integration_scheme(new GaussLobattoLegendre<1, 2>);
426  break;
427  case 3:
428  this->set_integration_scheme(new GaussLobattoLegendre<1, 3>);
429  break;
430  case 4:
431  this->set_integration_scheme(new GaussLobattoLegendre<1, 4>);
432  break;
433  case 5:
434  this->set_integration_scheme(new GaussLobattoLegendre<1, 5>);
435  break;
436  case 6:
437  this->set_integration_scheme(new GaussLobattoLegendre<1, 6>);
438  break;
439  case 7:
440  this->set_integration_scheme(new GaussLobattoLegendre<1, 7>);
441  break;
442  default:
443  std::ostringstream error_message;
444  error_message << "\nERROR: Exceeded maximum polynomial order for";
445  error_message << "\n integration scheme.\n";
446  throw OomphLibError(error_message.str(),
447  OOMPH_CURRENT_FUNCTION,
448  OOMPH_EXCEPTION_LOCATION);
449  }
450 
451  // Allocate new space for Nodes (at the element level)
452  this->set_n_node(P_order);
453 
454  // Copy vertex nodes and create new internal nodes
455  //------------------------------------------------
456 
457  // Setup vertex coordinates in element:
458  //-------------------------------------
459  Vector<double> s_left(1);
460  Vector<double> s_right(1);
461  s_left[0] = -1.0;
462  s_right[0] = 1.0;
463 
464  // Local coordinate in element
465  Vector<double> s(1);
466 
467  Vector<double> s_fraction(1);
468  // Loop over all nodes in the element
469  for (unsigned n = 0; n < P_order; n++)
470  {
471  // Get the fractional position (in the current element) of the node
472  // in the direction of s[0]
473  s_fraction[0] = this->local_one_d_fraction_of_node(n, 0);
474 
475  // Evaluate the local coordinate of the node in the father element
476  s[0] = s_left[0] + (s_right[0] - s_left[0]) * s_fraction[0];
477 
478  // Initialise flag: So far, this node hasn't been built or copied yet
479  bool node_done = false;
480 
481  // Get the pointer to the node in this element (or rather, its clone),
482  // returns NULL if there is not node
483  Node* created_node_pt = clone_el_pt->get_node_at_local_coordinate(s);
484 
485  // Does this node already exist in this element?
486  //----------------------------------------------
487  if (created_node_pt != 0)
488  {
489  // Copy node across
490  this->node_pt(n) = created_node_pt;
491 
492  // Make sure that we update the values at the node so that they
493  // are consistent with the present representation. This is only
494  // needed for mixed interpolation where the value at the father
495  // could now become active.
496 
497  // Loop over all history values
498  for (unsigned t = 0; t < ntstorage; t++)
499  {
500  // Get values from father element
501  // Note: get_interpolated_values() sets Vector size itself
502  Vector<double> prev_values;
503  clone_el_pt->get_interpolated_values(t, s, prev_values);
504  // Find the minimum number of values
505  //(either those stored at the node, or those returned by
506  // the function)
507  unsigned n_val_at_node = created_node_pt->nvalue();
508  unsigned n_val_from_function = prev_values.size();
509  // Use the ternary conditional operator here
510  unsigned n_var = n_val_at_node < n_val_from_function ?
511  n_val_at_node :
512  n_val_from_function;
513  // Assign the values that we can
514  for (unsigned k = 0; k < n_var; k++)
515  {
516  created_node_pt->set_value(t, k, prev_values[k]);
517  }
518  }
519 
520  // Indicate that node has been created by copy
521  node_done = true;
522  }
523 
524  // Node does not exist in this element
525  //------------------------------------
526 
527  // If the node has not been built anywhere ---> build it here
528  if (!node_done)
529  {
530  // In a 1D mesh any node which lies on the boundary must exist in
531  // the initial (coarse) mesh, so any newly-built nodes cannot be
532  // boundary nodes. Therefore we always create a normal "bulk" node.
533 
534  // Create node and set the pointer to it from the element
535  created_node_pt = this->construct_node(n, time_stepper_pt);
536 
537  // Now we set the position and values at the newly created node
538 
539  // Now we set the position and values at the newly created node.
540  // In the first instance use macro element or FE representation
541  // to create past and present nodal positions.
542  // (THIS STEP SHOULD NOT BE SKIPPED FOR ALGEBRAIC ELEMENTS AS NOT
543  // ALL OF THEM NECESSARILY IMPLEMENT NONTRIVIAL NODE UPDATE
544  // FUNCTIONS. CALLING THE NODE UPDATE FOR SUCH ELEMENTS/NODES WILL
545  // LEAVE THEIR NODAL POSITIONS WHERE THEY WERE (THIS IS APPROPRIATE
546  // ONCE THEY HAVE BEEN GIVEN POSITIONS) BUT WILL NOT ASSIGN SENSIBLE
547  // INITIAL POSITIONS!)
548 
549  // Loop over history values
550  for (unsigned t = 0; t < ntstorage; t++)
551  {
552  // Allocate storage for the previous position of the node
553  Vector<double> x_prev(1);
554 
555  // Get position from father element -- this uses the macro
556  // element representation if appropriate.
557  clone_el_pt->get_x(t, s, x_prev);
558 
559  // Set the previous position of the new node
560  created_node_pt->x(t, 0) = x_prev[0];
561 
562  // Allocate storage for the previous values at the node
563  // NOTE: the size of this vector is equal to the number of values
564  // (e.g. 3 velocity components and 1 pressure, say)
565  // associated with each node and NOT the number of history values
566  // which the node stores!
567  Vector<double> prev_values;
568 
569  // Get values from father element
570  // Note: get_interpolated_values() sets Vector size itself.
571  clone_el_pt->get_interpolated_values(t, s, prev_values);
572 
573  // Determine the number of values at the new node
574  const unsigned n_value = created_node_pt->nvalue();
575 
576  // Loop over all values and set the previous values
577  for (unsigned v = 0; v < n_value; v++)
578  {
579  created_node_pt->set_value(t, v, prev_values[v]);
580  }
581  } // End of loop over history values
582 
583  // Add new node to mesh (if requested)
584  if (mesh_pt != 0)
585  {
586  mesh_pt->add_node_pt(created_node_pt);
587  }
588 
589  AlgebraicElementBase* alg_el_pt =
590  dynamic_cast<AlgebraicElementBase*>(this);
591 
592  // If we do have an algebraic element
593  if (alg_el_pt != 0)
594  {
595  std::string error_message = "Have not implemented p-refinement for";
596  error_message += "Algebraic p-refineable elements yet\n";
597 
598  throw OomphLibError(
599  error_message,
600  "PRefineableQElement<1,INITIAL_NNODE_1D>::p_refine()",
601  OOMPH_EXCEPTION_LOCATION);
602  }
603 
604  } // End of case where we build the node ourselves
605 
606  // Check if the element is an algebraic element
607  AlgebraicElementBase* alg_el_pt =
608  dynamic_cast<AlgebraicElementBase*>(this);
609 
610  // If the element is an algebraic element, setup
611  // node position (past and present) from algebraic node update
612  // function. This over-writes previous assingments that
613  // were made based on the macro-element/FE representation.
614  // NOTE: YES, THIS NEEDS TO BE CALLED REPEATEDLY IF THE
615  // NODE IS MEMBER OF MULTIPLE ELEMENTS: THEY ALL ASSIGN
616  // THE SAME NODAL POSITIONS BUT WE NEED TO ADD THE REMESH
617  // INFO FOR *ALL* ROOT ELEMENTS!
618  if (alg_el_pt != 0)
619  {
620  // Build algebraic node update info for new node
621  // This sets up the node update data for all node update
622  // functions that are shared by all nodes in the father
623  // element
624  alg_el_pt->setup_algebraic_node_update(
625  this->node_pt(n), s, clone_el_pt);
626  }
627 
628  } // End of loop over all nodes in element
629 
630 
631  // If the element is a MacroElementNodeUpdateElement, set
632  // the update parameters for the current element's nodes --
633  // all this needs is the vector of (pointers to the)
634  // geometric objects that affect the MacroElement-based
635  // node update -- this needs to be done to set the node
636  // update info for newly created nodes
637  MacroElementNodeUpdateElementBase* clone_m_el_pt =
638  dynamic_cast<MacroElementNodeUpdateElementBase*>(clone_el_pt);
639  if (clone_m_el_pt != 0)
640  {
641  // Get vector of geometric objects from father (construct vector
642  // via copy operation)
643  Vector<GeomObject*> geom_object_pt(clone_m_el_pt->geom_object_pt());
644 
645  // Cast current element to MacroElementNodeUpdateElement:
647  dynamic_cast<MacroElementNodeUpdateElementBase*>(this);
648 
649 #ifdef PARANOID
650  if (m_el_pt == 0)
651  {
652  std::string error_message =
653  "Failed to cast to MacroElementNodeUpdateElementBase*\n";
654  error_message +=
655  "Strange -- if my clone is a MacroElementNodeUpdateElement\n";
656  error_message += "then I should be too....\n";
657 
658  throw OomphLibError(
659  error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
660  }
661 #endif
662  // Build update info by passing vector of geometric objects:
663  // This sets the current element to be the update element
664  // for all of the element's nodes -- this is reversed
665  // if the element is ever un-refined in the father element's
666  // rebuild_from_sons() function which overwrites this
667  // assignment to avoid nasty segmentation faults that occur
668  // when a node tries to update itself via an element that no
669  // longer exists...
670  m_el_pt->set_node_update_info(geom_object_pt);
671  }
672 
673 
674  // Loop over all nodes in element again, to re-set the positions
675  // This must be done using the new element's macro-element
676  // representation, rather than the old version which may be
677  // of a different p-order!
678  for (unsigned n = 0; n < P_order; n++)
679  {
680  // Get the fractional position of the node in the direction of s[0]
681  s_fraction[0] = this->local_one_d_fraction_of_node(n, 0);
682  // Local coordinate
683  s[0] = s_left[0] + (s_right[0] - s_left[0]) * s_fraction[0];
684 
685  // Loop over # of history values
686  for (unsigned t = 0; t < ntstorage; t++)
687  {
688  // Get position from father element -- this uses the macro
689  // element representation if appropriate. If the node
690  // turns out to be a hanging node later on, then
691  // its position gets adjusted in line with its
692  // hanging node interpolation.
693  Vector<double> x_prev(1);
694  this->get_x(t, s, x_prev);
695 
696  // Set previous positions of the new node
697  this->node_pt(n)->x(t, 0) = x_prev[0];
698  }
699  }
700 
701  // Not necessary to delete the old nodes since all original nodes are in the
702  // current mesh and so will be pruned as part of the mesh adaption process.
703 
704  // Do any further-build required
705  this->further_build();
706  }
707 
708  //=======================================================================
709  /// Shape functions for PRefineableQElement<DIM>
710  //=======================================================================
711  template<unsigned INITIAL_NNODE_1D>
713  Shape& psi) const
714  {
715  switch (p_order())
716  {
717  case 2:
718  {
719  // Calculate nodal positions
721  // Create one-dim shape functions
723  // Now let's loop over the nodal points in the element
724  // and copy the values back in
725  for (unsigned i = 0; i < p_order(); i++)
726  {
727  psi(i) = psi1[i];
728  }
729  break;
730  }
731  case 3:
732  {
733  // Calculate nodal positions
735  // Create one-dim shape functions
737  // Now let's loop over the nodal points in the element
738  // and copy the values back in
739  for (unsigned i = 0; i < p_order(); i++)
740  {
741  psi(i) = psi1[i];
742  }
743  break;
744  }
745  case 4:
746  {
747  // Calculate nodal positions
749  // Create one-dim shape functions
751  // Now let's loop over the nodal points in the element
752  // and copy the values back in
753  for (unsigned i = 0; i < p_order(); i++)
754  {
755  psi(i) = psi1[i];
756  }
757  break;
758  }
759  case 5:
760  {
761  // Calculate nodal positions
763  // Create one-dim shape functions
765  // Now let's loop over the nodal points in the element
766  // and copy the values back in
767  for (unsigned i = 0; i < p_order(); i++)
768  {
769  psi(i) = psi1[i];
770  }
771  break;
772  }
773  case 6:
774  {
775  // Calculate nodal positions
777  // Create one-dim shape functions
779  // Now let's loop over the nodal points in the element
780  // and copy the values back in
781  for (unsigned i = 0; i < p_order(); i++)
782  {
783  psi(i) = psi1[i];
784  }
785  break;
786  }
787  case 7:
788  {
789  // Calculate nodal positions
791  // Create one-dim shape functions
793  // Now let's loop over the nodal points in the element
794  // and copy the values back in
795  for (unsigned i = 0; i < p_order(); i++)
796  {
797  psi(i) = psi1[i];
798  }
799  break;
800  }
801  default:
802  oomph_info << "\n ERROR: PRefineableQElement::shape() exceeded maximum";
803  oomph_info << "\n polynomial order for shape functions."
804  << std::endl;
805  }
806  }
807 
808  //=======================================================================
809  /// Derivatives of shape functions for PRefineableQElement<DIM>
810  //=======================================================================
811  template<unsigned INITIAL_NNODE_1D>
813  const Vector<double>& s, Shape& psi, DShape& dpsi) const
814  {
815  switch (p_order())
816  {
817  case 2:
818  {
819  // Calculate nodal positions
821  // Call the shape functions and derivatives
824  // Loop over shapes and copy across
825  for (unsigned i = 0; i < p_order(); i++)
826  {
827  psi(i) = psi1[i];
828  dpsi(i, 0) = dpsi1ds[i];
829  }
830 
831  break;
832  }
833  case 3:
834  {
835  // Calculate nodal positions
837  // Call the shape functions and derivatives
840  // Loop over shapes and copy across
841  for (unsigned i = 0; i < p_order(); i++)
842  {
843  psi(i) = psi1[i];
844  dpsi(i, 0) = dpsi1ds[i];
845  }
846  break;
847  }
848  case 4:
849  {
850  // Calculate nodal positions
852  // Call the shape functions and derivatives
855  // Loop over shapes and copy across
856  for (unsigned i = 0; i < p_order(); i++)
857  {
858  psi(i) = psi1[i];
859  dpsi(i, 0) = dpsi1ds[i];
860  }
861  break;
862  }
863  case 5:
864  {
865  // Calculate nodal positions
867  // Call the shape functions and derivatives
870  // Loop over shapes and copy across
871  for (unsigned i = 0; i < p_order(); i++)
872  {
873  psi(i) = psi1[i];
874  dpsi(i, 0) = dpsi1ds[i];
875  }
876  break;
877  }
878  case 6:
879  {
880  // Calculate nodal positions
882  // Call the shape functions and derivatives
885  // Loop over shapes and copy across
886  for (unsigned i = 0; i < p_order(); i++)
887  {
888  psi(i) = psi1[i];
889  dpsi(i, 0) = dpsi1ds[i];
890  }
891  break;
892  }
893  case 7:
894  {
895  // Calculate nodal positions
897  // Call the shape functions and derivatives
900  // Loop over shapes and copy across
901  for (unsigned i = 0; i < p_order(); i++)
902  {
903  psi(i) = psi1[i];
904  dpsi(i, 0) = dpsi1ds[i];
905  }
906  break;
907  }
908  default:
909  oomph_info
910  << "\n ERROR: PRefineableQElement::dshape_local() exceeded maximum";
911  oomph_info << "\n polynomial order for shape functions."
912  << std::endl;
913  }
914  }
915 
916  //=======================================================================
917  /// Second derivatives of shape functions for PRefineableQElement<DIM>
918  /// d2psids(i,0) = \f$ d^2 \psi_j / d s^2 \f$
919  //=======================================================================
920  template<unsigned INITIAL_NNODE_1D>
922  const Vector<double>& s, Shape& psi, DShape& dpsids, DShape& d2psids) const
923  {
924  std::ostringstream error_message;
925  error_message
926  << "\nd2shape_local currently not implemented for this element\n";
927  throw OomphLibError(
928  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
929  }
930 
931  //=================================================================
932  /// Internal function to set up the hanging nodes on a particular
933  /// edge of the element. (Not required in 1D.)
934  //=================================================================
935  template<unsigned INITIAL_NNODE_1D>
937  const int& value_id, const int& my_edge, std::ofstream& output_hangfile)
938  {
939  }
940 
941  //=======================================================================
942  /// Rebuild the element from nodes found in its sons
943  /// Adjusts its p-order to be the maximum of its sons' p-orders
944  //=======================================================================
945  template<unsigned INITIAL_NNODE_1D>
947  Mesh*& mesh_pt)
948  {
949  // Get p-orders of sons
950  unsigned n_sons = this->tree_pt()->nsons();
951  Vector<unsigned> son_p_order(n_sons);
952  unsigned max_son_p_order = 0;
953  for (unsigned ison = 0; ison < n_sons; ison++)
954  {
955  PRefineableElement* el_pt = dynamic_cast<PRefineableElement*>(
956  this->tree_pt()->son_pt(ison)->object_pt());
957  son_p_order[ison] = el_pt->p_order();
958  if (son_p_order[ison] > max_son_p_order)
959  max_son_p_order = son_p_order[ison];
960  }
961 
962  unsigned old_Nnode = this->nnode();
963  unsigned old_P_order = this->p_order();
964  // Set p-order of the element
965  this->p_order() = max_son_p_order;
966 
967  // Change integration scheme
968  delete this->integral_pt();
969  switch (this->p_order())
970  {
971  case 2:
972  this->set_integration_scheme(new GaussLobattoLegendre<1, 2>);
973  break;
974  case 3:
975  this->set_integration_scheme(new GaussLobattoLegendre<1, 3>);
976  break;
977  case 4:
978  this->set_integration_scheme(new GaussLobattoLegendre<1, 4>);
979  break;
980  case 5:
981  this->set_integration_scheme(new GaussLobattoLegendre<1, 5>);
982  break;
983  case 6:
984  this->set_integration_scheme(new GaussLobattoLegendre<1, 6>);
985  break;
986  case 7:
987  this->set_integration_scheme(new GaussLobattoLegendre<1, 7>);
988  break;
989  default:
990  std::ostringstream error_message;
991  error_message << "\nERROR: Exceeded maximum polynomial order for";
992  error_message << "\n integration scheme.\n";
993  throw OomphLibError(error_message.str(),
994  OOMPH_CURRENT_FUNCTION,
995  OOMPH_EXCEPTION_LOCATION);
996  }
997 
998  // Back up pointers to old nodes before they are lost
999  Vector<Node*> old_node_pt(old_Nnode);
1000  for (unsigned n = 0; n < old_Nnode; n++)
1001  {
1002  old_node_pt[n] = this->node_pt(n);
1003  }
1004 
1005  // Allocate new space for Nodes (at the element level)
1006  this->set_n_node(this->p_order());
1007 
1008  // Copy vertex nodes and create new edge and internal nodes
1009  //---------------------------------------------------------
1010 
1011  // Copy vertex nodes
1012  this->node_pt(0) = old_node_pt[0];
1013  this->node_pt(this->p_order() - 1) = old_node_pt[old_P_order - 1];
1014 
1015 
1016  //=============================================================
1017  // Below this line is copied from RefineableQSpectralElement<2>
1018 
1019  // The timestepper should be the same for all nodes and node 0 should
1020  // never be deleted.
1021  if (this->node_pt(0) == 0)
1022  {
1023  throw OomphLibError("The vertex node (0) does not exist",
1024  OOMPH_CURRENT_FUNCTION,
1025  OOMPH_EXCEPTION_LOCATION);
1026  }
1027 
1028  TimeStepper* time_stepper_pt = this->node_pt(0)->time_stepper_pt();
1029 
1030  // Determine number of history values stored
1031  const unsigned ntstorage = time_stepper_pt->ntstorage();
1032 
1033  // Allocate storage for local coordinates
1034  Vector<double> s_fraction(1), s(1);
1035 
1036  // Determine the number of nodes in the element
1037  const unsigned n_node = this->nnode_1d();
1038 
1039  // Loop over the nodes in the element
1040  for (unsigned n = 0; n < n_node; n++)
1041  {
1042  // Get the fractional position of the node in the direction of s[0]
1043  s_fraction[0] = this->local_one_d_fraction_of_node(n, 0);
1044 
1045  // Determine the local coordinate in the father element
1046  s[0] = -1.0 + 2.0 * s_fraction[0];
1047 
1048  // If the node has not been built
1049  if (this->node_pt(n) == 0)
1050  {
1051  // Has the node been created by one of its neighbours?
1052  bool is_periodic = false;
1053  Node* created_node_pt =
1054  this->node_created_by_neighbour(s_fraction, is_periodic);
1055 
1056  // If it has, set the pointer
1057  if (created_node_pt != 0)
1058  {
1059  // If the node is periodic
1060  if (is_periodic)
1061  {
1062  throw OomphLibError("Cannot handle periodic nodes yet",
1063  OOMPH_CURRENT_FUNCTION,
1064  OOMPH_EXCEPTION_LOCATION);
1065  }
1066  // Non-periodic case, just set the pointer
1067  else
1068  {
1069  this->node_pt(n) = created_node_pt;
1070  }
1071  }
1072  // Otherwise, we need to build it
1073  else
1074  {
1075  // First, find the son element in which the node should live
1076 
1077  // Find coordinate in the son
1078  Vector<double> s_in_son(1);
1079  using namespace BinaryTreeNames;
1080  int son = -10;
1081  // If s_fraction is between 0 and 0.5, we are in the left son
1082  if (s_fraction[0] < 0.5)
1083  {
1084  son = L;
1085  s_in_son[0] = -1.0 + 4.0 * s_fraction[0];
1086  }
1087  // Otherwise we are in the right son
1088  else
1089  {
1090  son = R;
1091  s_in_son[0] = -1.0 + 4.0 * (s_fraction[0] - 0.5);
1092  }
1093 
1094  // Get the pointer to the son element in which the new node
1095  // would live
1098  this->tree_pt()->son_pt(son)->object_pt());
1099 
1100  // In 1D we should never be rebuilding an element's vertex nodes
1101  // (since they will never be deleted), so throw an error if we
1102  // appear to be doing so
1103 #ifdef PARANOID
1104  if (n == 0 || n == n_node - 1)
1105  {
1106  std::string error_message =
1107  "I am trying to rebuild one of the (two) vertex nodes in\n";
1108  error_message +=
1109  "this 1D element. It should not have been possible to delete\n";
1110  error_message += "either of these!\n";
1111 
1112  throw OomphLibError(
1113  error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1114  }
1115 #endif
1116 
1117  // With this in mind we will always be creating normal "bulk" nodes
1118  this->node_pt(n) = this->construct_node(n, time_stepper_pt);
1119 
1120  // Now we set the position and values at the newly created node
1121 
1122  // In the first instance use macro element or FE representation
1123  // to create past and present nodal positions.
1124  // (THIS STEP SHOULD NOT BE SKIPPED FOR ALGEBRAIC ELEMENTS AS NOT
1125  // ALL OF THEM NECESSARILY IMPLEMENT NONTRIVIAL NODE UPDATE
1126  // FUNCTIONS. CALLING THE NODE UPDATE FOR SUCH ELEMENTS/NODES WILL
1127  // LEAVE THEIR NODAL POSITIONS WHERE THEY WERE (THIS IS APPROPRIATE
1128  // ONCE THEY HAVE BEEN GIVEN POSITIONS) BUT WILL NOT ASSIGN SENSIBLE
1129  // INITIAL POSITIONS!)
1130 
1131  // Loop over history values
1132  for (unsigned t = 0; t < ntstorage; t++)
1133  {
1134  // Allocate storage for the previous position of the node
1135  Vector<double> x_prev(1);
1136 
1137  // Get position from son element -- this uses the macro element
1138  // representation if appropriate
1139  son_el_pt->get_x(t, s_in_son, x_prev);
1140 
1141  // Set the previous position of the new node
1142  this->node_pt(n)->x(t, 0) = x_prev[0];
1143 
1144  // Allocate storage for the previous values at the node
1145  // NOTE: the size of this vector is equal to the number of values
1146  // (e.g. 3 velocity components and 1 pressure, say)
1147  // associated with each node and NOT the number of history values
1148  // which the node stores!
1149  Vector<double> prev_values;
1150 
1151  // Get values from son element
1152  // Note: get_interpolated_values() sets Vector size itself.
1153  son_el_pt->get_interpolated_values(t, s_in_son, prev_values);
1154 
1155  // Determine the number of values at the new node
1156  const unsigned n_value = this->node_pt(n)->nvalue();
1157 
1158  // Loop over all values and set the previous values
1159  for (unsigned v = 0; v < n_value; v++)
1160  {
1161  this->node_pt(n)->set_value(t, v, prev_values[v]);
1162  }
1163  } // End of loop over history values
1164 
1165  // Add new node to mesh
1166  mesh_pt->add_node_pt(this->node_pt(n));
1167 
1168  } // End of case where we build the node ourselves
1169 
1170  } // End of if this node has not been built
1171  } // End of loop over nodes in element
1172 
1173  // Check if the element is an algebraic element
1174  // This is done on all nodes in the element after reconstruction
1175  // rather than as the nodes are built
1176  AlgebraicElementBase* alg_el_pt = dynamic_cast<AlgebraicElementBase*>(this);
1177 
1178  // If so, throw error
1179  if (alg_el_pt != 0)
1180  {
1181  std::string error_message =
1182  "Have not implemented rebuilding from sons for";
1183  error_message += "Algebraic p-refineable elements yet\n";
1184 
1185  throw OomphLibError(
1186  error_message,
1187  "PRefineableQElement<1,INITIAL_NNODE_1D>::rebuild_from_sons()",
1188  OOMPH_EXCEPTION_LOCATION);
1189  }
1190  }
1191 
1192  //=================================================================
1193  /// Check inter-element continuity of
1194  /// - nodal positions
1195  /// - (nodally) interpolated function values
1196  //====================================================================
1197  template<unsigned INITIAL_NNODE_1D>
1199  double& max_error)
1200  {
1202  }
1203 
1204  /// /////////////////////////////////////////////////////////////
1205  // 2D PRefineableQElements
1206  /// /////////////////////////////////////////////////////////////
1207 
1208  /// Get local coordinates of node j in the element; vector sets its own size
1209  template<unsigned INITIAL_NNODE_1D>
1211  const unsigned& n, Vector<double>& s) const
1212  {
1213  s.resize(2);
1214  unsigned Nnode_1d = this->nnode_1d();
1215  unsigned n0 = n % Nnode_1d;
1216  unsigned n1 = n / Nnode_1d;
1217 
1218  switch (Nnode_1d)
1219  {
1220  case 2:
1224  break;
1225  case 3:
1229  break;
1230  case 4:
1234  break;
1235  case 5:
1239  break;
1240  case 6:
1244  break;
1245  case 7:
1249  break;
1250  default:
1251  std::ostringstream error_message;
1252  error_message << "\nERROR: Exceeded maximum polynomial order for";
1253  error_message << "\n shape functions.\n";
1254  throw OomphLibError(error_message.str(),
1255  OOMPH_CURRENT_FUNCTION,
1256  OOMPH_EXCEPTION_LOCATION);
1257  break;
1258  }
1259  }
1260 
1261  /// Get the local fractino of node j in the element
1262  template<unsigned INITIAL_NNODE_1D>
1264  const unsigned& n, Vector<double>& s_fraction)
1265  {
1266  this->local_coordinate_of_node(n, s_fraction);
1267  s_fraction[0] = 0.5 * (s_fraction[0] + 1.0);
1268  s_fraction[1] = 0.5 * (s_fraction[1] + 1.0);
1269  }
1270 
1271  template<unsigned INITIAL_NNODE_1D>
1273  const unsigned& n1d, const unsigned& i)
1274  {
1275  switch (this->nnode_1d())
1276  {
1277  case 2:
1279  return 0.5 *
1281  case 3:
1283  return 0.5 *
1285  case 4:
1287  return 0.5 *
1289  case 5:
1291  return 0.5 *
1293  case 6:
1295  return 0.5 *
1297  case 7:
1299  return 0.5 *
1301  default:
1302  std::ostringstream error_message;
1303  error_message << "\nERROR: Exceeded maximum polynomial order for";
1304  error_message << "\n shape functions.\n";
1305  throw OomphLibError(error_message.str(),
1306  OOMPH_CURRENT_FUNCTION,
1307  OOMPH_EXCEPTION_LOCATION);
1308  return 0.0;
1309  }
1310  }
1311 
1312 
1313  //==================================================================
1314  /// Return the node at the specified local coordinate
1315  //==================================================================
1316  template<unsigned INITIAL_NNODE_1D>
1318  const Vector<double>& s) const
1319  {
1320  unsigned Nnode_1d = this->nnode_1d();
1321  // Load the tolerance into a local variable
1323  // There are two possible indices.
1324  Vector<int> index(2);
1325 
1326  // Loop over indices
1327  for (unsigned i = 0; i < 2; i++)
1328  {
1329  // Determine the index
1330  // -------------------
1331 
1332  bool is_found = false;
1333 
1334  // If we are at the lower limit, the index is zero
1335  if (std::fabs(s[i] + 1.0) < tol)
1336  {
1337  index[i] = 0;
1338  is_found = true;
1339  }
1340  // If we are at the upper limit, the index is the number of nodes minus 1
1341  else if (std::fabs(s[i] - 1.0) < tol)
1342  {
1343  index[i] = Nnode_1d - 1;
1344  is_found = true;
1345  }
1346  // Otherwise, we have to calculate the index in general
1347  else
1348  {
1349  // Compute Gauss-Lobatto-Legendre node positions
1350  Vector<double> z;
1351  Orthpoly::gll_nodes(Nnode_1d, z);
1352  // Loop over possible internal nodal positions
1353  for (unsigned n = 1; n < Nnode_1d - 1; n++)
1354  {
1355  if (std::fabs(z[n] - s[i]) < tol)
1356  {
1357  index[i] = n;
1358  is_found = true;
1359  break;
1360  }
1361  }
1362  }
1363 
1364  if (!is_found)
1365  {
1366  // No matching nodes
1367  return 0;
1368  }
1369  }
1370  // If we've got here we have a node, so let's return a pointer to it
1371  return this->node_pt(index[0] + Nnode_1d * index[1]);
1372  }
1373 
1374  //===================================================================
1375  /// If a neighbouring element has already created a node at
1376  /// a position corresponding to the local fractional position within the
1377  /// present element, s_fraction, return
1378  /// a pointer to that node. If not, return NULL (0). If the node is
1379  /// periodic the flag is_periodic will be true
1380  //===================================================================
1381  template<unsigned INITIAL_NNODE_1D>
1383  const Vector<double>& s_fraction, bool& is_periodic)
1384  {
1385  using namespace QuadTreeNames;
1386 
1387  // Calculate the edges on which the node lies
1388  Vector<int> edges;
1389  if (s_fraction[0] == 0.0)
1390  {
1391  edges.push_back(W);
1392  }
1393  if (s_fraction[0] == 1.0)
1394  {
1395  edges.push_back(E);
1396  }
1397  if (s_fraction[1] == 0.0)
1398  {
1399  edges.push_back(S);
1400  }
1401  if (s_fraction[1] == 1.0)
1402  {
1403  edges.push_back(N);
1404  }
1405 
1406  // Find the number of edges
1407  unsigned n_size = edges.size();
1408  // If there are no edges, then there is no neighbour, return 0
1409  if (n_size == 0)
1410  {
1411  return 0;
1412  }
1413 
1414  Vector<unsigned> translate_s(2);
1415  Vector<double> s_lo_neigh(2);
1416  Vector<double> s_hi_neigh(2);
1417  Vector<double> s(2);
1418 
1419  int neigh_edge, diff_level;
1420  bool in_neighbouring_tree;
1421 
1422  // Loop over the edges
1423  for (unsigned j = 0; j < n_size; j++)
1424  {
1425  // Find pointer to neighbouring element along edge
1426  QuadTree* neigh_pt;
1427  neigh_pt = quadtree_pt()->gteq_edge_neighbour(edges[j],
1428  translate_s,
1429  s_lo_neigh,
1430  s_hi_neigh,
1431  neigh_edge,
1432  diff_level,
1433  in_neighbouring_tree);
1434 
1435  // Neighbour exists
1436  if (neigh_pt != 0)
1437  {
1438  // Have any of its vertex nodes been created yet?
1439  // (Must look in incomplete neighbours because after the
1440  // pre-build they may contain pointers to the required nodes. e.g.
1441  // h-refinement of neighbouring linear and quadratic elements)
1442  bool a_vertex_node_is_built = false;
1443  QElement<2, INITIAL_NNODE_1D>* neigh_obj_pt =
1444  dynamic_cast<QElement<2, INITIAL_NNODE_1D>*>(neigh_pt->object_pt());
1445  if (neigh_obj_pt == 0)
1446  {
1447  throw OomphLibError("Not a quad element!",
1448  "PRefineableQElement<2,INITIAL_NNODE_1D>::node_"
1449  "created_by_neighbour()",
1450  OOMPH_EXCEPTION_LOCATION);
1451  }
1452  for (unsigned vnode = 0; vnode < neigh_obj_pt->nvertex_node(); vnode++)
1453  {
1454  if (neigh_obj_pt->vertex_node_pt(vnode) != 0)
1455  a_vertex_node_is_built = true;
1456  break;
1457  }
1458  if (a_vertex_node_is_built)
1459  {
1460  // We now need to translate the nodal location
1461  // as defined in terms of the fractional coordinates of the present
1462  // element into those of its neighbour
1463 
1464  // Calculate the local coordinate in the neighbour
1465  // Note that we need to use the translation scheme in case
1466  // the local coordinates are swapped in the neighbour.
1467  for (unsigned i = 0; i < 2; i++)
1468  {
1469  s[i] = s_lo_neigh[i] +
1470  s_fraction[translate_s[i]] * (s_hi_neigh[i] - s_lo_neigh[i]);
1471  }
1472 
1473  // Find the node in the neighbour
1474  Node* neighbour_node_pt =
1476 
1477  // If there is a node, return it
1478  if (neighbour_node_pt != 0)
1479  {
1480  // Now work out whether it's a periodic boundary
1481  // only possible if we have moved into a neighbouring tree
1482  if (in_neighbouring_tree)
1483  {
1484  // Return whether the neighbour is periodic
1485  is_periodic =
1486  quadtree_pt()->root_pt()->is_neighbour_periodic(edges[j]);
1487  }
1488  // Return the pointer to the neighbouring node
1489  return neighbour_node_pt;
1490  }
1491  }
1492  }
1493  }
1494  // Node not found, return null
1495  return 0;
1496  }
1497 
1498  //===================================================================
1499  /// If a neighbouring element's son has already created a node at
1500  /// a position corresponding to the local fractional position within the
1501  /// present element, s_fraction, return
1502  /// a pointer to that node. If not, return NULL (0). If the node is
1503  /// periodic the flag is_periodic will be true
1504  //===================================================================
1505  template<unsigned INITIAL_NNODE_1D>
1508  bool& is_periodic)
1509  {
1510  using namespace QuadTreeNames;
1511 
1512  // Calculate the edges on which the node lies
1513  Vector<int> edges;
1514  if (s_fraction[0] == 0.0)
1515  {
1516  edges.push_back(W);
1517  }
1518  if (s_fraction[0] == 1.0)
1519  {
1520  edges.push_back(E);
1521  }
1522  if (s_fraction[1] == 0.0)
1523  {
1524  edges.push_back(S);
1525  }
1526  if (s_fraction[1] == 1.0)
1527  {
1528  edges.push_back(N);
1529  }
1530 
1531  // Find the number of edges
1532  unsigned n_size = edges.size();
1533  // If there are no edges, then there is no neighbour, return 0
1534  if (n_size == 0)
1535  {
1536  return 0;
1537  }
1538 
1539  Vector<unsigned> translate_s(2);
1540  Vector<double> s_lo_neigh(2);
1541  Vector<double> s_hi_neigh(2);
1542  Vector<double> s(2);
1543 
1544  int neigh_edge, diff_level;
1545  bool in_neighbouring_tree;
1546 
1547  // Loop over the edges
1548  for (unsigned j = 0; j < n_size; j++)
1549  {
1550  // Find pointer to neighbouring element along edge
1551  QuadTree* neigh_pt;
1552  neigh_pt = quadtree_pt()->gteq_edge_neighbour(edges[j],
1553  translate_s,
1554  s_lo_neigh,
1555  s_hi_neigh,
1556  neigh_edge,
1557  diff_level,
1558  in_neighbouring_tree);
1559 
1560  // Neighbour exists
1561  if (neigh_pt != 0)
1562  {
1563  // Have its nodes been created yet?
1564  // (Must look in sons of unfinished neighbours too!!!)
1565  if (1)
1566  {
1567  // We now need to translate the nodal location
1568  // as defined in terms of the fractional coordinates of the present
1569  // element into those of its neighbour
1570 
1571  // Calculate the local coordinate in the neighbour
1572  // Note that we need to use the translation scheme in case
1573  // the local coordinates are swapped in the neighbour.
1574  for (unsigned i = 0; i < 2; i++)
1575  {
1576  s[i] = s_lo_neigh[i] +
1577  s_fraction[translate_s[i]] * (s_hi_neigh[i] - s_lo_neigh[i]);
1578  }
1579 
1580  // Check if the element has sons
1581  if (neigh_pt->nsons() != 0)
1582  {
1583  // First, find the son element in which the node should live
1584 
1585  // Find coordinates in the sons
1586  Vector<double> s_in_son(2);
1587  int son = -10;
1588  // If negative on the west side
1589  if (s[0] < 0.0)
1590  {
1591  // On the south side
1592  if (s[1] < 0.0)
1593  {
1594  // It's the southwest son
1595  son = SW;
1596  s_in_son[0] = 1.0 + 2.0 * s[0];
1597  s_in_son[1] = 1.0 + 2.0 * s[1];
1598  }
1599  // On the north side
1600  else
1601  {
1602  // It's the northwest son
1603  son = NW;
1604  s_in_son[0] = 1.0 + 2.0 * s[0];
1605  s_in_son[1] = -1.0 + 2.0 * s[1];
1606  }
1607  }
1608  else
1609  {
1610  // On the south side
1611  if (s[1] < 0.0)
1612  {
1613  // It's the southeast son
1614  son = SE;
1615  s_in_son[0] = -1.0 + 2.0 * s[0];
1616  s_in_son[1] = 1.0 + 2.0 * s[1];
1617  }
1618  // On the north side
1619  else
1620  {
1621  // It's the northeast son
1622  son = NE;
1623  s_in_son[0] = -1.0 + 2.0 * s[0];
1624  s_in_son[1] = -1.0 + 2.0 * s[1];
1625  }
1626  }
1627 
1628  // Find the node in the neighbour's son
1629  Node* neighbour_son_node_pt =
1630  neigh_pt->son_pt(son)->object_pt()->get_node_at_local_coordinate(
1631  s_in_son);
1632 
1633  // If there is a node, return it
1634  if (neighbour_son_node_pt != 0)
1635  {
1636  // Now work out whether it's a periodic boundary
1637  // only possible if we have moved into a neighbouring tree
1638  if (in_neighbouring_tree)
1639  {
1640  // Return whether the neighbour is periodic
1641  is_periodic =
1642  quadtree_pt()->root_pt()->is_neighbour_periodic(edges[j]);
1643  }
1644  // Return the pointer to the neighbouring node
1645  return neighbour_son_node_pt;
1646  }
1647  }
1648  else
1649  {
1650  // No sons to search in, so no node can be found
1651  return 0;
1652  }
1653  }
1654  }
1655  }
1656  // Node not found, return null
1657  return 0;
1658  }
1659 
1660  //==================================================================
1661  /// Set the correct p-order of the element based on that of its
1662  /// father. Then construct an integration scheme of the correct order.
1663  /// If an adopted father is specified, information from this is
1664  /// used instead of using the father found from the tree.
1665  //==================================================================
1666  template<unsigned INITIAL_NNODE_1D>
1668  Tree* const& adopted_father_pt, const unsigned& initial_p_order)
1669  {
1670  // Storage for pointer to my father (in quadtree impersonation)
1671  QuadTree* father_pt = 0;
1672 
1673  // Check if an adopted father has been specified
1674  if (adopted_father_pt != 0)
1675  {
1676  // Get pointer to my father (in quadtree impersonation)
1677  father_pt = dynamic_cast<QuadTree*>(adopted_father_pt);
1678  }
1679  // Check if element is in a tree
1680  else if (Tree_pt != 0)
1681  {
1682  // Get pointer to my father (in quadtree impersonation)
1683  father_pt = dynamic_cast<QuadTree*>(quadtree_pt()->father_pt());
1684  }
1685  // else
1686  // {
1687  // throw OomphLibError(
1688  // "Element not in a tree, and no adopted father has been
1689  // specified!", OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1690  // }
1691 
1692  // Check if we found a father
1693  if (father_pt != 0 || initial_p_order != 0)
1694  {
1695  if (father_pt != 0)
1696  {
1699  father_pt->object_pt());
1700  if (father_el_pt != 0)
1701  {
1702  unsigned father_p_order = father_el_pt->p_order();
1703  // Set p-order to that of father
1704  P_order = father_p_order;
1705  }
1706  }
1707  else
1708  {
1709  P_order = initial_p_order;
1710  }
1711 
1712  // Now sort out the element...
1713  // (has p^2 nodes)
1714  unsigned new_n_node = P_order * P_order;
1715 
1716  // Allocate new space for Nodes (at the element level)
1717  this->set_n_node(new_n_node);
1718 
1719  // Set integration scheme
1720  delete this->integral_pt();
1721  switch (P_order)
1722  {
1723  case 2:
1724  this->set_integration_scheme(new GaussLobattoLegendre<2, 2>);
1725  break;
1726  case 3:
1727  this->set_integration_scheme(new GaussLobattoLegendre<2, 3>);
1728  break;
1729  case 4:
1730  this->set_integration_scheme(new GaussLobattoLegendre<2, 4>);
1731  break;
1732  case 5:
1733  this->set_integration_scheme(new GaussLobattoLegendre<2, 5>);
1734  break;
1735  case 6:
1736  this->set_integration_scheme(new GaussLobattoLegendre<2, 6>);
1737  break;
1738  case 7:
1739  this->set_integration_scheme(new GaussLobattoLegendre<2, 7>);
1740  break;
1741  default:
1742  std::ostringstream error_message;
1743  error_message << "\nERROR: Exceeded maximum polynomial order for";
1744  error_message << "\n integration scheme.\n";
1745  throw OomphLibError(error_message.str(),
1746  OOMPH_CURRENT_FUNCTION,
1747  OOMPH_EXCEPTION_LOCATION);
1748  }
1749  }
1750  }
1751 
1752  //==================================================================
1753  /// Check the father element for any required nodes which
1754  /// already exist
1755  //==================================================================
1756  template<unsigned INITIAL_NNODE_1D>
1758  Mesh*& mesh_pt, Vector<Node*>& new_node_pt)
1759  {
1760  using namespace QuadTreeNames;
1761 
1762  // Get the number of 1d nodes
1763  unsigned n_p = nnode_1d();
1764 
1765  // Check whether static father_bound needs to be created
1766  if (Father_bound[n_p].nrow() == 0)
1767  {
1768  setup_father_bounds();
1769  }
1770 
1771  // Pointer to my father (in quadtree impersonation)
1772  QuadTree* father_pt = dynamic_cast<QuadTree*>(quadtree_pt()->father_pt());
1773 
1774  // What type of son am I? Ask my quadtree representation...
1775  int son_type = Tree_pt->son_type();
1776 
1777  // Has somebody build me already? (If any nodes have not been built)
1778  if (!nodes_built())
1779  {
1780 #ifdef PARANOID
1781  if (father_pt == 0)
1782  {
1783  std::string error_message =
1784  "Something fishy here: I have no father and yet \n";
1785  error_message += "I have no nodes. Who has created me then?!\n";
1786 
1787  throw OomphLibError(
1788  error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1789  }
1790 #endif
1791 
1792  // Return pointer to father element
1793  RefineableQElement<2>* father_el_pt =
1794  dynamic_cast<RefineableQElement<2>*>(father_pt->object_pt());
1795 
1796  // Timestepper should be the same for all nodes in father
1797  // element -- use it create timesteppers for new nodes
1798  TimeStepper* time_stepper_pt =
1799  father_el_pt->node_pt(0)->time_stepper_pt();
1800 
1801  // Number of history values (incl. present)
1802  unsigned ntstorage = time_stepper_pt->ntstorage();
1803 
1804  Vector<double> s_lo(2);
1805  Vector<double> s_hi(2);
1806  Vector<double> s(2);
1807  Vector<double> x(2);
1808 
1809  // Setup vertex coordinates in father element:
1810  //--------------------------------------------
1811  switch (son_type)
1812  {
1813  case SW:
1814  s_lo[0] = -1.0;
1815  s_hi[0] = 0.0;
1816  s_lo[1] = -1.0;
1817  s_hi[1] = 0.0;
1818  break;
1819 
1820  case SE:
1821  s_lo[0] = 0.0;
1822  s_hi[0] = 1.0;
1823  s_lo[1] = -1.0;
1824  s_hi[1] = 0.0;
1825  break;
1826 
1827  case NE:
1828  s_lo[0] = 0.0;
1829  s_hi[0] = 1.0;
1830  s_lo[1] = 0.0;
1831  s_hi[1] = 1.0;
1832  break;
1833 
1834  case NW:
1835  s_lo[0] = -1.0;
1836  s_hi[0] = 0.0;
1837  s_lo[1] = 0.0;
1838  s_hi[1] = 1.0;
1839  break;
1840  }
1841 
1842  // Pass macro element pointer on to sons and
1843  // set coordinates in macro element
1844  // hierher why can I see this?
1845  if (father_el_pt->macro_elem_pt() != 0)
1846  {
1847  set_macro_elem_pt(father_el_pt->macro_elem_pt());
1848  for (unsigned i = 0; i < 2; i++)
1849  {
1850  s_macro_ll(i) =
1851  father_el_pt->s_macro_ll(i) +
1852  0.5 * (s_lo[i] + 1.0) *
1853  (father_el_pt->s_macro_ur(i) - father_el_pt->s_macro_ll(i));
1854  s_macro_ur(i) =
1855  father_el_pt->s_macro_ll(i) +
1856  0.5 * (s_hi[i] + 1.0) *
1857  (father_el_pt->s_macro_ur(i) - father_el_pt->s_macro_ll(i));
1858  }
1859  }
1860 
1861 
1862  // If the father element hasn't been generated yet, we're stuck...
1863  if (father_el_pt->node_pt(0) == 0)
1864  {
1865  throw OomphLibError(
1866  "Trouble: father_el_pt->node_pt(0)==0\n Can't build son element!\n",
1867  OOMPH_CURRENT_FUNCTION,
1868  OOMPH_EXCEPTION_LOCATION);
1869  }
1870  else
1871  {
1872  unsigned jnod = 0;
1873  Vector<double> x_small(2);
1874  Vector<double> x_large(2);
1875 
1876  Vector<double> s_fraction(2);
1877  // Loop over nodes in element
1878  for (unsigned i0 = 0; i0 < n_p; i0++)
1879  {
1880  // Get the fractional position of the node in the direction of s[0]
1881  s_fraction[0] = this->local_one_d_fraction_of_node(i0, 0);
1882  // Local coordinate in father element
1883  s[0] = s_lo[0] + (s_hi[0] - s_lo[0]) * s_fraction[0];
1884 
1885  for (unsigned i1 = 0; i1 < n_p; i1++)
1886  {
1887  // Get the fractional position of the node in the direction of s[1]
1888  s_fraction[1] = this->local_one_d_fraction_of_node(i1, 1);
1889  // Local coordinate in father element
1890  s[1] = s_lo[1] + (s_hi[1] - s_lo[1]) * s_fraction[1];
1891 
1892  // Local node number
1893  jnod = i0 + n_p * i1;
1894 
1895  // Check whether the father's node is periodic if so, complain
1896  /* {
1897  Node* father_node_pt = father_el_pt->node_pt(jnod);
1898  if((father_node_pt->is_a_copy()) ||
1899  (father_node_pt->position_is_a_copy()))
1900  {
1901  throw OomphLibError(
1902  "Can't handle periodic nodes (yet).",
1903  OOMPH_CURRENT_FUNCTION,
1904  OOMPH_EXCEPTION_LOCATION);
1905  }
1906  }*/
1907 
1908  // Initialise flag: So far, this node hasn't been built
1909  // or copied yet
1910  // bool node_done=false;
1911 
1912  // Get the pointer to the node in the father, returns NULL
1913  // if there is not node
1914  Node* created_node_pt =
1915  father_el_pt->get_node_at_local_coordinate(s);
1916 
1917  // Does this node already exist in father element?
1918  //------------------------------------------------
1919  if (created_node_pt != 0)
1920  {
1921  // Copy node across
1922  this->node_pt(jnod) = created_node_pt;
1923 
1924  // Make sure that we update the values at the node so that
1925  // they are consistent with the present representation.
1926  // This is only need for mixed interpolation where the value
1927  // at the father could now become active.
1928 
1929  // Loop over all history values
1930  for (unsigned t = 0; t < ntstorage; t++)
1931  {
1932  // Get values from father element
1933  // Note: get_interpolated_values() sets Vector size itself.
1934  Vector<double> prev_values;
1935  father_el_pt->get_interpolated_values(t, s, prev_values);
1936  // Find the minimum number of values
1937  //(either those stored at the node, or those returned by
1938  // the function)
1939  unsigned n_val_at_node = created_node_pt->nvalue();
1940  unsigned n_val_from_function = prev_values.size();
1941  // Use the ternary conditional operator here
1942  unsigned n_var = n_val_at_node < n_val_from_function ?
1943  n_val_at_node :
1944  n_val_from_function;
1945  // Assign the values that we can
1946  for (unsigned k = 0; k < n_var; k++)
1947  {
1948  created_node_pt->set_value(t, k, prev_values[k]);
1949  }
1950  }
1951 
1952  // Node has been created by copy
1953  // node_done=true;
1954  }
1955  } // End of vertical loop over nodes in element
1956  } // End of horizontal loop over nodes in element
1957  } // Sanity check: Father element has been generated
1958 
1959  } // End of nodes not built
1960  else
1961  {
1962  // If this is element updates by macro element node update then we need
1963  // to set the correct info in the nodes here since this won't get done
1964  // later in build() because we already have all our nodes created.
1966  dynamic_cast<MacroElementNodeUpdateElementBase*>(this);
1967  if (m_el_pt != 0)
1968  {
1969  // Get vector of geometric objects
1970  Vector<GeomObject*> geom_object_pt = m_el_pt->geom_object_pt();
1971 
1972  /// / Build update info by passing vector of geometric objects:
1973  /// / This sets the current element to be the update element
1974  /// / for all of the element's nodes -- this is reversed
1975  /// / if the element is ever un-refined in the father element's
1976  /// / rebuild_from_sons() function which overwrites this
1977  /// / assignment to avoid nasty segmentation faults that occur
1978  /// / when a node tries to update itself via an element that no
1979  /// / longer exists...
1980  m_el_pt->set_node_update_info(geom_object_pt);
1981  }
1982  }
1983  }
1984 
1985  //==================================================================
1986  /// p-refine the element inc times. (If inc<0 then p-unrefinement
1987  /// is performed.)
1988  //==================================================================
1989  template<unsigned INITIAL_NNODE_1D>
1991  const int& inc, Mesh* const& mesh_pt, GeneralisedElement* const& clone_pt)
1992  {
1993  // Cast clone to correct type
1995  dynamic_cast<PRefineableQElement<2, INITIAL_NNODE_1D>*>(clone_pt);
1996 
1997  // If it is a MacroElement then we need to copy the geometric data too.
1999  dynamic_cast<MacroElementNodeUpdateElementBase*>(this);
2000  if (m_el_pt != 0)
2001  {
2002  MacroElementNodeUpdateElementBase* clone_m_el_pt =
2003  dynamic_cast<MacroElementNodeUpdateElementBase*>(clone_pt);
2004 
2005  // Store local copy of geom object vector, so it can be passed on
2006  // to son elements (and their nodes) during refinement
2007  unsigned ngeom_object = m_el_pt->ngeom_object();
2008  clone_m_el_pt->geom_object_pt().resize(ngeom_object);
2009  for (unsigned i = 0; i < ngeom_object; i++)
2010  {
2011  clone_m_el_pt->geom_object_pt()[i] = m_el_pt->geom_object_pt(i);
2012  }
2013 
2014  // clone_m_el_pt->set_node_update_info(m_el_pt->geom_object_pt());
2015  }
2016 
2017  // Check if we can use it
2018  if (clone_el_pt == 0)
2019  {
2020  throw OomphLibError(
2021  "Cloned copy must be a PRefineableQElement<2,INITIAL_NNODE_1D>!",
2022  OOMPH_CURRENT_FUNCTION,
2023  OOMPH_EXCEPTION_LOCATION);
2024  }
2025 #ifdef PARANOID
2026  // Clone exists, so check that it is infact a copy of me
2027  else
2028  {
2029  // Flag to keep track of check
2030  bool clone_is_ok = true;
2031 
2032  // Does the clone have the correct p-order?
2033  clone_is_ok = clone_is_ok && (clone_el_pt->p_order() == this->p_order());
2034 
2035  if (!clone_is_ok)
2036  {
2037  std::ostringstream err_stream;
2038  err_stream << "Clone element has a different p-order from me,"
2039  << std::endl
2040  << "but it is supposed to be a copy!" << std::endl;
2041 
2042  throw OomphLibError(
2043  err_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2044  }
2045 
2046  // Does the clone have the same number of nodes as me?
2047  clone_is_ok = clone_is_ok && (clone_el_pt->nnode() == this->nnode());
2048 
2049  if (!clone_is_ok)
2050  {
2051  std::ostringstream err_stream;
2052  err_stream << "Clone element has a different number of nodes from me,"
2053  << std::endl
2054  << "but it is supposed to be a copy!" << std::endl;
2055 
2056  throw OomphLibError(
2057  err_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2058  }
2059 
2060  // Does the clone have the same nodes as me?
2061  for (unsigned n = 0; n < this->nnode(); n++)
2062  {
2063  clone_is_ok =
2064  clone_is_ok && (clone_el_pt->node_pt(n) == this->node_pt(n));
2065  }
2066 
2067  if (!clone_is_ok)
2068  {
2069  std::ostringstream err_stream;
2070  err_stream << "The nodes belonging to the clone element are different"
2071  << std::endl
2072  << "from mine, but it is supposed to be a copy!"
2073  << std::endl;
2074 
2075  throw OomphLibError(
2076  err_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2077  }
2078 
2079  // Is this a macro element?
2081  dynamic_cast<MacroElementNodeUpdateElementBase*>(this);
2082  if (m_el_pt != 0)
2083  {
2084  // Get macro element version of clone
2085  MacroElementNodeUpdateElementBase* clone_m_el_pt =
2086  dynamic_cast<MacroElementNodeUpdateElementBase*>(clone_el_pt);
2087 
2088  // Does the clone have the same geometric objects?
2089  Vector<GeomObject*> clone_geom_object_pt(
2090  clone_m_el_pt->geom_object_pt());
2091  Vector<GeomObject*> geom_object_pt(m_el_pt->geom_object_pt());
2092 
2093  clone_is_ok =
2094  clone_is_ok && (geom_object_pt.size() == clone_geom_object_pt.size());
2095  for (unsigned n = 0;
2096  n < std::min(geom_object_pt.size(), clone_geom_object_pt.size());
2097  n++)
2098  {
2099  clone_is_ok =
2100  clone_is_ok && (clone_geom_object_pt[n] == geom_object_pt[n]);
2101  }
2102 
2103  if (!clone_is_ok)
2104  {
2105  std::ostringstream err_stream;
2106  err_stream << "The clone element has different geometric objects"
2107  << std::endl
2108  << "from mine, but it is supposed to be a copy!"
2109  << std::endl;
2110 
2111  throw OomphLibError(
2112  err_stream.str(),
2113  "PRefineableQElement<2,INITIAL_NNODE_1D>::p_refine()",
2114  OOMPH_EXCEPTION_LOCATION);
2115  }
2116  }
2117 
2118  // If we get to here then the clone has all the information we require
2119  }
2120 #endif
2121 
2122  // Currently we can't handle the case of generalised coordinates
2123  // since we haven't established how they should be interpolated.
2124  // Buffer this case:
2125  if (clone_el_pt->node_pt(0)->nposition_type() != 1)
2126  {
2127  throw OomphLibError("Can't handle generalised nodal positions (yet).",
2128  OOMPH_CURRENT_FUNCTION,
2129  OOMPH_EXCEPTION_LOCATION);
2130  }
2131 
2132  // Timestepper should be the same for all nodes -- use it
2133  // to create timesteppers for new nodes
2134  TimeStepper* time_stepper_pt = this->node_pt(0)->time_stepper_pt();
2135 
2136  // Get number of history values (incl. present)
2137  unsigned ntstorage = time_stepper_pt->ntstorage();
2138 
2139  // Increment p-order of the element
2140  P_order += inc;
2141 
2142  // Change integration scheme
2143  delete this->integral_pt();
2144  switch (P_order)
2145  {
2146  case 2:
2147  this->set_integration_scheme(new GaussLobattoLegendre<2, 2>);
2148  break;
2149  case 3:
2150  this->set_integration_scheme(new GaussLobattoLegendre<2, 3>);
2151  break;
2152  case 4:
2153  this->set_integration_scheme(new GaussLobattoLegendre<2, 4>);
2154  break;
2155  case 5:
2156  this->set_integration_scheme(new GaussLobattoLegendre<2, 5>);
2157  break;
2158  case 6:
2159  this->set_integration_scheme(new GaussLobattoLegendre<2, 6>);
2160  break;
2161  case 7:
2162  this->set_integration_scheme(new GaussLobattoLegendre<2, 7>);
2163  break;
2164  default:
2165  std::ostringstream error_message;
2166  error_message << "\nERROR: Exceeded maximum polynomial order for";
2167  error_message << "\n integration scheme.\n";
2168  throw OomphLibError(error_message.str(),
2169  OOMPH_CURRENT_FUNCTION,
2170  OOMPH_EXCEPTION_LOCATION);
2171  }
2172 
2173  // Allocate new space for Nodes (at the element level)
2174  this->set_n_node(P_order * P_order);
2175 
2176  // Copy vertex nodes and create new edge and internal nodes
2177  //---------------------------------------------------------
2178 
2179  // Setup vertex coordinates in element:
2180  //-------------------------------------
2181  Vector<double> s_lo(2);
2182  Vector<double> s_hi(2);
2183  s_lo[0] = -1.0;
2184  s_hi[0] = 1.0;
2185  s_lo[1] = -1.0;
2186  s_hi[1] = 1.0;
2187 
2188  // Local coordinate in element
2189  Vector<double> s(2);
2190 
2191  unsigned jnod = 0;
2192 
2193  Vector<double> s_fraction(2);
2194  // Loop over nodes in element
2195  for (unsigned i0 = 0; i0 < P_order; i0++)
2196  {
2197  // Get the fractional position of the node in the direction of s[0]
2198  s_fraction[0] = this->local_one_d_fraction_of_node(i0, 0);
2199  // Local coordinate
2200  s[0] = s_lo[0] + (s_hi[0] - s_lo[0]) * s_fraction[0];
2201 
2202  for (unsigned i1 = 0; i1 < P_order; i1++)
2203  {
2204  // Get the fractional position of the node in the direction of s[1]
2205  s_fraction[1] = this->local_one_d_fraction_of_node(i1, 1);
2206  // Local coordinate
2207  s[1] = s_lo[1] + (s_hi[1] - s_lo[1]) * s_fraction[1];
2208 
2209  // Local node number
2210  jnod = i0 + P_order * i1;
2211 
2212  // Initialise flag: So far, this node hasn't been built
2213  // or copied yet
2214  bool node_done = false;
2215 
2216  // Get the pointer to the node in this element (or rather, its clone),
2217  // returns NULL if there is not node
2218  Node* created_node_pt = clone_el_pt->get_node_at_local_coordinate(s);
2219 
2220  // Does this node already exist in this element?
2221  //----------------------------------------------
2222  if (created_node_pt != 0)
2223  {
2224  // Copy node across
2225  this->node_pt(jnod) = created_node_pt;
2226 
2227  // Make sure that we update the values at the node so that
2228  // they are consistent with the present representation.
2229  // This is only need for mixed interpolation where the value
2230  // at the father could now become active.
2231 
2232  // Loop over all history values
2233  for (unsigned t = 0; t < ntstorage; t++)
2234  {
2235  // Get values from father element
2236  // Note: get_interpolated_values() sets Vector size itself.
2237  Vector<double> prev_values;
2238  clone_el_pt->get_interpolated_values(t, s, prev_values);
2239  // Find the minimum number of values
2240  //(either those stored at the node, or those returned by
2241  // the function)
2242  unsigned n_val_at_node = created_node_pt->nvalue();
2243  unsigned n_val_from_function = prev_values.size();
2244  // Use the ternary conditional operator here
2245  unsigned n_var = n_val_at_node < n_val_from_function ?
2246  n_val_at_node :
2247  n_val_from_function;
2248  // Assign the values that we can
2249  for (unsigned k = 0; k < n_var; k++)
2250  {
2251  created_node_pt->set_value(t, k, prev_values[k]);
2252  }
2253  }
2254 
2255  // Node has been created by copy
2256  node_done = true;
2257  }
2258  // Node does not exist in this element but might already
2259  //------------------------------------------------------
2260  // have been created by neighbouring elements
2261  //-------------------------------------------
2262  else
2263  {
2264  // Was the node created by one of its neighbours
2265  // Whether or not the node lies on an edge can be calculated
2266  // by from the fractional position
2267  bool is_periodic = false;
2268  created_node_pt = node_created_by_neighbour(s_fraction, is_periodic);
2269 
2270  // If the node was so created, assign the pointers
2271  if (created_node_pt != 0)
2272  {
2273  // If the node is periodic
2274  if (is_periodic)
2275  {
2276  // Now the node must be on a boundary, but we don't know which
2277  // one
2278  // The returned created_node_pt is actually the neighbouring
2279  // periodic node
2280  Node* neighbour_node_pt = created_node_pt;
2281 
2282  // Determine the edge on which the new node will live
2283  //(cannot be a vertex node)
2284  int my_bound = Tree::OMEGA;
2285  if (s_fraction[0] == 0.0) my_bound = QuadTreeNames::W;
2286  else if (s_fraction[0] == 1.0)
2287  my_bound = QuadTreeNames::E;
2288  else if (s_fraction[1] == 0.0)
2289  my_bound = QuadTreeNames::S;
2290  else if (s_fraction[1] == 1.0)
2291  my_bound = QuadTreeNames::N;
2292 
2293  // Storage for the set of Mesh boundaries on which the
2294  // appropriate edge lives.
2295  // [New nodes should always be mid-edge nodes and therefore
2296  // only live on one boundary but just to play it safe...]
2297  std::set<unsigned> boundaries;
2298  // Only get the boundaries if we are at the edge of
2299  // an element. Nodes in the centre of an element cannot be
2300  // on Mesh boundaries
2301  if (my_bound != Tree::OMEGA)
2302  {
2303  clone_el_pt->get_boundaries(my_bound, boundaries);
2304  }
2305 
2306 #ifdef PARANOID
2307  // Case where a new node lives on more than one boundary
2308  // seems fishy enough to flag
2309  if (boundaries.size() > 1)
2310  {
2311  throw OomphLibError(
2312  "boundaries.size()!=1 seems a bit strange..\n",
2313  OOMPH_CURRENT_FUNCTION,
2314  OOMPH_EXCEPTION_LOCATION);
2315  }
2316 
2317  // Case when there are no boundaries, we are in big trouble
2318  if (boundaries.size() == 0)
2319  {
2320  std::ostringstream error_stream;
2321  error_stream << "Periodic node is not on a boundary...\n"
2322  << "Coordinates: " << created_node_pt->x(0) << " "
2323  << created_node_pt->x(1) << "\n";
2324  throw OomphLibError(error_stream.str(),
2325  OOMPH_CURRENT_FUNCTION,
2326  OOMPH_EXCEPTION_LOCATION);
2327  }
2328 #endif
2329 
2330  // Create node and set the pointer to it from the element
2331  created_node_pt =
2332  this->construct_boundary_node(jnod, time_stepper_pt);
2333  // Make the node periodic from the neighbour
2334  created_node_pt->make_periodic(neighbour_node_pt);
2335 
2336  // Loop over # of history values
2337  for (unsigned t = 0; t < ntstorage; t++)
2338  {
2339  // Get position from father element -- this uses the macro
2340  // element representation if appropriate. If the node
2341  // turns out to be a hanging node later on, then
2342  // its position gets adjusted in line with its
2343  // hanging node interpolation.
2344  Vector<double> x_prev(2);
2345  clone_el_pt->get_x(t, s, x_prev);
2346  // Set previous positions of the new node
2347  for (unsigned i = 0; i < 2; i++)
2348  {
2349  created_node_pt->x(t, i) = x_prev[i];
2350  }
2351  }
2352 
2353  // Check if we need to add nodes to the mesh
2354  if (mesh_pt != 0)
2355  {
2356  // Next, we Update the boundary lookup schemes
2357  // Loop over the boundaries stored in the set
2358  for (std::set<unsigned>::iterator it = boundaries.begin();
2359  it != boundaries.end();
2360  ++it)
2361  {
2362  // Add the node to the boundary
2363  mesh_pt->add_boundary_node(*it, created_node_pt);
2364 
2365  // If we have set an intrinsic coordinate on this
2366  // mesh boundary then it must also be interpolated on
2367  // the new node
2368  // Now interpolate the intrinsic boundary coordinate
2369  if (mesh_pt->boundary_coordinate_exists(*it) == true)
2370  {
2371  Vector<double> zeta(1);
2372  clone_el_pt->interpolated_zeta_on_edge(
2373  *it, my_bound, s, zeta);
2374 
2375  created_node_pt->set_coordinates_on_boundary(*it, zeta);
2376  }
2377  }
2378 
2379  // Make sure that we add the node to the mesh
2380  mesh_pt->add_node_pt(created_node_pt);
2381  }
2382  } // End of periodic case
2383  // Otherwise the node is not periodic, so just set the
2384  // pointer to the neighbours node
2385  else
2386  {
2387  this->node_pt(jnod) = created_node_pt;
2388  }
2389  // Node has been created
2390  node_done = true;
2391  }
2392  // Node does not exist in neighbour element but might already
2393  //-----------------------------------------------------------
2394  // have been created by a son of a neighbouring element
2395  //-----------------------------------------------------
2396  else
2397  {
2398  // Was the node created by one of its neighbours' sons
2399  // Whether or not the node lies on an edge can be calculated
2400  // by from the fractional position
2401  bool is_periodic = false;
2402  created_node_pt =
2403  node_created_by_son_of_neighbour(s_fraction, is_periodic);
2404 
2405  // If the node was so created, assign the pointers
2406  if (created_node_pt != 0)
2407  {
2408  // If the node is periodic
2409  if (is_periodic)
2410  {
2411  // Now the node must be on a boundary, but we don't know which
2412  // one
2413  // The returned created_node_pt is actually the neighbouring
2414  // periodic node
2415  Node* neighbour_node_pt = created_node_pt;
2416 
2417  // Determine the edge on which the new node will live
2418  //(cannot be a vertex node)
2419  int my_bound = Tree::OMEGA;
2420  if (s_fraction[0] == 0.0) my_bound = QuadTreeNames::W;
2421  else if (s_fraction[0] == 1.0)
2422  my_bound = QuadTreeNames::E;
2423  else if (s_fraction[1] == 0.0)
2424  my_bound = QuadTreeNames::S;
2425  else if (s_fraction[1] == 1.0)
2426  my_bound = QuadTreeNames::N;
2427 
2428  // Storage for the set of Mesh boundaries on which the
2429  // appropriate edge lives.
2430  // [New nodes should always be mid-edge nodes and therefore
2431  // only live on one boundary but just to play it safe...]
2432  std::set<unsigned> boundaries;
2433  // Only get the boundaries if we are at the edge of
2434  // an element. Nodes in the centre of an element cannot be
2435  // on Mesh boundaries
2436  if (my_bound != Tree::OMEGA)
2437  {
2438  clone_el_pt->get_boundaries(my_bound, boundaries);
2439  }
2440 
2441 #ifdef PARANOID
2442  // Case where a new node lives on more than one boundary
2443  // seems fishy enough to flag
2444  if (boundaries.size() > 1)
2445  {
2446  throw OomphLibError(
2447  "boundaries.size()!=1 seems a bit strange..\n",
2448  OOMPH_CURRENT_FUNCTION,
2449  OOMPH_EXCEPTION_LOCATION);
2450  }
2451 
2452  // Case when there are no boundaries, we are in big trouble
2453  if (boundaries.size() == 0)
2454  {
2455  std::ostringstream error_stream;
2456  error_stream << "Periodic node is not on a boundary...\n"
2457  << "Coordinates: " << created_node_pt->x(0)
2458  << " " << created_node_pt->x(1) << "\n";
2459  throw OomphLibError(error_stream.str(),
2460  OOMPH_CURRENT_FUNCTION,
2461  OOMPH_EXCEPTION_LOCATION);
2462  }
2463 #endif
2464 
2465  // Create node and set the pointer to it from the element
2466  created_node_pt =
2467  this->construct_boundary_node(jnod, time_stepper_pt);
2468  // Make the node periodic from the neighbour
2469  created_node_pt->make_periodic(neighbour_node_pt);
2470 
2471  // Loop over # of history values
2472  for (unsigned t = 0; t < ntstorage; t++)
2473  {
2474  // Get position from father element -- this uses the macro
2475  // element representation if appropriate. If the node
2476  // turns out to be a hanging node later on, then
2477  // its position gets adjusted in line with its
2478  // hanging node interpolation.
2479  Vector<double> x_prev(2);
2480  clone_el_pt->get_x(t, s, x_prev);
2481  // Set previous positions of the new node
2482  for (unsigned i = 0; i < 2; i++)
2483  {
2484  created_node_pt->x(t, i) = x_prev[i];
2485  }
2486  }
2487 
2488  // Check if we need to add nodes to the mesh
2489  if (mesh_pt != 0)
2490  {
2491  // Next, we Update the boundary lookup schemes
2492  // Loop over the boundaries stored in the set
2493  for (std::set<unsigned>::iterator it = boundaries.begin();
2494  it != boundaries.end();
2495  ++it)
2496  {
2497  // Add the node to the boundary
2498  mesh_pt->add_boundary_node(*it, created_node_pt);
2499 
2500  // If we have set an intrinsic coordinate on this
2501  // mesh boundary then it must also be interpolated on
2502  // the new node
2503  // Now interpolate the intrinsic boundary coordinate
2504  if (mesh_pt->boundary_coordinate_exists(*it) == true)
2505  {
2506  Vector<double> zeta(1);
2507  clone_el_pt->interpolated_zeta_on_edge(
2508  *it, my_bound, s, zeta);
2509 
2510  created_node_pt->set_coordinates_on_boundary(*it, zeta);
2511  }
2512  }
2513 
2514  // Make sure that we add the node to the mesh
2515  mesh_pt->add_node_pt(created_node_pt);
2516  }
2517  } // End of periodic case
2518  // Otherwise the node is not periodic, so just set the
2519  // pointer to the neighbours node
2520  else
2521  {
2522  this->node_pt(jnod) = created_node_pt;
2523  }
2524  // Node has been created
2525  node_done = true;
2526  } // Node does not exist in son of neighbouring element
2527  } // Node does not exist in neighbouring element
2528  } // Node does not exist in this element
2529 
2530  // Node has not been built anywhere ---> build it here
2531  if (!node_done)
2532  {
2533  // Firstly, we need to determine whether or not a node lies
2534  // on the boundary before building it, because
2535  // we actually assign a different type of node on boundaries.
2536 
2537  // Determine the edge on which the new node will live
2538  //(cannot be a vertex node)
2539  int my_bound = Tree::OMEGA;
2540  if (s_fraction[0] == 0.0) my_bound = QuadTreeNames::W;
2541  else if (s_fraction[0] == 1.0)
2542  my_bound = QuadTreeNames::E;
2543  else if (s_fraction[1] == 0.0)
2544  my_bound = QuadTreeNames::S;
2545  else if (s_fraction[1] == 1.0)
2546  my_bound = QuadTreeNames::N;
2547 
2548  // Storage for the set of Mesh boundaries on which the
2549  // appropriate edge lives.
2550  // [New nodes should always be mid-edge nodes and therefore
2551  // only live on one boundary but just to play it safe...]
2552  std::set<unsigned> boundaries;
2553  // Only get the boundaries if we are at the edge of
2554  // an element. Nodes in the centre of an element cannot be
2555  // on Mesh boundaries
2556  if (my_bound != Tree::OMEGA)
2557  {
2558  clone_el_pt->get_boundaries(my_bound, boundaries);
2559  }
2560 
2561 #ifdef PARANOID
2562  // Case where a new node lives on more than one boundary
2563  // seems fishy enough to flag
2564  if (boundaries.size() > 1)
2565  {
2566  throw OomphLibError("boundaries.size()!=1 seems a bit strange..\n",
2567  OOMPH_CURRENT_FUNCTION,
2568  OOMPH_EXCEPTION_LOCATION);
2569  }
2570 #endif
2571 
2572  // If the node lives on a mesh boundary,
2573  // then we need to create a boundary node
2574  if (boundaries.size() > 0)
2575  {
2576  // Create node and set the pointer to it from the element
2577  created_node_pt =
2578  this->construct_boundary_node(jnod, time_stepper_pt);
2579 
2580  // Now we need to work out whether to pin the values at
2581  // the new node based on the boundary conditions applied at
2582  // its Mesh boundary
2583 
2584  // Get the boundary conditions from the father
2585  Vector<int> bound_cons(this->ncont_interpolated_values());
2586  clone_el_pt->get_bcs(my_bound, bound_cons);
2587 
2588  // Loop over the values and pin, if necessary
2589  unsigned n_value = created_node_pt->nvalue();
2590  for (unsigned k = 0; k < n_value; k++)
2591  {
2592  if (bound_cons[k])
2593  {
2594  created_node_pt->pin(k);
2595  }
2596  }
2597 
2598  // Solid node? If so, deal with the positional boundary
2599  // conditions:
2600  SolidNode* solid_node_pt =
2601  dynamic_cast<SolidNode*>(created_node_pt);
2602  if (solid_node_pt != 0)
2603  {
2604  // Get the positional boundary conditions from the father:
2605  unsigned n_dim = created_node_pt->ndim();
2606  Vector<int> solid_bound_cons(n_dim);
2607  RefineableSolidQElement<2>* clone_solid_el_pt =
2608  dynamic_cast<RefineableSolidQElement<2>*>(clone_el_pt);
2609 #ifdef PARANOID
2610  if (clone_solid_el_pt == 0)
2611  {
2612  std::string error_message =
2613  "We have a SolidNode outside a refineable SolidElement\n";
2614  error_message +=
2615  "during mesh refinement -- this doesn't make sense";
2616 
2617  throw OomphLibError(error_message,
2618  OOMPH_CURRENT_FUNCTION,
2619  OOMPH_EXCEPTION_LOCATION);
2620  }
2621 #endif
2622  clone_solid_el_pt->get_solid_bcs(my_bound, solid_bound_cons);
2623 
2624  // Loop over the positions and pin, if necessary
2625  for (unsigned k = 0; k < n_dim; k++)
2626  {
2627  if (solid_bound_cons[k])
2628  {
2629  solid_node_pt->pin_position(k);
2630  }
2631  }
2632  } // End of if solid_node_pt
2633 
2634 
2635  // Check if we need to add nodes to the mesh
2636  if (mesh_pt != 0)
2637  {
2638  // Next, we Update the boundary lookup schemes
2639  // Loop over the boundaries stored in the set
2640  for (std::set<unsigned>::iterator it = boundaries.begin();
2641  it != boundaries.end();
2642  ++it)
2643  {
2644  // Add the node to the boundary
2645  mesh_pt->add_boundary_node(*it, created_node_pt);
2646 
2647  // If we have set an intrinsic coordinate on this
2648  // mesh boundary then it must also be interpolated on
2649  // the new node
2650  // Now interpolate the intrinsic boundary coordinate
2651  if (mesh_pt->boundary_coordinate_exists(*it) == true)
2652  {
2653  Vector<double> zeta(1);
2654  clone_el_pt->interpolated_zeta_on_edge(
2655  *it, my_bound, s, zeta);
2656 
2657  created_node_pt->set_coordinates_on_boundary(*it, zeta);
2658  }
2659  }
2660  }
2661  }
2662  // Otherwise the node is not on a Mesh boundary and
2663  // we create a normal "bulk" node
2664  else
2665  {
2666  // Create node and set the pointer to it from the element
2667  created_node_pt = this->construct_node(jnod, time_stepper_pt);
2668  }
2669 
2670  // Now we set the position and values at the newly created node
2671 
2672  // In the first instance use macro element or FE representation
2673  // to create past and present nodal positions.
2674  // (THIS STEP SHOULD NOT BE SKIPPED FOR ALGEBRAIC
2675  // ELEMENTS AS NOT ALL OF THEM NECESSARILY IMPLEMENT
2676  // NONTRIVIAL NODE UPDATE FUNCTIONS. CALLING
2677  // THE NODE UPDATE FOR SUCH ELEMENTS/NODES WILL LEAVE
2678  // THEIR NODAL POSITIONS WHERE THEY WERE (THIS IS APPROPRIATE
2679  // ONCE THEY HAVE BEEN GIVEN POSITIONS) BUT WILL
2680  // NOT ASSIGN SENSIBLE INITIAL POSITONS!
2681 
2682  // Loop over # of history values
2683  for (unsigned t = 0; t < ntstorage; t++)
2684  {
2685  // Get position from father element -- this uses the macro
2686  // element representation if appropriate. If the node
2687  // turns out to be a hanging node later on, then
2688  // its position gets adjusted in line with its
2689  // hanging node interpolation.
2690  Vector<double> x_prev(2);
2691  clone_el_pt->get_x(t, s, x_prev);
2692 
2693  // Set previous positions of the new node
2694  for (unsigned i = 0; i < 2; i++)
2695  {
2696  created_node_pt->x(t, i) = x_prev[i];
2697  }
2698  }
2699 
2700  // Loop over all history values
2701  for (unsigned t = 0; t < ntstorage; t++)
2702  {
2703  // Get values from father element
2704  // Note: get_interpolated_values() sets Vector size itself.
2705  Vector<double> prev_values;
2706  clone_el_pt->get_interpolated_values(t, s, prev_values);
2707  // Initialise the values at the new node
2708  unsigned n_value = created_node_pt->nvalue();
2709  for (unsigned k = 0; k < n_value; k++)
2710  {
2711  created_node_pt->set_value(t, k, prev_values[k]);
2712  }
2713  }
2714 
2715  // Add new node to mesh (if requested)
2716  if (mesh_pt != 0)
2717  {
2718  mesh_pt->add_node_pt(created_node_pt);
2719  }
2720 
2721  AlgebraicElementBase* alg_el_pt =
2722  dynamic_cast<AlgebraicElementBase*>(this);
2723 
2724  // If we do have an algebraic element
2725  if (alg_el_pt != 0)
2726  {
2727  std::string error_message = "Have not implemented p-refinement for";
2728  error_message += "Algebraic p-refineable elements yet\n";
2729 
2730  throw OomphLibError(
2731  error_message,
2732  "PRefineableQElement<2,INITIAL_NNODE_1D>::p_refine()",
2733  OOMPH_EXCEPTION_LOCATION);
2734  }
2735 
2736  } // End of case when we build the node ourselves
2737 
2738  // Check if the element is an algebraic element
2739  AlgebraicElementBase* alg_el_pt =
2740  dynamic_cast<AlgebraicElementBase*>(this);
2741 
2742  // If the element is an algebraic element, setup
2743  // node position (past and present) from algebraic node update
2744  // function. This over-writes previous assingments that
2745  // were made based on the macro-element/FE representation.
2746  // NOTE: YES, THIS NEEDS TO BE CALLED REPEATEDLY IF THE
2747  // NODE IS MEMBER OF MULTIPLE ELEMENTS: THEY ALL ASSIGN
2748  // THE SAME NODAL POSITIONS BUT WE NEED TO ADD THE REMESH
2749  // INFO FOR *ALL* ROOT ELEMENTS!
2750  if (alg_el_pt != 0)
2751  {
2752  // Build algebraic node update info for new node
2753  // This sets up the node update data for all node update
2754  // functions that are shared by all nodes in the father
2755  // element
2756  alg_el_pt->setup_algebraic_node_update(
2757  this->node_pt(jnod), s, clone_el_pt);
2758  }
2759 
2760  } // End of vertical loop over nodes in element
2761 
2762  } // End of horizontal loop over nodes in element
2763 
2764 
2765  // If the element is a MacroElementNodeUpdateElement, set
2766  // the update parameters for the current element's nodes --
2767  // all this needs is the vector of (pointers to the)
2768  // geometric objects that affect the MacroElement-based
2769  // node update -- this needs to be done to set the node
2770  // update info for newly created nodes
2771  MacroElementNodeUpdateElementBase* clone_m_el_pt =
2772  dynamic_cast<MacroElementNodeUpdateElementBase*>(clone_el_pt);
2773  if (clone_m_el_pt != 0)
2774  {
2775  // Get vector of geometric objects from father (construct vector
2776  // via copy operation)
2777  Vector<GeomObject*> geom_object_pt(clone_m_el_pt->geom_object_pt());
2778 
2779  // Cast current element to MacroElementNodeUpdateElement:
2781  dynamic_cast<MacroElementNodeUpdateElementBase*>(this);
2782 
2783 #ifdef PARANOID
2784  if (m_el_pt == 0)
2785  {
2786  std::string error_message =
2787  "Failed to cast to MacroElementNodeUpdateElementBase*\n";
2788  error_message +=
2789  "Strange -- if my clone is a MacroElementNodeUpdateElement\n";
2790  error_message += "then I should be too....\n";
2791 
2792  throw OomphLibError(
2793  error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
2794  }
2795 #endif
2796  // Build update info by passing vector of geometric objects:
2797  // This sets the current element to be the update element
2798  // for all of the element's nodes -- this is reversed
2799  // if the element is ever un-refined in the father element's
2800  // rebuild_from_sons() function which overwrites this
2801  // assignment to avoid nasty segmentation faults that occur
2802  // when a node tries to update itself via an element that no
2803  // longer exists...
2804  m_el_pt->set_node_update_info(geom_object_pt);
2805 
2806  /// / Now loop over nodes in element
2807  // unsigned n_node = this->nnode();
2808  // for (unsigned j=0;j<n_node;j++)
2809  // {
2810  // // Get local coordinate in element (Vector sets its own size)
2811  // Vector<double> s_in_node_update_element;
2812  // this->local_coordinate_of_node(j,s_in_node_update_element);
2813  //
2814  // // Pass the lot to the node
2815  // static_cast<MacroElementNodeUpdateNode*>(this->node_pt(j))->
2816  // set_node_update_info(this,s_in_node_update_element,m_el_pt->geom_object_pt());
2817  // }
2818 
2819  /// /BENFLAG:
2820  // std::cout << "Checking that all the nodes have this as their update
2821  // element..." << std::endl;
2822  /// /std::cout << "this = " << this << std::endl;
2823  // for(unsigned j=0; j<this->nnode(); j++)
2824  // {
2825  // //std::cout << this->node_pt(j) << ": [" << this->node_pt(j)->x(0)
2826  // << "," << this->node_pt(j)->x(1) << "] update element: " <<
2827  // dynamic_cast<MacroElementNodeUpdateNode*>(this->node_pt(j))->node_update_element_pt()
2828  // << std::endl; MacroElementNodeUpdateNode* mac_nod_pt =
2829  // dynamic_cast<MacroElementNodeUpdateNode*>(this->node_pt(j));
2830  // if(mac_nod_pt->node_update_element_pt()!=this)
2831  // {
2832  // std::cout << "Something's not right! Update element is wrong..." <<
2833  // std::endl;
2834  // }
2835  // FiniteElement* up_el_pt =
2836  // dynamic_cast<FiniteElement*>(mac_nod_pt->node_update_element_pt());
2837  // bool not_good = true;
2838  // for(unsigned l=0; l<up_el_pt->nnode(); l++)
2839  // {
2840  // if(up_el_pt->node_pt(l)==mac_nod_pt)
2841  // {
2842  // not_good = false;
2843  // break;
2844  // }
2845  // }
2846  // if(not_good==true)
2847  // {
2848  // std::cout << "Macro node doesn't belong to its update element!" <<
2849  // std::endl;
2850  // }
2851  // }
2852 
2853 
2854  // Loop over all nodes in element again, to re-set the positions
2855  // This must be done using the new element's macro-element
2856  // representation, rather than the old version which may be
2857  // of a different p-order!
2858  for (unsigned i0 = 0; i0 < P_order; i0++)
2859  {
2860  // Get the fractional position of the node in the direction of s[0]
2861  s_fraction[0] = this->local_one_d_fraction_of_node(i0, 0);
2862  // Local coordinate
2863  s[0] = s_lo[0] + (s_hi[0] - s_lo[0]) * s_fraction[0];
2864 
2865  for (unsigned i1 = 0; i1 < P_order; i1++)
2866  {
2867  // Get the fractional position of the node in the direction of s[1]
2868  s_fraction[1] = this->local_one_d_fraction_of_node(i1, 1);
2869  // Local coordinate
2870  s[1] = s_lo[1] + (s_hi[1] - s_lo[1]) * s_fraction[1];
2871 
2872  // Local node number
2873  jnod = i0 + P_order * i1;
2874 
2875  // Loop over # of history values
2876  for (unsigned t = 0; t < ntstorage; t++)
2877  {
2878  // Get position from father element -- this uses the macro
2879  // element representation if appropriate. If the node
2880  // turns out to be a hanging node later on, then
2881  // its position gets adjusted in line with its
2882  // hanging node interpolation.
2883  Vector<double> x_prev(2);
2884  this->get_x(t, s, x_prev);
2885 
2886  // Set previous positions of the new node
2887  for (unsigned i = 0; i < 2; i++)
2888  {
2889  this->node_pt(jnod)->x(t, i) = x_prev[i];
2890  }
2891  }
2892  }
2893  }
2894  }
2895 
2896  // Not necessary to delete the old nodes since all original nodes are in the
2897  // current mesh and so will be pruned as part of the mesh adaption process.
2898 
2899  // Do any further-build required
2900  this->further_build();
2901  }
2902 
2903  //=======================================================================
2904  /// Shape functions for PRefineableQElement<DIM>
2905  //=======================================================================
2906  template<unsigned INITIAL_NNODE_1D>
2908  Shape& psi) const
2909  {
2910  switch (p_order())
2911  {
2912  case 2:
2913  {
2914  // Call the OneDimensional Shape functions
2916  OneDimensionalLegendreShape<2> psi1(s[0]), psi2(s[1]);
2917 
2918  // Now let's loop over the nodal points in the element
2919  // and copy the values back in
2920  for (unsigned i = 0; i < 2; i++)
2921  {
2922  for (unsigned j = 0; j < 2; j++)
2923  {
2924  psi(2 * i + j) = psi2[i] * psi1[j];
2925  }
2926  }
2927  break;
2928  }
2929  case 3:
2930  {
2931  // Call the OneDimensional Shape functions
2933  OneDimensionalLegendreShape<3> psi1(s[0]), psi2(s[1]);
2934 
2935  // Now let's loop over the nodal points in the element
2936  // and copy the values back in
2937  for (unsigned i = 0; i < 3; i++)
2938  {
2939  for (unsigned j = 0; j < 3; j++)
2940  {
2941  psi(3 * i + j) = psi2[i] * psi1[j];
2942  }
2943  }
2944  break;
2945  }
2946  case 4:
2947  {
2948  // Call the OneDimensional Shape functions
2950  OneDimensionalLegendreShape<4> psi1(s[0]), psi2(s[1]);
2951 
2952  // Now let's loop over the nodal points in the element
2953  // and copy the values back in
2954  for (unsigned i = 0; i < 4; i++)
2955  {
2956  for (unsigned j = 0; j < 4; j++)
2957  {
2958  psi(4 * i + j) = psi2[i] * psi1[j];
2959  }
2960  }
2961  break;
2962  }
2963  case 5:
2964  {
2965  // Call the OneDimensional Shape functions
2967  OneDimensionalLegendreShape<5> psi1(s[0]), psi2(s[1]);
2968 
2969  // Now let's loop over the nodal points in the element
2970  // and copy the values back in
2971  for (unsigned i = 0; i < 5; i++)
2972  {
2973  for (unsigned j = 0; j < 5; j++)
2974  {
2975  psi(5 * i + j) = psi2[i] * psi1[j];
2976  }
2977  }
2978  break;
2979  }
2980  case 6:
2981  {
2982  // Call the OneDimensional Shape functions
2984  OneDimensionalLegendreShape<6> psi1(s[0]), psi2(s[1]);
2985 
2986  // Now let's loop over the nodal points in the element
2987  // and copy the values back in
2988  for (unsigned i = 0; i < 6; i++)
2989  {
2990  for (unsigned j = 0; j < 6; j++)
2991  {
2992  psi(6 * i + j) = psi2[i] * psi1[j];
2993  }
2994  }
2995  break;
2996  }
2997  case 7:
2998  {
2999  // Call the OneDimensional Shape functions
3001  OneDimensionalLegendreShape<7> psi1(s[0]), psi2(s[1]);
3002 
3003  // Now let's loop over the nodal points in the element
3004  // and copy the values back in
3005  for (unsigned i = 0; i < 7; i++)
3006  {
3007  for (unsigned j = 0; j < 7; j++)
3008  {
3009  psi(7 * i + j) = psi2[i] * psi1[j];
3010  }
3011  }
3012  break;
3013  }
3014  default:
3015  std::ostringstream error_message;
3016  error_message << "\nERROR: Exceeded maximum polynomial order for";
3017  error_message << "\n polynomial order for shape functions.\n";
3018  throw OomphLibError(error_message.str(),
3019  OOMPH_CURRENT_FUNCTION,
3020  OOMPH_EXCEPTION_LOCATION);
3021  }
3022  }
3023 
3024  //=======================================================================
3025  /// Derivatives of shape functions for PRefineableQElement<DIM>
3026  //=======================================================================
3027  template<unsigned INITIAL_NNODE_1D>
3029  const Vector<double>& s, Shape& psi, DShape& dpsids) const
3030  {
3031  switch (p_order())
3032  {
3033  case 2:
3034  {
3035  // Call the shape functions and derivatives
3037  OneDimensionalLegendreShape<2> psi1(s[0]), psi2(s[1]);
3038  OneDimensionalLegendreDShape<2> dpsi1ds(s[0]), dpsi2ds(s[1]);
3039 
3040  // Index for the shape functions
3041  unsigned index = 0;
3042  // Loop over shape functions in element
3043  for (unsigned i = 0; i < 2; i++)
3044  {
3045  for (unsigned j = 0; j < 2; j++)
3046  {
3047  // Assign the values
3048  dpsids(index, 0) = psi2[i] * dpsi1ds[j];
3049  dpsids(index, 1) = dpsi2ds[i] * psi1[j];
3050  psi[index] = psi2[i] * psi1[j];
3051  // Increment the index
3052  ++index;
3053  }
3054  }
3055  break;
3056  }
3057  case 3:
3058  {
3059  // Call the shape functions and derivatives
3061  OneDimensionalLegendreShape<3> psi1(s[0]), psi2(s[1]);
3062  OneDimensionalLegendreDShape<3> dpsi1ds(s[0]), dpsi2ds(s[1]);
3063 
3064  // Index for the shape functions
3065  unsigned index = 0;
3066  // Loop over shape functions in element
3067  for (unsigned i = 0; i < 3; i++)
3068  {
3069  for (unsigned j = 0; j < 3; j++)
3070  {
3071  // Assign the values
3072  dpsids(index, 0) = psi2[i] * dpsi1ds[j];
3073  dpsids(index, 1) = dpsi2ds[i] * psi1[j];
3074  psi[index] = psi2[i] * psi1[j];
3075  // Increment the index
3076  ++index;
3077  }
3078  }
3079  break;
3080  }
3081  case 4:
3082  {
3083  // Call the shape functions and derivatives
3085  OneDimensionalLegendreShape<4> psi1(s[0]), psi2(s[1]);
3086  OneDimensionalLegendreDShape<4> dpsi1ds(s[0]), dpsi2ds(s[1]);
3087 
3088  // Index for the shape functions
3089  unsigned index = 0;
3090  // Loop over shape functions in element
3091  for (unsigned i = 0; i < 4; i++)
3092  {
3093  for (unsigned j = 0; j < 4; j++)
3094  {
3095  // Assign the values
3096  dpsids(index, 0) = psi2[i] * dpsi1ds[j];
3097  dpsids(index, 1) = dpsi2ds[i] * psi1[j];
3098  psi[index] = psi2[i] * psi1[j];
3099  // Increment the index
3100  ++index;
3101  }
3102  }
3103  break;
3104  }
3105  case 5:
3106  {
3107  // Call the shape functions and derivatives
3109  OneDimensionalLegendreShape<5> psi1(s[0]), psi2(s[1]);
3110  OneDimensionalLegendreDShape<5> dpsi1ds(s[0]), dpsi2ds(s[1]);
3111 
3112  // Index for the shape functions
3113  unsigned index = 0;
3114  // Loop over shape functions in element
3115  for (unsigned i = 0; i < 5; i++)
3116  {
3117  for (unsigned j = 0; j < 5; j++)
3118  {
3119  // Assign the values
3120  dpsids(index, 0) = psi2[i] * dpsi1ds[j];
3121  dpsids(index, 1) = dpsi2ds[i] * psi1[j];
3122  psi[index] = psi2[i] * psi1[j];
3123  // Increment the index
3124  ++index;
3125  }
3126  }
3127  break;
3128  }
3129  case 6:
3130  {
3131  // Call the shape functions and derivatives
3133  OneDimensionalLegendreShape<6> psi1(s[0]), psi2(s[1]);
3134  OneDimensionalLegendreDShape<6> dpsi1ds(s[0]), dpsi2ds(s[1]);
3135 
3136  // Index for the shape functions
3137  unsigned index = 0;
3138  // Loop over shape functions in element
3139  for (unsigned i = 0; i < 6; i++)
3140  {
3141  for (unsigned j = 0; j < 6; j++)
3142  {
3143  // Assign the values
3144  dpsids(index, 0) = psi2[i] * dpsi1ds[j];
3145  dpsids(index, 1) = dpsi2ds[i] * psi1[j];
3146  psi[index] = psi2[i] * psi1[j];
3147  // Increment the index
3148  ++index;
3149  }
3150  }
3151  break;
3152  }
3153  case 7:
3154  {
3155  // Call the shape functions and derivatives
3157  OneDimensionalLegendreShape<7> psi1(s[0]), psi2(s[1]);
3158  OneDimensionalLegendreDShape<7> dpsi1ds(s[0]), dpsi2ds(s[1]);
3159 
3160  // Index for the shape functions
3161  unsigned index = 0;
3162  // Loop over shape functions in element
3163  for (unsigned i = 0; i < 7; i++)
3164  {
3165  for (unsigned j = 0; j < 7; j++)
3166  {
3167  // Assign the values
3168  dpsids(index, 0) = psi2[i] * dpsi1ds[j];
3169  dpsids(index, 1) = dpsi2ds[i] * psi1[j];
3170  psi[index] = psi2[i] * psi1[j];
3171  // Increment the index
3172  ++index;
3173  }
3174  }
3175  break;
3176  }
3177  default:
3178  std::ostringstream error_message;
3179  error_message << "\nERROR: Exceeded maximum polynomial order for";
3180  error_message << "\n polynomial order for shape functions.\n";
3181  throw OomphLibError(error_message.str(),
3182  OOMPH_CURRENT_FUNCTION,
3183  OOMPH_EXCEPTION_LOCATION);
3184  }
3185  }
3186 
3187  //=======================================================================
3188  /// Second derivatives of shape functions for PRefineableQElement<DIM>
3189  /// d2psids(i,0) = \f$ d^2 \psi_j / d s^2 \f$
3190  //=======================================================================
3191  template<unsigned INITIAL_NNODE_1D>
3193  const Vector<double>& s, Shape& psi, DShape& dpsids, DShape& d2psids) const
3194  {
3195  std::ostringstream error_message;
3196  error_message
3197  << "\nd2shape_local currently not implemented for this element\n";
3198  throw OomphLibError(
3199  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3200  }
3201 
3202  //=======================================================================
3203  /// Rebuild the element from nodes found in its sons
3204  /// Adjusts its p-order to be the maximum of its sons' p-orders
3205  //=======================================================================
3206  template<unsigned INITIAL_NNODE_1D>
3208  Mesh*& mesh_pt)
3209  {
3210  using namespace QuadTreeNames;
3211 
3212  // Get p-orders of sons
3213  unsigned n_sons = this->tree_pt()->nsons();
3214  Vector<unsigned> son_p_order(n_sons);
3215  unsigned max_son_p_order = 0;
3216  for (unsigned ison = 0; ison < n_sons; ison++)
3217  {
3218  PRefineableElement* el_pt = dynamic_cast<PRefineableElement*>(
3219  this->tree_pt()->son_pt(ison)->object_pt());
3220  son_p_order[ison] = el_pt->p_order();
3221  if (son_p_order[ison] > max_son_p_order)
3222  max_son_p_order = son_p_order[ison];
3223  }
3224 
3225  unsigned old_Nnode = this->nnode();
3226  unsigned old_P_order = this->p_order();
3227  // Set p-order of the element
3228  this->p_order() = max_son_p_order;
3229 
3230  // Change integration scheme
3231  delete this->integral_pt();
3232  switch (this->p_order())
3233  {
3234  case 2:
3235  this->set_integration_scheme(new GaussLobattoLegendre<2, 2>);
3236  break;
3237  case 3:
3238  this->set_integration_scheme(new GaussLobattoLegendre<2, 3>);
3239  break;
3240  case 4:
3241  this->set_integration_scheme(new GaussLobattoLegendre<2, 4>);
3242  break;
3243  case 5:
3244  this->set_integration_scheme(new GaussLobattoLegendre<2, 5>);
3245  break;
3246  case 6:
3247  this->set_integration_scheme(new GaussLobattoLegendre<2, 6>);
3248  break;
3249  case 7:
3250  this->set_integration_scheme(new GaussLobattoLegendre<2, 7>);
3251  break;
3252  default:
3253  std::ostringstream error_message;
3254  error_message << "\nERROR: Exceeded maximum polynomial order for";
3255  error_message << "\n integration scheme.\n";
3256  throw OomphLibError(error_message.str(),
3257  OOMPH_CURRENT_FUNCTION,
3258  OOMPH_EXCEPTION_LOCATION);
3259  }
3260 
3261  // Back up pointers to old nodes before they are lost
3262  Vector<Node*> old_node_pt(old_Nnode);
3263  for (unsigned n = 0; n < old_Nnode; n++)
3264  {
3265  old_node_pt[n] = this->node_pt(n);
3266  }
3267 
3268  // Allocate new space for Nodes (at the element level)
3269  this->set_n_node(this->p_order() * this->p_order());
3270 
3271  // Copy vertex nodes which were populated in the pre-build
3272  this->node_pt(0) = old_node_pt[0];
3273  this->node_pt(this->p_order() - 1) = old_node_pt[old_P_order - 1];
3274  this->node_pt(this->p_order() * (this->p_order() - 1)) =
3275  old_node_pt[(old_P_order) * (old_P_order - 1)];
3276  this->node_pt(this->p_order() * this->p_order() - 1) =
3277  old_node_pt[(old_P_order) * (old_P_order)-1];
3278 
3279  // Copy midpoint nodes from sons if new p-order is odd
3280  if (this->p_order() % 2 == 1)
3281  {
3282  // Work out which is midpoint node
3283  unsigned midpoint = (this->p_order() - 1) / 2;
3284 
3285  // Bottom edge
3286  this->node_pt(midpoint) = dynamic_cast<RefineableQElement<2>*>(
3287  quadtree_pt()->son_pt(SW)->object_pt())
3288  ->vertex_node_pt(1);
3289  // Left edge
3290  this->node_pt(midpoint * this->p_order()) =
3291  dynamic_cast<RefineableQElement<2>*>(
3292  quadtree_pt()->son_pt(SW)->object_pt())
3293  ->vertex_node_pt(2);
3294  // Top edge
3295  this->node_pt((this->p_order() - 1) * this->p_order() + midpoint) =
3296  dynamic_cast<RefineableQElement<2>*>(
3297  quadtree_pt()->son_pt(NE)->object_pt())
3298  ->vertex_node_pt(2);
3299  // Right edge
3300  this->node_pt((midpoint + 1) * this->p_order() - 1) =
3301  dynamic_cast<RefineableQElement<2>*>(
3302  quadtree_pt()->son_pt(NE)->object_pt())
3303  ->vertex_node_pt(1);
3304  }
3305 
3306 
3307  // The timestepper should be the same for all nodes and node 0 should
3308  // never be deleted.
3309  if (this->node_pt(0) == 0)
3310  {
3311  throw OomphLibError("The Corner node (0) does not exist",
3312  OOMPH_CURRENT_FUNCTION,
3313  OOMPH_EXCEPTION_LOCATION);
3314  }
3315 
3316  TimeStepper* time_stepper_pt = this->node_pt(0)->time_stepper_pt();
3317  unsigned ntstorage = time_stepper_pt->ntstorage();
3318 
3319  unsigned jnod = 0;
3320  Vector<double> s_fraction(2), s(2);
3321  // Loop over the nodes in the element
3322  unsigned n_p = this->nnode_1d();
3323  for (unsigned i0 = 0; i0 < n_p; i0++)
3324  {
3325  // Get the fractional position of the node
3326  s_fraction[0] = this->local_one_d_fraction_of_node(i0, 0);
3327  // Local coordinate
3328  s[0] = -1.0 + 2.0 * s_fraction[0];
3329 
3330  for (unsigned i1 = 0; i1 < n_p; i1++)
3331  {
3332  // Get the fractional position of the node in the direction of s[1]
3333  s_fraction[1] = this->local_one_d_fraction_of_node(i1, 1);
3334  // Local coordinate in father element
3335  s[1] = -1.0 + 2.0 * s_fraction[1];
3336 
3337  // Set the local node number
3338  jnod = i0 + n_p * i1;
3339 
3340  // Initialise flag: So far, this node hasn't been built
3341  // or copied yet
3342  bool node_done = false;
3343 
3344  // Get the pointer to the node in this element, returns NULL
3345  // if there is not node
3346  Node* created_node_pt = this->get_node_at_local_coordinate(s);
3347 
3348  // Does this node already exist in this element?
3349  //----------------------------------------------
3350  if (created_node_pt != 0)
3351  {
3352  // Copy node across
3353  this->node_pt(jnod) = created_node_pt;
3354 
3355  // Node has been created by copy
3356  node_done = true;
3357  }
3358  // Node does not exist in this element but might already
3359  //------------------------------------------------------
3360  // have been created by neighbouring elements
3361  //-------------------------------------------
3362  else
3363  {
3364  // Was the node created by one of its neighbours
3365  // Whether or not the node lies on an edge can be calculated
3366  // by from the fractional position
3367  bool is_periodic = false;
3368  created_node_pt = node_created_by_neighbour(s_fraction, is_periodic);
3369 
3370  // If the node was so created, assign the pointers
3371  if (created_node_pt != 0)
3372  {
3373  // If the node is periodic
3374  if (is_periodic)
3375  {
3376  throw OomphLibError("Cannot handle periodic nodes yet",
3377  OOMPH_CURRENT_FUNCTION,
3378  OOMPH_EXCEPTION_LOCATION);
3379  }
3380  // Non-periodic case, just set the pointer
3381  else
3382  {
3383  this->node_pt(jnod) = created_node_pt;
3384  }
3385  // Node has been created
3386  node_done = true;
3387  }
3388  } // Node does not exist in this element
3389 
3390  // Node has not been built anywhere ---> build it here
3391  if (!node_done)
3392  {
3393  // First, find the son element in which the node should live
3394 
3395  // Find coordinates in the sons
3396  Vector<double> s_in_son(2);
3397  using namespace QuadTreeNames;
3398  int son = -10;
3399  // If negative on the west side
3400  if (s_fraction[0] < 0.5)
3401  {
3402  // On the south side
3403  if (s_fraction[1] < 0.5)
3404  {
3405  // It's the southwest son
3406  son = SW;
3407  s_in_son[0] = -1.0 + 4.0 * s_fraction[0];
3408  s_in_son[1] = -1.0 + 4.0 * s_fraction[1];
3409  }
3410  // On the north side
3411  else
3412  {
3413  // It's the northwest son
3414  son = NW;
3415  s_in_son[0] = -1.0 + 4.0 * s_fraction[0];
3416  s_in_son[1] = -1.0 + 4.0 * (s_fraction[1] - 0.5);
3417  }
3418  }
3419  else
3420  {
3421  // On the south side
3422  if (s_fraction[1] < 0.5)
3423  {
3424  // It's the southeast son
3425  son = SE;
3426  s_in_son[0] = -1.0 + 4.0 * (s_fraction[0] - 0.5);
3427  s_in_son[1] = -1.0 + 4.0 * s_fraction[1];
3428  }
3429  // On the north side
3430  else
3431  {
3432  // It's the northeast son
3433  son = NE;
3434  s_in_son[0] = -1.0 + 4.0 * (s_fraction[0] - 0.5);
3435  s_in_son[1] = -1.0 + 4.0 * (s_fraction[1] - 0.5);
3436  }
3437  }
3438 
3439  // Get the pointer to the son element in which the new node
3440  // would live
3443  this->tree_pt()->son_pt(son)->object_pt());
3444 
3445  // If we are rebuilding, then worry about the boundary conditions
3446  // Find the boundary of the node
3447  // Initially none
3448  int boundary = Tree::OMEGA;
3449  // If we are on the western boundary
3450  if (i0 == 0)
3451  {
3452  boundary = W;
3453  }
3454  // If we are on the eastern boundary
3455  else if (i0 == n_p - 1)
3456  {
3457  boundary = E;
3458  }
3459 
3460  // If we are on the southern boundary
3461  if (i1 == 0)
3462  {
3463  // If we already have already set the boundary, we're on a corner
3464  switch (boundary)
3465  {
3466  case W:
3467  boundary = SW;
3468  break;
3469  case E:
3470  boundary = SE;
3471  break;
3472  // Boundary not set
3473  default:
3474  boundary = S;
3475  break;
3476  }
3477  }
3478  // If we are the northern bounadry
3479  else if (i1 == n_p - 1)
3480  {
3481  // If we already have a boundary
3482  switch (boundary)
3483  {
3484  case W:
3485  boundary = NW;
3486  break;
3487  case E:
3488  boundary = NE;
3489  break;
3490  default:
3491  boundary = N;
3492  break;
3493  }
3494  }
3495 
3496  // set of boundaries that this edge in the son lives on
3497  std::set<unsigned> boundaries;
3498 
3499  // Now get the boundary conditions from the son
3500  // The boundaries will be common to the son because there can be
3501  // no rotations here
3502  if (boundary != Tree::OMEGA)
3503  {
3504  son_el_pt->get_boundaries(boundary, boundaries);
3505  }
3506 
3507  // If the node lives on a boundary:
3508  // Construct a boundary node,
3509  // Get boundary conditions and
3510  // update all lookup schemes
3511  if (boundaries.size() > 0)
3512  {
3513  // Construct the new node
3514  created_node_pt =
3515  this->construct_boundary_node(jnod, time_stepper_pt);
3516 
3517  // Get the boundary conditions from the son
3518  Vector<int> bound_cons(this->ncont_interpolated_values());
3519  son_el_pt->get_bcs(boundary, bound_cons);
3520 
3521  // Loop over the values and pin if necessary
3522  unsigned nval = created_node_pt->nvalue();
3523  for (unsigned k = 0; k < nval; k++)
3524  {
3525  if (bound_cons[k])
3526  {
3527  created_node_pt->pin(k);
3528  }
3529  }
3530 
3531  // Solid node? If so, deal with the positional boundary
3532  // conditions:
3533  SolidNode* solid_node_pt =
3534  dynamic_cast<SolidNode*>(created_node_pt);
3535  if (solid_node_pt != 0)
3536  {
3537  // Get the positional boundary conditions from the father:
3538  unsigned n_dim = created_node_pt->ndim();
3539  Vector<int> solid_bound_cons(n_dim);
3540  RefineableSolidQElement<2>* son_solid_el_pt =
3541  dynamic_cast<RefineableSolidQElement<2>*>(son_el_pt);
3542 #ifdef PARANOID
3543  if (son_solid_el_pt == 0)
3544  {
3545  std::string error_message =
3546  "We have a SolidNode outside a refineable SolidElement\n";
3547  error_message +=
3548  "during mesh refinement -- this doesn't make sense\n";
3549 
3550  throw OomphLibError(error_message,
3551  OOMPH_CURRENT_FUNCTION,
3552  OOMPH_EXCEPTION_LOCATION);
3553  }
3554 #endif
3555  son_solid_el_pt->get_solid_bcs(boundary, solid_bound_cons);
3556 
3557  // Loop over the positions and pin, if necessary
3558  for (unsigned k = 0; k < n_dim; k++)
3559  {
3560  if (solid_bound_cons[k])
3561  {
3562  solid_node_pt->pin_position(k);
3563  }
3564  }
3565  } // End of if solid_node_pt
3566 
3567 
3568  // Next we update the boundary look-up schemes
3569  // Loop over the boundaries stored in the set
3570  for (std::set<unsigned>::iterator it = boundaries.begin();
3571  it != boundaries.end();
3572  ++it)
3573  {
3574  // Add the node to the boundary
3575  mesh_pt->add_boundary_node(*it, created_node_pt);
3576 
3577  // If we have set an intrinsic coordinate on this
3578  // mesh boundary then it must also be interpolated on
3579  // the new node
3580  // Now interpolate the intrinsic boundary coordinate
3581  if (mesh_pt->boundary_coordinate_exists(*it) == true)
3582  {
3583  Vector<double> zeta(1);
3584  son_el_pt->interpolated_zeta_on_edge(
3585  *it, boundary, s_in_son, zeta);
3586 
3587  created_node_pt->set_coordinates_on_boundary(*it, zeta);
3588  }
3589  }
3590  }
3591  // Otherwise the node is not on a Mesh boundary
3592  // and we create a normal "bulk" node
3593  else
3594  {
3595  // Construct the new node
3596  created_node_pt = this->construct_node(jnod, time_stepper_pt);
3597  }
3598 
3599  // Now we set the position and values at the newly created node
3600 
3601  // In the first instance use macro element or FE representation
3602  // to create past and present nodal positions.
3603  // (THIS STEP SHOULD NOT BE SKIPPED FOR ALGEBRAIC
3604  // ELEMENTS AS NOT ALL OF THEM NECESSARILY IMPLEMENT
3605  // NONTRIVIAL NODE UPDATE FUNCTIONS. CALLING
3606  // THE NODE UPDATE FOR SUCH ELEMENTS/NODES WILL LEAVE
3607  // THEIR NODAL POSITIONS WHERE THEY WERE (THIS IS APPROPRIATE
3608  // ONCE THEY HAVE BEEN GIVEN POSITIONS) BUT WILL
3609  // NOT ASSIGN SENSIBLE INITIAL POSITONS!
3610 
3611  // Loop over # of history values
3612  // Loop over # of history values
3613  for (unsigned t = 0; t < ntstorage; t++)
3614  {
3615  using namespace QuadTreeNames;
3616  // Get the position from the son
3617  Vector<double> x_prev(2);
3618 
3619  // Now let's fill in the value
3620  son_el_pt->get_x(t, s_in_son, x_prev);
3621  for (unsigned i = 0; i < 2; i++)
3622  {
3623  created_node_pt->x(t, i) = x_prev[i];
3624  }
3625  }
3626 
3627  // Now set up the values
3628  // Loop over all history values
3629  for (unsigned t = 0; t < ntstorage; t++)
3630  {
3631  // Get values from father element
3632  // Note: get_interpolated_values() sets Vector size itself.
3633  Vector<double> prev_values;
3634  son_el_pt->get_interpolated_values(t, s_in_son, prev_values);
3635 
3636  // Initialise the values at the new node
3637  for (unsigned k = 0; k < created_node_pt->nvalue(); k++)
3638  {
3639  created_node_pt->set_value(t, k, prev_values[k]);
3640  }
3641  }
3642 
3643  // Add the node to the mesh
3644  mesh_pt->add_node_pt(created_node_pt);
3645 
3646  // Check if the element is an algebraic element
3647  AlgebraicElementBase* alg_el_pt =
3648  dynamic_cast<AlgebraicElementBase*>(this);
3649 
3650  // If we do have an algebraic element
3651  if (alg_el_pt != 0)
3652  {
3653  std::string error_message =
3654  "Have not implemented rebuilding from sons for";
3655  error_message += "Algebraic p-refineable elements yet\n";
3656 
3657  throw OomphLibError(
3658  error_message,
3659  "PRefineableQElement<2,INITIAL_NNODE_1D>::rebuild_from_sons()",
3660  OOMPH_EXCEPTION_LOCATION);
3661  }
3662 
3663  } // End of the case when we build the node ourselves
3664  }
3665  } // End of loop over all nodes in element
3666 
3667 
3668  // If the element is a MacroElementNodeUpdateElement, set the update
3669  // parameters for the current element's nodes. These need to be reset
3670  // (as in MacroElementNodeUpdateElement<ELEMENT>::rebuild_from_sons())
3671  // because the nodes in this element have changed
3673  dynamic_cast<MacroElementNodeUpdateElementBase*>(this);
3674  if (m_el_pt != 0)
3675  {
3676  // Loop over the nodes
3677  for (unsigned j = 0; j < this->nnode(); j++)
3678  {
3679  // Get local coordinate in element (Vector sets its own size)
3680  Vector<double> s_in_node_update_element;
3681  this->local_coordinate_of_node(j, s_in_node_update_element);
3682 
3683  // Get vector of geometric objects
3684  Vector<GeomObject*> geom_object_pt(m_el_pt->geom_object_pt());
3685 
3686  // Pass the lot to the node
3687  static_cast<MacroElementNodeUpdateNode*>(this->node_pt(j))
3688  ->set_node_update_info(
3689  this, s_in_node_update_element, geom_object_pt);
3690  }
3691  }
3692 
3693  // MacroElementNodeUpdateElementBase* m_el_pt=dynamic_cast<
3694  // MacroElementNodeUpdateElementBase*>(this);
3695  // if(m_el_pt!=0)
3696  // {
3697  // Loop over all nodes in element again, to re-set the positions
3698  // This must be done using the new element's macro-element
3699  // representation, rather than the old version which may be
3700  // of a different p-order!
3701  for (unsigned i0 = 0; i0 < n_p; i0++)
3702  {
3703  // Get the fractional position of the node
3704  s_fraction[0] = this->local_one_d_fraction_of_node(i0, 0);
3705  // Local coordinate
3706  s[0] = -1.0 + 2.0 * s_fraction[0];
3707 
3708  for (unsigned i1 = 0; i1 < n_p; i1++)
3709  {
3710  // Get the fractional position of the node in the direction of s[1]
3711  s_fraction[1] = this->local_one_d_fraction_of_node(i1, 1);
3712  // Local coordinate in father element
3713  s[1] = -1.0 + 2.0 * s_fraction[1];
3714 
3715  // Set the local node number
3716  jnod = i0 + n_p * i1;
3717 
3718  // Loop over # of history values
3719  for (unsigned t = 0; t < ntstorage; t++)
3720  {
3721  // Get position from father element -- this uses the macro
3722  // element representation if appropriate. If the node
3723  // turns out to be a hanging node later on, then
3724  // its position gets adjusted in line with its
3725  // hanging node interpolation.
3726  Vector<double> x_prev(2);
3727  this->get_x(t, s, x_prev);
3728 
3729  // Set previous positions of the new node
3730  for (unsigned i = 0; i < 2; i++)
3731  {
3732  this->node_pt(jnod)->x(t, i) = x_prev[i];
3733  }
3734  }
3735  }
3736  }
3737  // }
3738  }
3739 
3740  //=================================================================
3741  /// Check inter-element continuity of
3742  /// - nodal positions
3743  /// - (nodally) interpolated function values
3744  /// Overloaded to not check differences in the value. Mortaring
3745  /// doesn't enforce strong continuity between elements.
3746  //====================================================================
3747  template<unsigned INITIAL_NNODE_1D>
3749  double& max_error)
3750  {
3751  // Overloaded to *not* check for continuity in value of interpolated
3752  // variables. This is necessary because mortaring does not ensure continuity
3753  // across element boundaries. It therefore makes no sense to test for this.
3754 
3755  // Dummy set max_error to 0
3756  max_error = 0.0;
3757 
3758  // With macro-elements, (strong) continuity in position is nolonger
3759  // guaranteed either, so we don't check for this either. In fact, we do
3760  // nothing at all.
3761  if (this->macro_elem_pt() != 0)
3762  {
3763  // We have a macro element, so do nothing!
3764  return;
3765  }
3766 
3767  using namespace QuadTreeNames;
3768 
3769  // Number of nodes along edge
3770  unsigned n_p = nnode_1d();
3771 
3772  // Number of timesteps (incl. present) for which continuity is
3773  // to be checked.
3774  unsigned n_time = 1;
3775 
3776  // Initialise errors
3777  max_error = 0.0;
3778  Vector<double> max_error_x(2, 0.0);
3779  double max_error_val = 0.0;
3780 
3781  Vector<int> edges(4);
3782  edges[0] = S;
3783  edges[1] = N;
3784  edges[2] = W;
3785  edges[3] = E;
3786 
3787  // Loop over the edges
3788  for (unsigned edge_counter = 0; edge_counter < 4; edge_counter++)
3789  {
3790  Vector<unsigned> translate_s(2);
3791  Vector<double> s(2), s_lo_neigh(2), s_hi_neigh(2), s_fraction(2);
3792  int neigh_edge, diff_level;
3793  bool in_neighbouring_tree;
3794 
3795  // Find pointer to neighbour in this direction
3796  QuadTree* neigh_pt;
3797  neigh_pt = quadtree_pt()->gteq_edge_neighbour(edges[edge_counter],
3798  translate_s,
3799  s_lo_neigh,
3800  s_hi_neigh,
3801  neigh_edge,
3802  diff_level,
3803  in_neighbouring_tree);
3804 
3805  // Neighbour exists and has existing nodes
3806  if ((neigh_pt != 0) && (neigh_pt->object_pt()->nodes_built()))
3807  {
3808  // Need to exclude periodic nodes from this check
3809  // There are only periodic nodes if we are in a neighbouring tree
3810  bool is_periodic = false;
3811  if (in_neighbouring_tree)
3812  {
3813  // Is it periodic
3814  is_periodic = this->tree_pt()->root_pt()->is_neighbour_periodic(
3815  edges[edge_counter]);
3816  }
3817 
3818  // We also need to exclude edges which may have hanging nodes
3819  // because mortaring does not guarantee (strong) continuity
3820  // in position or in value at nonconforming element boundaries
3821  bool exclude_this_edge = false;
3822  if (diff_level != 0)
3823  {
3824  // h-type nonconformity (dependent)
3825  exclude_this_edge = true;
3826  }
3827  else if (neigh_pt->nsons() != 0)
3828  {
3829  // h-type nonconformity (master)
3830  exclude_this_edge = true;
3831  }
3832  else
3833  {
3834  unsigned my_p_order = this->p_order();
3835  unsigned neigh_p_order =
3836  dynamic_cast<PRefineableQElement*>(neigh_pt->object_pt())
3837  ->p_order();
3838  if (my_p_order != neigh_p_order)
3839  {
3840  // p-type nonconformity
3841  exclude_this_edge = true;
3842  }
3843  }
3844 
3845  // With macro-elements, (strong) continuity in position is nolonger
3846  // guaranteed either, so we don't check for this either. In fact, we do
3847  // nothing at all.
3848  if (dynamic_cast<FiniteElement*>(neigh_pt->object_pt())
3849  ->macro_elem_pt() != 0)
3850  {
3851  // We have a macro element, so do nothing!
3852  break;
3853  }
3854 
3855  // Check conforming edges
3856  if (!exclude_this_edge)
3857  {
3858  // Loop over nodes along the edge
3859  for (unsigned i0 = 0; i0 < n_p; i0++)
3860  {
3861  // Storage for pointer to the local node
3862  Node* local_node_pt = 0;
3863 
3864  switch (edge_counter)
3865  {
3866  case 0:
3867  // Local fraction of node
3868  s_fraction[0] = this->local_one_d_fraction_of_node(i0, 0);
3869  s_fraction[1] = 0.0;
3870  // Get pointer to local node
3871  local_node_pt = this->node_pt(i0);
3872  break;
3873 
3874  case 1:
3875  // Local fraction of node
3876  s_fraction[0] = this->local_one_d_fraction_of_node(i0, 0);
3877  s_fraction[1] = 1.0;
3878  // Get pointer to local node
3879  local_node_pt = this->node_pt(i0 + n_p * (n_p - 1));
3880  break;
3881 
3882  case 2:
3883  // Local fraction of node
3884  s_fraction[0] = 0.0;
3885  s_fraction[1] = this->local_one_d_fraction_of_node(i0, 1);
3886  // Get pointer to local node
3887  local_node_pt = this->node_pt(n_p * i0);
3888  break;
3889 
3890  case 3:
3891  // Local fraction of node
3892  s_fraction[0] = 1.0;
3893  s_fraction[1] = this->local_one_d_fraction_of_node(i0, 1);
3894  // Get pointer to local node
3895  local_node_pt = this->node_pt(n_p - 1 + n_p * i0);
3896  break;
3897  }
3898 
3899  // Calculate the local coordinate and the local coordinate as viewed
3900  // from the neighbour
3901  Vector<double> s_in_neighb(2);
3902  for (unsigned i = 0; i < 2; i++)
3903  {
3904  // Local coordinate in this element
3905  s[i] = -1.0 + 2.0 * s_fraction[i];
3906  // Local coordinate in the neighbour
3907  s_in_neighb[i] =
3908  s_lo_neigh[i] +
3909  s_fraction[translate_s[i]] * (s_hi_neigh[i] - s_lo_neigh[i]);
3910  }
3911 
3912  // Loop over timesteps
3913  for (unsigned t = 0; t < n_time; t++)
3914  {
3915  // Get the nodal position from neighbour element
3916  Vector<double> x_in_neighb(2);
3917  neigh_pt->object_pt()->interpolated_x(
3918  t, s_in_neighb, x_in_neighb);
3919 
3920  // Check error only if the node is NOT periodic
3921  if (is_periodic == false)
3922  {
3923  for (int i = 0; i < 2; i++)
3924  {
3925  // Find the spatial error
3926  double err =
3927  std::fabs(local_node_pt->x(t, i) - x_in_neighb[i]);
3928 
3929  // If it's bigger than our tolerance, say so
3930  if (err > 1e-9)
3931  {
3932  oomph_info << "errx " << err << " " << t << " "
3933  << local_node_pt->x(t, i) << " "
3934  << x_in_neighb[i] << std::endl;
3935 
3936  oomph_info << "at " << local_node_pt->x(0) << " "
3937  << local_node_pt->x(1) << std::endl;
3938  }
3939 
3940  // If it's bigger than the previous max error, it is the
3941  // new max error!
3942  if (err > max_error_x[i])
3943  {
3944  max_error_x[i] = err;
3945  }
3946  }
3947  }
3948 
3949  // Get the values from neighbour element. Note: # of values
3950  // gets set by routine (because in general we don't know
3951  // how many interpolated values a certain element has
3952  Vector<double> values_in_neighb;
3953  neigh_pt->object_pt()->get_interpolated_values(
3954  t, s_in_neighb, values_in_neighb);
3955 
3956  // Get the values in current element.
3957  Vector<double> values;
3958  this->get_interpolated_values(t, s, values);
3959 
3960  // Now figure out how many continuously interpolated values there
3961  // are
3962  unsigned num_val =
3963  neigh_pt->object_pt()->ncont_interpolated_values();
3964 
3965  // Check error
3966  for (unsigned ival = 0; ival < num_val; ival++)
3967  {
3968  double err = std::fabs(values[ival] - values_in_neighb[ival]);
3969 
3970  if (err > 1.0e-10)
3971  {
3972  oomph_info << local_node_pt->x(0) << " "
3973  << local_node_pt->x(1) << " \n# "
3974  << "erru (S)" << err << " " << ival << " "
3975  << this->get_node_number(local_node_pt) << " "
3976  << values[ival] << " " << values_in_neighb[ival]
3977  << std::endl;
3978  }
3979 
3980  if (err > max_error_val)
3981  {
3982  max_error_val = err;
3983  }
3984  }
3985  }
3986  }
3987  }
3988  }
3989  }
3990 
3991  max_error = max_error_x[0];
3992  if (max_error_x[1] > max_error) max_error = max_error_x[1];
3993  if (max_error_val > max_error) max_error = max_error_val;
3994 
3995  if (max_error > 1e-9)
3996  {
3997  oomph_info << "\n#------------------------------------ \n#Max error ";
3998  oomph_info << max_error_x[0] << " " << max_error_x[1] << " "
3999  << max_error_val << std::endl;
4000  oomph_info << "#------------------------------------ \n " << std::endl;
4001  }
4002  }
4003 
4004  //=================================================================
4005  /// Internal function to set up the hanging nodes on a particular
4006  /// edge of the element.
4007  /// Implements the mortarting method to enforce continuity weakly
4008  /// across non-conforming element boundaries \f$\Gamma\f$ using an
4009  /// integral matching condition
4010  /// \f[ \int_\Gamma (u_{\mbox{S}} - u_{\mbox{M}}) \psi \mbox{d} s = 0 \f]
4011  /// for all polynomials \f$\psi\f$ on \f$\Gamma\f$ of degree at most
4012  /// p-2 (where p is the spectral-order of the dependent element) and a
4013  /// vertex matching condition
4014  /// \f[ (u_{\mbox{S}} - u_{\mbox{M}})\big\vert_{\partial\Gamma} = 0.\f]
4015  ///
4016  /// The algorithm works as follows:
4017  /// - First the element determines if its edge my_edge is on the
4018  /// master or dependent side of the non-conformity.
4019  /// At h-type non-conformities
4020  /// we choose long edges to be masters, and at p-type nonconformities the
4021  /// edge with lower p-order is the master.
4022  /// - Mortaring is performed by the dependent side.
4023  /// - If a vertex node of the mortar is shared between master and dependent
4024  /// element then the vertex matching condition is enforced automatically.
4025  /// Otherwise it must be imposed by constraining its value to that at on
4026  /// the master side.
4027  /// - The integral matching condition is discretised and the mortar test
4028  /// functions \f$ \psi \f$ are chosen to be derivatives of Legendre
4029  /// polynomials of degree p-1.
4030  /// - The mortar mass matrix M is constructed. Its entries are the
4031  /// mortar test functions evaluated at the dependent nodal positions,
4032  /// so it is diagonal.
4033  /// - The local projection matrix is constructed for the master element by
4034  /// applying the discretised integral matching condition along the mortar
4035  /// using the appropriate quadrature order.
4036  /// - The global projection matrix is then assembled by subtracting
4037  /// contributions from the mortar vertex nodes.
4038  /// - The mortar system \f$ M\xi^s = P\hat{\xi^m} \f$ is constructed,
4039  /// where \f$ \xi^m \f$ and \f$ \xi^s \f$ are the nodal values at
4040  /// the master and dependent nodes respectively.
4041  /// - The conformity matrix \f$ C = M^{-1}P \f$ is computed. This is
4042  /// straightforward since the mass matrix is diagonal.
4043  /// - Finally, the master nodes and weights for each dependent node
4044  /// are read from
4045  /// the conformity matrix and stored in the dependents' hanging schemes.
4046  ///
4047  /// The positions of the dependent nodes are set to be consistent with their
4048  /// hanging schemes.
4049  //=================================================================
4050  template<unsigned INITIAL_NNODE_1D>
4052  const int& value_id, const int& my_edge, std::ofstream& output_hangfile)
4053  {
4054  using namespace QuadTreeNames;
4055 
4056  Vector<unsigned> translate_s(2);
4057  Vector<double> s_lo_neigh(2);
4058  Vector<double> s_hi_neigh(2);
4059  int neigh_edge, diff_level;
4060  bool in_neighbouring_tree;
4061 
4062  // Find pointer to neighbour in this direction
4063  QuadTree* neigh_pt;
4064  neigh_pt = this->quadtree_pt()->gteq_edge_neighbour(my_edge,
4065  translate_s,
4066  s_lo_neigh,
4067  s_hi_neigh,
4068  neigh_edge,
4069  diff_level,
4070  in_neighbouring_tree);
4071 
4072  // Work out master/dependent edges
4073  //----------------------------
4074 
4075  // Set up booleans
4076  // bool h_type_master = false;
4077  bool h_type_dependent = false;
4078  // bool p_type_master = false;
4079  bool p_type_dependent = false;
4080 
4081  // Neighbour exists and all nodes have been created
4082  if (neigh_pt != 0)
4083  {
4084  // Check if neighbour is bigger than me
4085  if (diff_level != 0)
4086  {
4087  // Dependent at h-type non-conformity
4088  h_type_dependent = true;
4089  }
4090  // Check if neighbour is the same size as me
4091  else if (neigh_pt->nsons() == 0)
4092  {
4093  // Neighbour is same size as me
4094  // Find p-orders of each element
4095  unsigned my_p_order =
4096  dynamic_cast<PRefineableQElement<2, INITIAL_NNODE_1D>*>(this)
4097  ->p_order();
4098  unsigned neigh_p_order =
4100  neigh_pt->object_pt())
4101  ->p_order();
4102 
4103  // Check for p-type non-conformity
4104  if (neigh_p_order == my_p_order)
4105  {
4106  // At a conforming interface
4107  }
4108  else if (neigh_p_order < my_p_order)
4109  {
4110  // Dependent at p-type non-conformity
4111  p_type_dependent = true;
4112  }
4113  else
4114  {
4115  // Master at p-type non-conformity
4116  // p_type_master = true;
4117  }
4118  }
4119  // Neighbour must be smaller than me
4120  else
4121  {
4122  // Master at h-type non-conformity
4123  // h_type_master = true;
4124  }
4125  }
4126  else
4127  {
4128  // Edge is on a boundary
4129  }
4130 
4131  // Now do the mortaring
4132  //---------------------
4133  if (h_type_dependent || p_type_dependent)
4134  {
4135  // Compute the active coordinate index along the this side of mortar
4136  unsigned active_coord_index;
4137  if (my_edge == N || my_edge == S) active_coord_index = 0;
4138  else if (my_edge == E || my_edge == W)
4139  active_coord_index = 1;
4140  else
4141  {
4142  throw OomphLibError("Cannot transform coordinates",
4143  OOMPH_CURRENT_FUNCTION,
4144  OOMPH_EXCEPTION_LOCATION);
4145  }
4146 
4147  // Get pointer to neighbouring master element (in p-refineable form)
4149  neigh_obj_pt = dynamic_cast<PRefineableQElement<2, INITIAL_NNODE_1D>*>(
4150  neigh_pt->object_pt());
4151 
4152  // Create vector of master and dependent nodes
4153  //----------------------------------------
4154  Vector<Node*> master_node_pt, dependent_node_pt;
4155  Vector<unsigned> master_node_number, dependent_node_number;
4156  Vector<Vector<double>> dependent_node_s_fraction;
4157 
4158  // Number of nodes in one dimension
4159  const unsigned my_n_p = this->ninterpolating_node_1d(value_id);
4160  const unsigned neigh_n_p = neigh_obj_pt->ninterpolating_node_1d(value_id);
4161 
4162  // Test for the periodic node case
4163  // Are we crossing a periodic boundary
4164  bool is_periodic = false;
4165  if (in_neighbouring_tree)
4166  {
4167  is_periodic =
4168  this->tree_pt()->root_pt()->is_neighbour_periodic(my_edge);
4169  }
4170 
4171  // If it is periodic we actually need to get the node in
4172  // the neighbour of the neighbour (which will be a parent of
4173  // the present element) so that the "fixed" coordinate is
4174  // correctly calculated.
4175  // The idea is to replace the neigh_pt and associated data
4176  // with those of the neighbour of the neighbour
4177  if (is_periodic)
4178  {
4179  throw OomphLibError(
4180  "Cannot do mortaring with periodic hanging nodes yet! (Fix me!)",
4181  "PRefineableQElement<2,INITIAL_NNODE_1D>::quad_hang_helper()",
4182  OOMPH_EXCEPTION_LOCATION);
4183  } // End of special treatment for periodic hanging nodes
4184 
4185  // Storage for pointers to the nodes and their numbers along the master
4186  // edge
4187  unsigned neighbour_node_number = 0;
4188  Node* neighbour_node_pt = 0;
4189 
4190  // Loop over nodes along the edge
4191  for (unsigned i0 = 0; i0 < neigh_n_p; i0++)
4192  {
4193  // Find the neighbour's node
4194  switch (neigh_edge)
4195  {
4196  case N:
4197  neighbour_node_number = i0 + neigh_n_p * (neigh_n_p - 1);
4198  neighbour_node_pt = neigh_obj_pt->interpolating_node_pt(
4199  neighbour_node_number, value_id);
4200  break;
4201 
4202  case S:
4203  neighbour_node_number = i0;
4204  neighbour_node_pt = neigh_obj_pt->interpolating_node_pt(
4205  neighbour_node_number, value_id);
4206  break;
4207 
4208  case E:
4209  neighbour_node_number = neigh_n_p - 1 + neigh_n_p * i0;
4210  neighbour_node_pt = neigh_obj_pt->interpolating_node_pt(
4211  neighbour_node_number, value_id);
4212  break;
4213 
4214  case W:
4215  neighbour_node_number = neigh_n_p * i0;
4216  neighbour_node_pt = neigh_obj_pt->interpolating_node_pt(
4217  neighbour_node_number, value_id);
4218  break;
4219 
4220  default:
4221  throw OomphLibError("my_edge not N, S, W, E\n",
4222  OOMPH_CURRENT_FUNCTION,
4223  OOMPH_EXCEPTION_LOCATION);
4224  }
4225 
4226  // Set node as master node
4227  master_node_number.push_back(neighbour_node_number);
4228  master_node_pt.push_back(neighbour_node_pt);
4229  }
4230 
4231  // Storage for pointers to the local nodes and their numbers along my edge
4232  unsigned local_node_number = 0;
4233  Node* local_node_pt = 0;
4234 
4235  // Loop over the nodes along my edge
4236  for (unsigned i0 = 0; i0 < my_n_p; i0++)
4237  {
4238  // Storage for the fractional position of the node in the element
4239  Vector<double> s_fraction(2);
4240 
4241  // Find the local node and the fractional position of the node
4242  // which depends on the edge, of course
4243  switch (my_edge)
4244  {
4245  case N:
4246  s_fraction[0] =
4247  local_one_d_fraction_of_interpolating_node(i0, 0, value_id);
4248  s_fraction[1] = 1.0;
4249  local_node_number = i0 + my_n_p * (my_n_p - 1);
4250  local_node_pt =
4251  this->interpolating_node_pt(local_node_number, value_id);
4252  break;
4253 
4254  case S:
4255  s_fraction[0] =
4256  local_one_d_fraction_of_interpolating_node(i0, 0, value_id);
4257  s_fraction[1] = 0.0;
4258  local_node_number = i0;
4259  local_node_pt =
4260  this->interpolating_node_pt(local_node_number, value_id);
4261  break;
4262 
4263  case E:
4264  s_fraction[0] = 1.0;
4265  s_fraction[1] =
4266  local_one_d_fraction_of_interpolating_node(i0, 1, value_id);
4267  local_node_number = my_n_p - 1 + my_n_p * i0;
4268  local_node_pt =
4269  this->interpolating_node_pt(local_node_number, value_id);
4270  break;
4271 
4272  case W:
4273  s_fraction[0] = 0.0;
4274  s_fraction[1] =
4275  local_one_d_fraction_of_interpolating_node(i0, 1, value_id);
4276  local_node_number = my_n_p * i0;
4277  local_node_pt =
4278  this->interpolating_node_pt(local_node_number, value_id);
4279  break;
4280 
4281  default:
4282  throw OomphLibError("my_edge not N, S, W, E\n",
4283  OOMPH_CURRENT_FUNCTION,
4284  OOMPH_EXCEPTION_LOCATION);
4285  }
4286 
4287  // Add node to vector of dependent element nodes
4288  dependent_node_number.push_back(local_node_number);
4289  dependent_node_pt.push_back(local_node_pt);
4290 
4291  // Store node's local fraction
4292  dependent_node_s_fraction.push_back(s_fraction);
4293  }
4294 
4295  // Store the number of dependent and master nodes for use later
4296  const unsigned n_dependent_nodes = dependent_node_pt.size();
4297  const unsigned n_master_nodes = master_node_pt.size();
4298  const unsigned dependent_element_nnode_1d = my_n_p;
4299  const unsigned master_element_nnode_1d = neigh_n_p;
4300 
4301  // Storage for master shapes
4302  Shape master_shapes(neigh_obj_pt->ninterpolating_node(value_id));
4303 
4304  // Get master and dependent nodal positions
4305  //-------------------------------------
4306  Vector<double> dependent_nodal_position;
4307  Vector<double> dependent_weight(dependent_element_nnode_1d);
4309  dependent_element_nnode_1d, dependent_nodal_position, dependent_weight);
4310  Vector<double> master_nodal_position;
4311  Vector<double> master_weight(master_element_nnode_1d);
4313  master_element_nnode_1d, master_nodal_position, master_weight);
4314 
4315  // Apply the vertex matching condition
4316  //------------------------------------
4317  // Vertiex matching is ensured automatically in cases where there is a
4318  // node at each end of the mortar that is shared between the master and
4319  // dependent elements. Where this is not the case, the vertex matching
4320  // condition must be enforced by constraining the value of the unknown at
4321  // the node on the dependent side to be the same as the value at that
4322  // location in the master.
4323 
4324  // Store positions of the mortar vertex/non-vertex nodes in the dependent
4325  // element
4326  const unsigned n_mortar_vertices = 2;
4327  Vector<unsigned> vertex_pos(n_mortar_vertices);
4328  vertex_pos[0] = 0;
4329  vertex_pos[1] = this->ninterpolating_node_1d(value_id) - 1;
4330  Vector<unsigned> non_vertex_pos(my_n_p - n_mortar_vertices);
4331  for (unsigned i = 0; i < my_n_p - n_mortar_vertices; i++)
4332  {
4333  non_vertex_pos[i] = i + 1;
4334  }
4335 
4336  // Check if the mortar vertices are shared
4337  for (unsigned v = 0; v < n_mortar_vertices; v++)
4338  {
4339  // Search master node storage for the node
4340  bool node_is_shared = false;
4341  for (unsigned i = 0; i < master_node_pt.size(); i++)
4342  {
4343  if (dependent_node_pt[vertex_pos[v]] == master_node_pt[i])
4344  {
4345  node_is_shared = true;
4346  break;
4347  }
4348  }
4349 
4350  // If the node is not shared then we must constrain its value by setting
4351  // up a hanging scheme
4352  if (!node_is_shared)
4353  {
4354  // Calculate weights. These are just the master shapes evaluated at
4355  // this dependent node's position
4356 
4357  // Work out this node's location in the master
4358  Vector<double> s_in_neigh(2);
4359  for (unsigned i = 0; i < 2; i++)
4360  {
4361  s_in_neigh[i] =
4362  s_lo_neigh[i] +
4363  dependent_node_s_fraction[vertex_pos[v]][translate_s[i]] *
4364  (s_hi_neigh[i] - s_lo_neigh[i]);
4365  }
4366 
4367  // Get master shapes at dependent nodal positions
4368  neigh_obj_pt->interpolating_basis(
4369  s_in_neigh, master_shapes, value_id);
4370 
4371  // Remove any existing hanging node info
4372  // (This may be a bit wasteful, but guarantees correctness)
4373  dependent_node_pt[vertex_pos[v]]->set_nonhanging();
4374 
4375  // Set up hanging scheme for this node
4376  HangInfo* explicit_hang_pt = new HangInfo(n_master_nodes);
4377  for (unsigned m = 0; m < n_master_nodes; m++)
4378  {
4379  explicit_hang_pt->set_master_node_pt(
4380  m, master_node_pt[m], master_shapes[master_node_number[m]]);
4381  }
4382 
4383  // Make node hang
4384  dependent_node_pt[vertex_pos[v]]->set_hanging_pt(explicit_hang_pt,
4385  -1);
4386  }
4387  }
4388 
4389  // Check that there are actually dependent nodes for which we still need
4390  // to construct a hanging scheme. If not then there is nothing more to do.
4391  if (n_dependent_nodes - n_mortar_vertices > 0)
4392  {
4393  // Assemble mass matrix for mortar
4394  //--------------------------------
4395  Vector<double> psi(n_dependent_nodes - n_mortar_vertices);
4396  Vector<double> diag_M(n_dependent_nodes - n_mortar_vertices);
4397  Vector<Vector<double>> shared_node_M(n_mortar_vertices);
4398  for (unsigned i = 0; i < shared_node_M.size(); i++)
4399  {
4400  shared_node_M[i].resize(n_dependent_nodes - n_mortar_vertices);
4401  }
4402 
4403  // Fill in part corresponding to dependent nodal positions (unknown)
4404  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
4405  {
4406  // Use L'Hosptal's rule:
4407  psi[i] =
4408  pow(-1.0, int((dependent_element_nnode_1d - 1) - i - 1)) *
4409  -Orthpoly::ddlegendre(dependent_element_nnode_1d - 1,
4410  dependent_nodal_position[non_vertex_pos[i]]);
4411  // Put in contribution
4412  diag_M[i] = psi[i] * dependent_weight[non_vertex_pos[i]];
4413  }
4414 
4415  // Fill in part corresponding to dependent element vertices (known)
4416  for (unsigned v = 0; v < shared_node_M.size(); v++)
4417  {
4418  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
4419  {
4420  // Check if denominator is zero
4421  if (std::fabs(dependent_nodal_position[non_vertex_pos[i]] -
4422  dependent_nodal_position[vertex_pos[v]]) >= 1.0e-8)
4423  {
4424  // We're ok
4425  psi[i] =
4426  pow(-1.0, int((dependent_element_nnode_1d - 1) - i - 1)) *
4427  Orthpoly::dlegendre(dependent_element_nnode_1d - 1,
4428  dependent_nodal_position[vertex_pos[v]]) /
4429  (dependent_nodal_position[non_vertex_pos[i]] -
4430  dependent_nodal_position[vertex_pos[v]]);
4431  }
4432  // Check if numerator is zero
4433  else if (std::fabs(Orthpoly::dlegendre(
4434  dependent_element_nnode_1d - 1,
4435  dependent_nodal_position[vertex_pos[v]])) < 1.0e-8)
4436  {
4437  // We can use l'hopital's rule
4438  psi[i] =
4439  pow(-1.0, int((dependent_element_nnode_1d - 1) - i - 1)) *
4441  dependent_element_nnode_1d - 1,
4442  dependent_nodal_position[non_vertex_pos[i]]);
4443  }
4444  else
4445  {
4446  // We can't use l'hopital's rule
4447  throw OomphLibError(
4448  "Cannot use l'Hopital's rule. Dividing by zero is not allowed!",
4449  "PRefineableQElement<2,INITIAL_NNODE_1D>::quad_hang_helper()",
4450  OOMPH_EXCEPTION_LOCATION);
4451  }
4452  // Put in contribution
4453  shared_node_M[v][i] = psi[i] * dependent_weight[vertex_pos[v]];
4454  }
4455  }
4456 
4457  // Assemble local projection matrix for mortar
4458  //--------------------------------------------
4459 
4460  // Have only one local projection matrix because there is just one
4461  // master
4462  Vector<Vector<double>> P(n_dependent_nodes - n_mortar_vertices);
4463  for (unsigned i = 0; i < P.size(); i++)
4464  {
4465  P[i].resize(n_master_nodes, 0.0);
4466  }
4467 
4468  // Storage for local coordinate
4469  Vector<double> s(2);
4470 
4471  // Sum contributions from master element shapes (quadrature).
4472  // The order of quadrature must be high enough to evaluate a polynomial
4473  // of order N_s + N_m - 3 exactly, where N_s = n_dependent_nodes, N_m =
4474  // n_master_nodes.
4475  // (Use pointers for the quadrature knots and weights so that
4476  // data is not unnecessarily copied)
4477  // unsigned quadrature_order =
4478  // std::max(dependent_element_nnode_1d,master_element_nnode_1d);
4479  Vector<double>*quadrature_knot, *quadrature_weight;
4480  if (dependent_element_nnode_1d >= master_element_nnode_1d)
4481  {
4482  // Use the same quadrature order as the dependent element (me)
4483  quadrature_knot = &dependent_nodal_position;
4484  quadrature_weight = &dependent_weight;
4485  }
4486  else
4487  {
4488  // Use the same quadrature order as the master element (neighbour)
4489  quadrature_knot = &master_nodal_position;
4490  quadrature_weight = &master_weight;
4491  }
4492 
4493  // Quadrature loop
4494  for (unsigned q = 0; q < (*quadrature_weight).size(); q++)
4495  {
4496  // Evaluate mortar test functions at the quadrature knots in the
4497  // dependent
4498  // s[active_coord_index] = (*quadrature_knot)[q];
4499  Vector<double> s_on_mortar(1);
4500  s_on_mortar[0] = (*quadrature_knot)[q];
4501 
4502  // Get psi
4503  for (unsigned k = 0; k < n_dependent_nodes - n_mortar_vertices; k++)
4504  {
4505  // Check if denominator is zero
4506  if (std::fabs(dependent_nodal_position[non_vertex_pos[k]] -
4507  s_on_mortar[0]) >= 1.0e-08)
4508  {
4509  // We're ok
4510  psi[k] =
4511  pow(-1.0, int((dependent_element_nnode_1d - 1) - k - 1)) *
4512  Orthpoly::dlegendre(dependent_element_nnode_1d - 1,
4513  s_on_mortar[0]) /
4514  (dependent_nodal_position[non_vertex_pos[k]] - s_on_mortar[0]);
4515  }
4516  // Check if numerator is zero
4517  else if (std::fabs(Orthpoly::dlegendre(
4518  dependent_element_nnode_1d - 1, s_on_mortar[0])) <
4519  1.0e-8)
4520  {
4521  // We can use l'Hopital's rule
4522  psi[k] =
4523  pow(-1.0, int((dependent_element_nnode_1d - 1) - k - 1)) *
4524  -Orthpoly::ddlegendre(dependent_element_nnode_1d - 1,
4525  s_on_mortar[0]);
4526  }
4527  else
4528  {
4529  // We can't use l'hopital's rule
4530  throw OomphLibError(
4531  "Cannot use l'Hopital's rule. Dividing by zero is not allowed!",
4532  "PRefineableQElement<2,INITIAL_NNODE_1D>::quad_hang_helper()",
4533  OOMPH_EXCEPTION_LOCATION);
4534  }
4535  }
4536 
4537  // Convert coordinate on mortar to local fraction in dependent element
4538  Vector<double> s_fraction(2);
4539  for (unsigned i = 0; i < 2; i++)
4540  {
4541  s_fraction[i] = (i == active_coord_index) ?
4542  0.5 * (s_on_mortar[0] + 1.0) :
4543  dependent_node_s_fraction[vertex_pos[0]][i];
4544  }
4545 
4546  // Project active coordinate into master element
4547  Vector<double> s_in_neigh(2);
4548  for (unsigned i = 0; i < 2; i++)
4549  {
4550  s_in_neigh[i] = s_lo_neigh[i] + s_fraction[translate_s[i]] *
4551  (s_hi_neigh[i] - s_lo_neigh[i]);
4552  }
4553 
4554  // Evaluate master shapes at projections of local quadrature knots
4555  neigh_obj_pt->interpolating_basis(
4556  s_in_neigh, master_shapes, value_id);
4557 
4558  // Populate local projection matrix
4559  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
4560  {
4561  for (unsigned j = 0; j < n_master_nodes; j++)
4562  {
4563  P[i][j] += master_shapes[master_node_number[j]] * psi[i] *
4564  (*quadrature_weight)[q];
4565  }
4566  }
4567  }
4568 
4569  // Assemble global projection matrices for mortar
4570  //-----------------------------------------------
4571  // Need to subtract contributions from the "known unknowns"
4572  // corresponding to the nodes at the vertices of the mortar
4573 
4574  // Assemble contributions from mortar vertex nodes
4575  for (unsigned v = 0; v < n_mortar_vertices; v++)
4576  {
4577  // Convert coordinate on mortar to local fraction in dependent element
4578  Vector<double> s_fraction(2);
4579  for (unsigned i = 0; i < 2; i++)
4580  {
4581  s_fraction[i] =
4582  (i == active_coord_index) ?
4583  0.5 * (dependent_nodal_position[vertex_pos[v]] + 1.0) :
4584  dependent_node_s_fraction[vertex_pos[0]][i];
4585  }
4586 
4587  // Project active coordinate into master element
4588  Vector<double> s_in_neigh(2);
4589  for (unsigned i = 0; i < 2; i++)
4590  {
4591  s_in_neigh[i] = s_lo_neigh[i] + s_fraction[translate_s[i]] *
4592  (s_hi_neigh[i] - s_lo_neigh[i]);
4593  }
4594 
4595  // Get master shapes at dependent nodal positions
4596  neigh_obj_pt->interpolating_basis(
4597  s_in_neigh, master_shapes, value_id);
4598 
4599  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
4600  {
4601  for (unsigned k = 0; k < n_master_nodes; k++)
4602  {
4603  P[i][k] -=
4604  master_shapes[master_node_number[k]] * shared_node_M[v][i];
4605  }
4606  }
4607  }
4608 
4609  // Solve mortar system
4610  //--------------------
4611  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
4612  {
4613  for (unsigned j = 0; j < n_master_nodes; j++)
4614  {
4615  P[i][j] /= diag_M[i];
4616  }
4617  }
4618 
4619  // Create structures to hold the hanging info
4620  //-------------------------------------------
4621  Vector<HangInfo*> hang_info_pt(n_dependent_nodes);
4622  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
4623  {
4624  hang_info_pt[i] = new HangInfo(n_master_nodes);
4625  }
4626 
4627  // Copy information to hanging nodes
4628  //----------------------------------
4629  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
4630  {
4631  for (unsigned j = 0; j < n_master_nodes; j++)
4632  {
4633  hang_info_pt[i]->set_master_node_pt(j, master_node_pt[j], P[i][j]);
4634  }
4635  }
4636 
4637  // Set pointers to hanging info
4638  //-----------------------------
4639  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
4640  {
4641  // Check that the node shoule actually hang.
4642  // That is, if the polynomial orders of the elements at a p-type
4643  // non-conormity are both odd then the middle node on the edge is
4644  // shared but a hanging scheme has been constructed for it.
4645  bool node_is_really_shared = false;
4646  for (unsigned m = 0; m < hang_info_pt[i]->nmaster(); m++)
4647  {
4648  // We can simply check if the hanging scheme lists itself as a
4649  // master
4650  if (hang_info_pt[i]->master_node_pt(m) ==
4651  dependent_node_pt[non_vertex_pos[i]])
4652  {
4653  node_is_really_shared = true;
4654 
4655 #ifdef PARANOID
4656  // Also check the corresponding weight: it should be 1
4657  if (std::fabs(hang_info_pt[i]->master_weight(m) - 1.0) > 1.0e-06)
4658  {
4659  throw OomphLibError(
4660  "Something fishy here -- with shared node at a mortar vertex",
4661  "PRefineableQElemen<2,INITIAL_NNODE_1D>t::quad_hang_helper()",
4662  OOMPH_EXCEPTION_LOCATION);
4663  }
4664 #endif
4665  }
4666  }
4667 
4668  // Now we can make the node hang, if it isn't a shared node
4669  if (!node_is_really_shared)
4670  {
4671  dependent_node_pt[non_vertex_pos[i]]->set_hanging_pt(
4672  hang_info_pt[i], -1);
4673  }
4674  }
4675 
4676  } // End of case where there are still dependent nodes
4677 
4678 #ifdef PARANOID
4679  // Check all dependent nodes, hanging or otherwise
4680  for (unsigned i = 0; i < n_dependent_nodes; i++)
4681  {
4682  // Check that weights sum to 1 for those that hang
4683  if (dependent_node_pt[i]->is_hanging())
4684  {
4685  // Check that weights sum to 1
4686  double weight_sum = 0.0;
4687  for (unsigned m = 0;
4688  m < dependent_node_pt[i]->hanging_pt()->nmaster();
4689  m++)
4690  {
4691  weight_sum += dependent_node_pt[i]->hanging_pt()->master_weight(m);
4692  }
4693 
4694  // Warn if not
4695  if (std::fabs(weight_sum - 1.0) > 1.0e-08)
4696  {
4697  oomph_info << "Sum of master weights: " << weight_sum << std::endl;
4699  "Weights in hanging scheme do not sum to 1",
4700  "PRefineableQElement<2,INITIAL_NNODE_1D>::quad_hang_helper()",
4701  OOMPH_EXCEPTION_LOCATION);
4702  }
4703  }
4704  else
4705  {
4706  // Check that this node is shared with the master element if it
4707  // isn't hanging
4708  bool is_master = false;
4709  for (unsigned n = 0; n < n_master_nodes; n++)
4710  {
4711  if (dependent_node_pt[i] == master_node_pt[n])
4712  {
4713  // Node is a master
4714  is_master = true;
4715  break;
4716  }
4717  }
4718 
4719  if (!is_master)
4720  {
4721  // Throw error
4722  std::ostringstream error_string;
4723  error_string << "This node in the dependent element is neither"
4724  << std::endl
4725  << "hanging or shared with a master element."
4726  << std::endl;
4727 
4728  throw OomphLibError(
4729  error_string.str(),
4730  "PRefineableQElement<2,INITIAL_NNODE_1D>::quad_hang_helper()",
4731  OOMPH_EXCEPTION_LOCATION);
4732  }
4733  }
4734  }
4735 #endif
4736 
4737  // Finally, Loop over all dependent nodes and fine-tune their positions
4738  //-----------------------------------------------------------------
4739  // Here we simply set the node's positions to be consistent
4740  // with the hanging scheme. This is not strictly necessary
4741  // because it is done in the mesh adaptation before the node
4742  // becomes non-hanging later on. We make no attempt to ensure
4743  // (strong) continuity in the position across the mortar.
4744  for (unsigned i = 0; i < n_dependent_nodes; i++)
4745  {
4746  // Only fine-tune hanging nodes
4747  if (dependent_node_pt[i]->is_hanging())
4748  {
4749  // If we are doing the position, then
4750  if (value_id == -1)
4751  {
4752  // Get the local coordinate of this dependent node
4753  Vector<double> s_local(2);
4754  this->local_coordinate_of_node(dependent_node_number[i], s_local);
4755 
4756  // Get the position from interpolation in this element via
4757  // the hanging scheme
4758  Vector<double> x_in_neighb(2);
4759  this->interpolated_x(s_local, x_in_neighb);
4760 
4761  // Fine adjust the coordinates (macro map will pick up boundary
4762  // accurately but will lead to different element edges)
4763  dependent_node_pt[i]->x(0) = x_in_neighb[0];
4764  dependent_node_pt[i]->x(1) = x_in_neighb[1];
4765  }
4766  }
4767  }
4768  } // End of case where this interface is to be mortared
4769  }
4770 
4771  /// /////////////////////////////////////////////////////////////
4772  // 3D PRefineableQElements
4773  /// /////////////////////////////////////////////////////////////
4774 
4775  /// Get local coordinates of node j in the element; vector sets its own size
4776  template<unsigned INITIAL_NNODE_1D>
4778  const unsigned& n, Vector<double>& s) const
4779  {
4780  s.resize(3);
4781  unsigned Nnode_1d = this->nnode_1d();
4782  unsigned n0 = n % Nnode_1d;
4783  unsigned n1 = unsigned(double(n) / double(Nnode_1d)) % Nnode_1d;
4784  unsigned n2 = unsigned(double(n) / double(Nnode_1d * Nnode_1d));
4785 
4786  switch (Nnode_1d)
4787  {
4788  case 2:
4793  break;
4794  case 3:
4799  break;
4800  case 4:
4805  break;
4806  case 5:
4811  break;
4812  case 6:
4817  break;
4818  case 7:
4823  break;
4824  default:
4825  std::ostringstream error_message;
4826  error_message << "\nERROR: Exceeded maximum polynomial order for";
4827  error_message << "\n shape functions.\n";
4828  throw OomphLibError(error_message.str(),
4829  OOMPH_CURRENT_FUNCTION,
4830  OOMPH_EXCEPTION_LOCATION);
4831  break;
4832  }
4833  }
4834 
4835  /// Get the local fractino of node j in the element
4836  template<unsigned INITIAL_NNODE_1D>
4838  const unsigned& n, Vector<double>& s_fraction)
4839  {
4840  this->local_coordinate_of_node(n, s_fraction);
4841  s_fraction[0] = 0.5 * (s_fraction[0] + 1.0);
4842  s_fraction[1] = 0.5 * (s_fraction[1] + 1.0);
4843  s_fraction[2] = 0.5 * (s_fraction[2] + 1.0);
4844  }
4845 
4846  template<unsigned INITIAL_NNODE_1D>
4848  const unsigned& n1d, const unsigned& i)
4849  {
4850  switch (this->nnode_1d())
4851  {
4852  case 2:
4854  return 0.5 *
4856  case 3:
4858  return 0.5 *
4860  case 4:
4862  return 0.5 *
4864  case 5:
4866  return 0.5 *
4868  case 6:
4870  return 0.5 *
4872  case 7:
4874  return 0.5 *
4876  default:
4877  std::ostringstream error_message;
4878  error_message << "\nERROR: Exceeded maximum polynomial order for";
4879  error_message << "\n shape functions.\n";
4880  throw OomphLibError(error_message.str(),
4881  OOMPH_CURRENT_FUNCTION,
4882  OOMPH_EXCEPTION_LOCATION);
4883  return 0.0;
4884  }
4885  }
4886 
4887  //==================================================================
4888  /// Return the node at the specified local coordinate
4889  //==================================================================
4890  template<unsigned INITIAL_NNODE_1D>
4892  const Vector<double>& s) const
4893  {
4894  unsigned Nnode_1d = this->nnode_1d();
4895  // Load the tolerance into a local variable
4897  // There are two possible indices.
4898  Vector<int> index(3);
4899 
4900  // Loop over indices
4901  for (unsigned i = 0; i < 3; i++)
4902  {
4903  // Determine the index
4904  // -------------------
4905 
4906  bool is_found = false;
4907 
4908  // If we are at the lower limit, the index is zero
4909  if (std::fabs(s[i] + 1.0) < tol)
4910  {
4911  index[i] = 0;
4912  is_found = true;
4913  }
4914  // If we are at the upper limit, the index is the number of nodes minus 1
4915  else if (std::fabs(s[i] - 1.0) < tol)
4916  {
4917  index[i] = Nnode_1d - 1;
4918  is_found = true;
4919  }
4920  // Otherwise, we have to calculate the index in general
4921  else
4922  {
4923  // Compute Gauss-Lobatto-Legendre node positions
4924  Vector<double> z;
4925  Orthpoly::gll_nodes(Nnode_1d, z);
4926  // Loop over possible internal nodal positions
4927  for (unsigned n = 1; n < Nnode_1d - 1; n++)
4928  {
4929  if (std::fabs(z[n] - s[i]) < tol)
4930  {
4931  index[i] = n;
4932  is_found = true;
4933  break;
4934  }
4935  }
4936  }
4937 
4938  if (!is_found)
4939  {
4940  // No matching nodes
4941  return 0;
4942  }
4943  }
4944  // If we've got here we have a node, so let's return a pointer to it
4945  return this->node_pt(index[0] + Nnode_1d * index[1] +
4946  Nnode_1d * Nnode_1d * index[2]);
4947  }
4948 
4949  //===================================================================
4950  /// If a neighbouring element has already created a node at
4951  /// a position corresponding to the local fractional position within the
4952  /// present element, s_fraction, return
4953  /// a pointer to that node. If not, return NULL (0).
4954  //===================================================================
4955  template<unsigned INITIAL_NNODE_1D>
4957  const Vector<double>& s_fraction, bool& is_periodic)
4958  {
4959  using namespace OcTreeNames;
4960 
4961  // Calculate the faces/edges on which the node lies
4962  Vector<int> faces;
4963  Vector<int> edges;
4964 
4965  if (s_fraction[0] == 0.0)
4966  {
4967  faces.push_back(L);
4968  if (s_fraction[1] == 0.0)
4969  {
4970  edges.push_back(LD);
4971  }
4972  if (s_fraction[2] == 0.0)
4973  {
4974  edges.push_back(LB);
4975  }
4976  if (s_fraction[1] == 1.0)
4977  {
4978  edges.push_back(LU);
4979  }
4980  if (s_fraction[2] == 1.0)
4981  {
4982  edges.push_back(LF);
4983  }
4984  }
4985 
4986  if (s_fraction[0] == 1.0)
4987  {
4988  faces.push_back(R);
4989  if (s_fraction[1] == 0.0)
4990  {
4991  edges.push_back(RD);
4992  }
4993  if (s_fraction[2] == 0.0)
4994  {
4995  edges.push_back(RB);
4996  }
4997  if (s_fraction[1] == 1.0)
4998  {
4999  edges.push_back(RU);
5000  }
5001  if (s_fraction[2] == 1.0)
5002  {
5003  edges.push_back(RF);
5004  }
5005  }
5006 
5007  if (s_fraction[1] == 0.0)
5008  {
5009  faces.push_back(D);
5010  if (s_fraction[2] == 0.0)
5011  {
5012  edges.push_back(DB);
5013  }
5014  if (s_fraction[2] == 1.0)
5015  {
5016  edges.push_back(DF);
5017  }
5018  }
5019 
5020  if (s_fraction[1] == 1.0)
5021  {
5022  faces.push_back(U);
5023  if (s_fraction[2] == 0.0)
5024  {
5025  edges.push_back(UB);
5026  }
5027  if (s_fraction[2] == 1.0)
5028  {
5029  edges.push_back(UF);
5030  }
5031  }
5032 
5033  if (s_fraction[2] == 0.0)
5034  {
5035  faces.push_back(B);
5036  }
5037 
5038  if (s_fraction[2] == 1.0)
5039  {
5040  faces.push_back(F);
5041  }
5042 
5043  // Find the number of faces
5044  unsigned n_face = faces.size();
5045 
5046  // Find the number of edges
5047  unsigned n_edge = edges.size();
5048 
5049  Vector<unsigned> translate_s(3);
5050  Vector<double> s_lo_neigh(3);
5051  Vector<double> s_hi_neigh(3);
5052  Vector<double> s(3);
5053 
5054  int neigh_face, diff_level;
5055  bool in_neighbouring_tree;
5056 
5057  // Loop over the faces on which the node lies
5058  //------------------------------------------
5059  for (unsigned j = 0; j < n_face; j++)
5060  {
5061  // Find pointer to neighbouring element along face
5062  OcTree* neigh_pt;
5063  neigh_pt = octree_pt()->gteq_face_neighbour(faces[j],
5064  translate_s,
5065  s_lo_neigh,
5066  s_hi_neigh,
5067  neigh_face,
5068  diff_level,
5069  in_neighbouring_tree);
5070 
5071  // Neighbour exists
5072  if (neigh_pt != 0)
5073  {
5074  // Have any of its vertex nodes been created yet?
5075  // (Must look in incomplete neighbours because after the
5076  // pre-build they may contain pointers to the required nodes. e.g.
5077  // h-refinement of neighbouring linear and quadratic elements)
5078  bool a_vertex_node_is_built = false;
5079  QElement<3, INITIAL_NNODE_1D>* neigh_obj_pt =
5080  dynamic_cast<QElement<3, INITIAL_NNODE_1D>*>(neigh_pt->object_pt());
5081  if (neigh_obj_pt == 0)
5082  {
5083  throw OomphLibError("Not a quad element!",
5084  OOMPH_CURRENT_FUNCTION,
5085  OOMPH_EXCEPTION_LOCATION);
5086  }
5087  for (unsigned vnode = 0; vnode < neigh_obj_pt->nvertex_node(); vnode++)
5088  {
5089  if (neigh_obj_pt->vertex_node_pt(vnode) != 0)
5090  a_vertex_node_is_built = true;
5091  break;
5092  }
5093  if (a_vertex_node_is_built)
5094  {
5095  // We now need to translate the nodal location, defined in terms
5096  // of the fractional coordinates of the present element into
5097  // those of its neighbour. For this we use the information returned
5098  // to use from the octree function.
5099 
5100  // Calculate the local coordinate in the neighbour
5101  // Note that we need to use the translation scheme in case
5102  // the local coordinates are swapped in the neighbour.
5103  for (unsigned i = 0; i < 3; i++)
5104  {
5105  s[i] = s_lo_neigh[i] +
5106  s_fraction[translate_s[i]] * (s_hi_neigh[i] - s_lo_neigh[i]);
5107  }
5108 
5109  // Find the node in the neighbour
5110  Node* neighbour_node_pt =
5112 
5113  // If there is a node, return it
5114  if (neighbour_node_pt != 0)
5115  {
5116  // Now work out whether it's a periodic boundary
5117  // only possible if we have moved into a neighbouring tree
5118  if (in_neighbouring_tree)
5119  {
5120  // Return whether the neighbour is periodic
5121  is_periodic =
5122  octree_pt()->root_pt()->is_neighbour_periodic(faces[j]);
5123  }
5124 
5125  return neighbour_node_pt;
5126  }
5127  }
5128  }
5129  } // End of loop over faces
5130 
5131 
5132  // Loop over the edges on which the node lies
5133  //------------------------------------------
5134  for (unsigned j = 0; j < n_edge; j++)
5135  {
5136  // Even if we restrict ourselves to true edge neighbours (i.e.
5137  // elements that are not also face neighbours) there may be multiple
5138  // edge neighbours across the edges between multiple root octrees.
5139  // When making the first call to OcTree::gteq_true_edge_neighbour(...)
5140  // we simply return the first one of these multiple edge neighbours
5141  // (if there are any at all, of course) and also return the total number
5142  // of true edge neighbours. If the node in question already exists
5143  // on the first edge neighbour we're done. If it doesn't it may exist
5144  // on other edge neighbours so we repeat the process over all
5145  // other edge neighbours (bailing out if a node is found, of course).
5146 
5147  // Initially return the zero-th true edge neighbour
5148  unsigned i_root_edge_neighbour = 0;
5149 
5150  // Initialise the total number of true edge neighbours
5151  unsigned nroot_edge_neighbour = 0;
5152 
5153  // Keep searching until we've found the node or until we've checked
5154  // all available edge neighbours
5155  bool keep_searching = true;
5156  while (keep_searching)
5157  {
5158  // Find pointer to neighbouring element along edge
5159  OcTree* neigh_pt;
5160  neigh_pt = octree_pt()->gteq_true_edge_neighbour(edges[j],
5161  i_root_edge_neighbour,
5162  nroot_edge_neighbour,
5163  translate_s,
5164  s_lo_neigh,
5165  s_hi_neigh,
5166  neigh_face,
5167  diff_level);
5168 
5169  // Neighbour exists
5170  if (neigh_pt != 0)
5171  {
5172  // Have any of its vertex nodes been created yet?
5173  // (Must look in incomplete neighbours because after the
5174  // pre-build they may contain pointers to the required nodes. e.g.
5175  // h-refinement of neighbouring linear and quadratic elements)
5176  bool a_vertex_node_is_built = false;
5177  QElement<3, INITIAL_NNODE_1D>* neigh_obj_pt =
5178  dynamic_cast<QElement<3, INITIAL_NNODE_1D>*>(neigh_pt->object_pt());
5179  if (neigh_obj_pt == 0)
5180  {
5181  throw OomphLibError("Not a quad element!",
5182  OOMPH_CURRENT_FUNCTION,
5183  OOMPH_EXCEPTION_LOCATION);
5184  }
5185  for (unsigned vnode = 0; vnode < neigh_obj_pt->nvertex_node();
5186  vnode++)
5187  {
5188  if (neigh_obj_pt->vertex_node_pt(vnode) != 0)
5189  a_vertex_node_is_built = true;
5190  break;
5191  }
5192  if (a_vertex_node_is_built)
5193  {
5194  // We now need to translate the nodal location, defined in terms
5195  // of the fractional coordinates of the present element into
5196  // those of its neighbour. For this we use the information returned
5197  // to use from the octree function.
5198 
5199  // Calculate the local coordinate in the neighbour
5200  // Note that we need to use the translation scheme in case
5201  // the local coordinates are swapped in the neighbour.
5202  for (unsigned i = 0; i < 3; i++)
5203  {
5204  s[i] = s_lo_neigh[i] + s_fraction[translate_s[i]] *
5205  (s_hi_neigh[i] - s_lo_neigh[i]);
5206  }
5207 
5208  // Find the node in the neighbour
5209  Node* neighbour_node_pt =
5211 
5212  // If there is a node, return it
5213  if (neighbour_node_pt != 0)
5214  {
5215  // Get the faces on which the edge lies
5216  Vector<int> faces_attached_to_edge =
5217  OcTree::faces_of_common_edge(edges[j]);
5218 
5219  // Get the number of entries in the vector
5220  unsigned n_faces_attached_to_edge = faces_attached_to_edge.size();
5221 
5222  // Loop over the faces
5223  for (unsigned i_face = 0; i_face < n_faces_attached_to_edge;
5224  i_face++)
5225  {
5226  // Is the node periodic in the face direction?
5227  is_periodic = octree_pt()->root_pt()->is_neighbour_periodic(
5228  faces_attached_to_edge[i_face]);
5229 
5230  // Check if the edge is periodic in the i_face-th face direction
5231  if (is_periodic)
5232  {
5233  // We're done!
5234  break;
5235  }
5236  } // for (unsigned
5237  // i_face=0;i_face<n_faces_attached_to_edge;i_face++)
5238 
5239  return neighbour_node_pt;
5240  }
5241  }
5242  }
5243 
5244  // Keep searching, but only if there are further edge neighbours
5245  // Try next root edge neighbour
5246  i_root_edge_neighbour++;
5247 
5248  // Have we exhausted the search
5249  if (i_root_edge_neighbour >= nroot_edge_neighbour)
5250  {
5251  keep_searching = false;
5252  }
5253 
5254  } // End of while keep searching over all true edge neighbours
5255 
5256  } // End of loop over edges
5257 
5258  // Node not found, return null
5259  return 0;
5260  }
5261 
5262  //===================================================================
5263  /// If a neighbouring element's son has already created a node at
5264  /// a position corresponding to the local fractional position within the
5265  /// present element, s_fraction, return
5266  /// a pointer to that node. If not, return NULL (0). If the node is
5267  /// periodic the flag is_periodic will be true
5268  //===================================================================
5269  template<unsigned INITIAL_NNODE_1D>
5272  bool& is_periodic)
5273  {
5274  using namespace OcTreeNames;
5275 
5276  // Calculate the faces/edges on which the node lies
5277  Vector<int> faces;
5278  Vector<int> edges;
5279 
5280  if (s_fraction[0] == 0.0)
5281  {
5282  faces.push_back(L);
5283  if (s_fraction[1] == 0.0)
5284  {
5285  edges.push_back(LD);
5286  }
5287  if (s_fraction[2] == 0.0)
5288  {
5289  edges.push_back(LB);
5290  }
5291  if (s_fraction[1] == 1.0)
5292  {
5293  edges.push_back(LU);
5294  }
5295  if (s_fraction[2] == 1.0)
5296  {
5297  edges.push_back(LF);
5298  }
5299  }
5300 
5301  if (s_fraction[0] == 1.0)
5302  {
5303  faces.push_back(R);
5304  if (s_fraction[1] == 0.0)
5305  {
5306  edges.push_back(RD);
5307  }
5308  if (s_fraction[2] == 0.0)
5309  {
5310  edges.push_back(RB);
5311  }
5312  if (s_fraction[1] == 1.0)
5313  {
5314  edges.push_back(RU);
5315  }
5316  if (s_fraction[2] == 1.0)
5317  {
5318  edges.push_back(RF);
5319  }
5320  }
5321 
5322  if (s_fraction[1] == 0.0)
5323  {
5324  faces.push_back(D);
5325  if (s_fraction[2] == 0.0)
5326  {
5327  edges.push_back(DB);
5328  }
5329  if (s_fraction[2] == 1.0)
5330  {
5331  edges.push_back(DF);
5332  }
5333  }
5334 
5335  if (s_fraction[1] == 1.0)
5336  {
5337  faces.push_back(U);
5338  if (s_fraction[2] == 0.0)
5339  {
5340  edges.push_back(UB);
5341  }
5342  if (s_fraction[2] == 1.0)
5343  {
5344  edges.push_back(UF);
5345  }
5346  }
5347 
5348  if (s_fraction[2] == 0.0)
5349  {
5350  faces.push_back(B);
5351  }
5352 
5353  if (s_fraction[2] == 1.0)
5354  {
5355  faces.push_back(F);
5356  }
5357 
5358  // Find the number of faces
5359  unsigned n_face = faces.size();
5360 
5361  // Find the number of edges
5362  unsigned n_edge = edges.size();
5363 
5364  Vector<unsigned> translate_s(3);
5365  Vector<double> s_lo_neigh(3);
5366  Vector<double> s_hi_neigh(3);
5367  Vector<double> s(3);
5368 
5369  int neigh_face, diff_level;
5370  bool in_neighbouring_tree;
5371 
5372  // Loop over the faces on which the node lies
5373  //------------------------------------------
5374  for (unsigned j = 0; j < n_face; j++)
5375  {
5376  // Find pointer to neighbouring element along face
5377  OcTree* neigh_pt;
5378  neigh_pt = octree_pt()->gteq_face_neighbour(faces[j],
5379  translate_s,
5380  s_lo_neigh,
5381  s_hi_neigh,
5382  neigh_face,
5383  diff_level,
5384  in_neighbouring_tree);
5385 
5386  // Neighbour exists
5387  if (neigh_pt != 0)
5388  {
5389  // Have its nodes been created yet?
5390  // (Must look in sons of unfinished neighbours too!!!)
5391  if (true)
5392  {
5393  // We now need to translate the nodal location, defined in terms
5394  // of the fractional coordinates of the present element into
5395  // those of its neighbour. For this we use the information returned
5396  // to use from the octree function.
5397 
5398  // Calculate the local coordinate in the neighbour
5399  // Note that we need to use the translation scheme in case
5400  // the local coordinates are swapped in the neighbour.
5401  for (unsigned i = 0; i < 3; i++)
5402  {
5403  s[i] = s_lo_neigh[i] +
5404  s_fraction[translate_s[i]] * (s_hi_neigh[i] - s_lo_neigh[i]);
5405  }
5406 
5407  // Check if the element has sons
5408  if (neigh_pt->nsons() != 0)
5409  {
5410  // First, find the son element in which the node should live
5411 
5412  // Find coordinates in the sons
5413  Vector<double> s_in_son(3);
5414  int son = -10;
5415  // On the left
5416  if (s[0] < 0.0)
5417  {
5418  // On the bottom
5419  if (s[1] < 0.0)
5420  {
5421  // On the back
5422  if (s[2] < 0.0)
5423  {
5424  // It's the LDB son
5425  son = OcTreeNames::LDB;
5426  s_in_son[0] = 1.0 + 2.0 * s[0];
5427  s_in_son[1] = 1.0 + 2.0 * s[1];
5428  s_in_son[2] = 1.0 + 2.0 * s[2];
5429  }
5430  // On the front
5431  else
5432  {
5433  // It's the LDF son
5434  son = OcTreeNames::LDF;
5435  s_in_son[0] = 1.0 + 2.0 * s[0];
5436  s_in_son[1] = 1.0 + 2.0 * s[1];
5437  s_in_son[2] = -1.0 + 2.0 * s[2];
5438  }
5439  }
5440  // On the top
5441  else
5442  {
5443  // On the back
5444  if (s[2] < 0.0)
5445  {
5446  // It's the LUB son
5447  son = OcTreeNames::LUB;
5448  s_in_son[0] = 1.0 + 2.0 * s[0];
5449  s_in_son[1] = -1.0 + 2.0 * s[1];
5450  s_in_son[2] = 1.0 + 2.0 * s[2];
5451  }
5452  // On the front
5453  else
5454  {
5455  // It's the LUF son
5456  son = OcTreeNames::LUF;
5457  s_in_son[0] = 1.0 + 2.0 * s[0];
5458  s_in_son[1] = -1.0 + 2.0 * s[1];
5459  s_in_son[2] = -1.0 + 2.0 * s[2];
5460  }
5461  }
5462  }
5463  // On the right
5464  else
5465  {
5466  // On the bottom
5467  if (s[1] < 0.0)
5468  {
5469  // On the back
5470  if (s[2] < 0.0)
5471  {
5472  // It's the RDB son
5473  son = OcTreeNames::RDB;
5474  s_in_son[0] = -1.0 + 2.0 * s[0];
5475  s_in_son[1] = 1.0 + 2.0 * s[1];
5476  s_in_son[2] = 1.0 + 2.0 * s[2];
5477  }
5478  // On the front
5479  else
5480  {
5481  // It's the RDF son
5482  son = OcTreeNames::RDF;
5483  s_in_son[0] = -1.0 + 2.0 * s[0];
5484  s_in_son[1] = 1.0 + 2.0 * s[1];
5485  s_in_son[2] = -1.0 + 2.0 * s[2];
5486  }
5487  }
5488  // On the top
5489  else
5490  {
5491  // On the back
5492  if (s[2] < 0.0)
5493  {
5494  // It's the RUB son
5495  son = OcTreeNames::RUB;
5496  s_in_son[0] = -1.0 + 2.0 * s[0];
5497  s_in_son[1] = -1.0 + 2.0 * s[1];
5498  s_in_son[2] = 1.0 + 2.0 * s[2];
5499  }
5500  // On the front
5501  else
5502  {
5503  // It's the RUF son
5504  son = OcTreeNames::RUF;
5505  s_in_son[0] = -1.0 + 2.0 * s[0];
5506  s_in_son[1] = -1.0 + 2.0 * s[1];
5507  s_in_son[2] = -1.0 + 2.0 * s[2];
5508  }
5509  }
5510  }
5511 
5512  // Find the node in the neighbour's son
5513  Node* neighbour_son_node_pt =
5514  neigh_pt->son_pt(son)->object_pt()->get_node_at_local_coordinate(
5515  s_in_son);
5516 
5517  // If there is a node, return it
5518  if (neighbour_son_node_pt != 0)
5519  {
5520  // Now work out whether it's a periodic boundary
5521  // only possible if we have moved into a neighbouring tree
5522  if (in_neighbouring_tree)
5523  {
5524  // Return whether the neighbour is periodic
5525  is_periodic =
5526  octree_pt()->root_pt()->is_neighbour_periodic(faces[j]);
5527  }
5528 
5529  // Return the pointer to the neighbouring node
5530  return neighbour_son_node_pt;
5531  }
5532  }
5533  }
5534  }
5535  } // End of loop over faces
5536 
5537 
5538  // Loop over the edges on which the node lies
5539  //------------------------------------------
5540  for (unsigned j = 0; j < n_edge; j++)
5541  {
5542  // Even if we restrict ourselves to true edge neighbours (i.e.
5543  // elements that are not also face neighbours) there may be multiple
5544  // edge neighbours across the edges between multiple root octrees.
5545  // When making the first call to OcTree::gteq_true_edge_neighbour(...)
5546  // we simply return the first one of these multiple edge neighbours
5547  // (if there are any at all, of course) and also return the total number
5548  // of true edge neighbours. If the node in question already exists
5549  // on the first edge neighbour we're done. If it doesn't it may exist
5550  // on other edge neighbours so we repeat the process over all
5551  // other edge neighbours (bailing out if a node is found, of course).
5552 
5553  // Initially return the zero-th true edge neighbour
5554  unsigned i_root_edge_neighbour = 0;
5555 
5556  // Initialise the total number of true edge neighbours
5557  unsigned nroot_edge_neighbour = 0;
5558 
5559  // Keep searching until we've found the node or until we've checked
5560  // all available edge neighbours
5561  bool keep_searching = true;
5562  while (keep_searching)
5563  {
5564  // Find pointer to neighbouring element along edge
5565  OcTree* neigh_pt;
5566  neigh_pt = octree_pt()->gteq_true_edge_neighbour(edges[j],
5567  i_root_edge_neighbour,
5568  nroot_edge_neighbour,
5569  translate_s,
5570  s_lo_neigh,
5571  s_hi_neigh,
5572  neigh_face,
5573  diff_level);
5574 
5575  // Neighbour exists
5576  if (neigh_pt != 0)
5577  {
5578  // Have its nodes been created yet?
5579  // (Must look in sons of unfinished neighbours too!!!)
5580  if (true)
5581  {
5582  // We now need to translate the nodal location, defined in terms
5583  // of the fractional coordinates of the present element into
5584  // those of its neighbour. For this we use the information returned
5585  // to use from the octree function.
5586 
5587  // Calculate the local coordinate in the neighbour
5588  // Note that we need to use the translation scheme in case
5589  // the local coordinates are swapped in the neighbour.
5590  for (unsigned i = 0; i < 3; i++)
5591  {
5592  s[i] = s_lo_neigh[i] + s_fraction[translate_s[i]] *
5593  (s_hi_neigh[i] - s_lo_neigh[i]);
5594  }
5595 
5596  // Check if the element has sons
5597  if (neigh_pt->nsons() != 0)
5598  {
5599  // First, find the son element in which the node should live
5600 
5601  // Find coordinates in the sons
5602  Vector<double> s_in_son(3);
5603  int son = -10;
5604  // On the left
5605  if (s[0] < 0.0)
5606  {
5607  // On the bottom
5608  if (s[1] < 0.0)
5609  {
5610  // On the back
5611  if (s[2] < 0.0)
5612  {
5613  // It's the LDB son
5614  son = OcTreeNames::LDB;
5615  s_in_son[0] = 1.0 + 2.0 * s[0];
5616  s_in_son[1] = 1.0 + 2.0 * s[1];
5617  s_in_son[2] = 1.0 + 2.0 * s[2];
5618  }
5619  // On the front
5620  else
5621  {
5622  // It's the LDF son
5623  son = OcTreeNames::LDF;
5624  s_in_son[0] = 1.0 + 2.0 * s[0];
5625  s_in_son[1] = 1.0 + 2.0 * s[1];
5626  s_in_son[2] = -1.0 + 2.0 * s[2];
5627  }
5628  }
5629  // On the top
5630  else
5631  {
5632  // On the back
5633  if (s[2] < 0.0)
5634  {
5635  // It's the LUB son
5636  son = OcTreeNames::LUB;
5637  s_in_son[0] = 1.0 + 2.0 * s[0];
5638  s_in_son[1] = -1.0 + 2.0 * s[1];
5639  s_in_son[2] = 1.0 + 2.0 * s[2];
5640  }
5641  // On the front
5642  else
5643  {
5644  // It's the LUF son
5645  son = OcTreeNames::LUF;
5646  s_in_son[0] = 1.0 + 2.0 * s[0];
5647  s_in_son[1] = -1.0 + 2.0 * s[1];
5648  s_in_son[2] = -1.0 + 2.0 * s[2];
5649  }
5650  }
5651  }
5652  // On the right
5653  else
5654  {
5655  // On the bottom
5656  if (s[1] < 0.0)
5657  {
5658  // On the back
5659  if (s[2] < 0.0)
5660  {
5661  // It's the RDB son
5662  son = OcTreeNames::RDB;
5663  s_in_son[0] = -1.0 + 2.0 * s[0];
5664  s_in_son[1] = 1.0 + 2.0 * s[1];
5665  s_in_son[2] = 1.0 + 2.0 * s[2];
5666  }
5667  // On the front
5668  else
5669  {
5670  // It's the RDF son
5671  son = OcTreeNames::RDF;
5672  s_in_son[0] = -1.0 + 2.0 * s[0];
5673  s_in_son[1] = 1.0 + 2.0 * s[1];
5674  s_in_son[2] = -1.0 + 2.0 * s[2];
5675  }
5676  }
5677  // On the top
5678  else
5679  {
5680  // On the back
5681  if (s[2] < 0.0)
5682  {
5683  // It's the RUB son
5684  son = OcTreeNames::RUB;
5685  s_in_son[0] = -1.0 + 2.0 * s[0];
5686  s_in_son[1] = -1.0 + 2.0 * s[1];
5687  s_in_son[2] = 1.0 + 2.0 * s[2];
5688  }
5689  // On the front
5690  else
5691  {
5692  // It's the RUF son
5693  son = OcTreeNames::RUF;
5694  s_in_son[0] = -1.0 + 2.0 * s[0];
5695  s_in_son[1] = -1.0 + 2.0 * s[1];
5696  s_in_son[2] = -1.0 + 2.0 * s[2];
5697  }
5698  }
5699  }
5700 
5701  // Find the node in the neighbour's son
5702  Node* neighbour_son_node_pt =
5703  neigh_pt->son_pt(son)
5704  ->object_pt()
5705  ->get_node_at_local_coordinate(s_in_son);
5706 
5707  // If there is a node, return it
5708  if (neighbour_son_node_pt != 0)
5709  {
5710  // Get the faces on which the edge lies
5711  Vector<int> faces_attached_to_edge =
5712  OcTree::faces_of_common_edge(edges[j]);
5713 
5714  // Get the number of entries in the vector
5715  unsigned n_faces_attached_to_edge =
5716  faces_attached_to_edge.size();
5717 
5718  // Loop over the faces
5719  for (unsigned i_face = 0; i_face < n_faces_attached_to_edge;
5720  i_face++)
5721  {
5722  // Is the node periodic in the face direction?
5723  is_periodic = octree_pt()->root_pt()->is_neighbour_periodic(
5724  faces_attached_to_edge[i_face]);
5725 
5726  // Check if the edge is periodic in the i_face-th face
5727  // direction
5728  if (is_periodic)
5729  {
5730  // We're done!
5731  break;
5732  }
5733  } // for (unsigned
5734  // i_face=0;i_face<n_faces_attached_to_edge;i_face++)
5735 
5736  // Return the pointer to the neighbouring node
5737  return neighbour_son_node_pt;
5738  }
5739  }
5740  }
5741  }
5742 
5743  // Keep searching, but only if there are further edge neighbours
5744  // Try next root edge neighbour
5745  i_root_edge_neighbour++;
5746 
5747  // Have we exhausted the search
5748  if (i_root_edge_neighbour >= nroot_edge_neighbour)
5749  {
5750  keep_searching = false;
5751  }
5752 
5753  } // End of while keep searching over all true edge neighbours
5754 
5755  } // End of loop over edges
5756 
5757  // Node not found, return null
5758  return 0;
5759  }
5760 
5761  //==================================================================
5762  /// Set the correct p-order of the element based on that of its
5763  /// father. Then construct an integration scheme of the correct order.
5764  /// If an adopted father is specified, information from this is
5765  /// used instead of using the father found from the tree.
5766  //==================================================================
5767  template<unsigned INITIAL_NNODE_1D>
5769  Tree* const& adopted_father_pt, const unsigned& initial_p_order)
5770  {
5771  // Storage for pointer to my father (in octree impersonation)
5772  OcTree* father_pt = 0;
5773 
5774  // Check if an adopted father has been specified
5775  if (adopted_father_pt != 0)
5776  {
5777  // Get pointer to my father (in octree impersonation)
5778  father_pt = dynamic_cast<OcTree*>(adopted_father_pt);
5779  }
5780  // Check if element is in a tree
5781  else if (Tree_pt != 0)
5782  {
5783  // Get pointer to my father (in octree impersonation)
5784  father_pt = dynamic_cast<OcTree*>(octree_pt()->father_pt());
5785  }
5786  else
5787  {
5788  // throw OomphLibError(
5789  // "Element not in a tree, and no adopted father has been
5790  // specified!",
5791  // "PRefineableQElement<2,INITIAL_NNODE_1D>::initial_setup()",
5792  // OOMPH_EXCEPTION_LOCATION);
5793  }
5794 
5795  // Check if element has father
5796  if (father_pt != 0 || initial_p_order != 0)
5797  {
5798  if (father_pt != 0)
5799  {
5802  father_pt->object_pt());
5803  if (father_el_pt != 0)
5804  {
5805  unsigned father_p_order = father_el_pt->p_order();
5806  // Set p-order to that of father
5807  P_order = father_p_order;
5808  }
5809  }
5810  else
5811  {
5812  P_order = initial_p_order;
5813  }
5814 
5815  // Now sort out the element...
5816  // (has p^3 nodes)
5817  unsigned new_n_node = P_order * P_order * P_order;
5818 
5819  // Allocate new space for Nodes (at the element level)
5820  this->set_n_node(new_n_node);
5821 
5822  // Set integration scheme
5823  delete this->integral_pt();
5824  switch (P_order)
5825  {
5826  case 2:
5827  this->set_integration_scheme(new GaussLobattoLegendre<3, 2>);
5828  break;
5829  case 3:
5830  this->set_integration_scheme(new GaussLobattoLegendre<3, 3>);
5831  break;
5832  case 4:
5833  this->set_integration_scheme(new GaussLobattoLegendre<3, 4>);
5834  break;
5835  case 5:
5836  this->set_integration_scheme(new GaussLobattoLegendre<3, 5>);
5837  break;
5838  case 6:
5839  this->set_integration_scheme(new GaussLobattoLegendre<3, 6>);
5840  break;
5841  case 7:
5842  this->set_integration_scheme(new GaussLobattoLegendre<3, 7>);
5843  break;
5844  default:
5845  std::ostringstream error_message;
5846  error_message << "\nERROR: Exceeded maximum polynomial order for";
5847  error_message << "\n integration scheme.\n";
5848  throw OomphLibError(error_message.str(),
5849  OOMPH_CURRENT_FUNCTION,
5850  OOMPH_EXCEPTION_LOCATION);
5851  }
5852  }
5853  }
5854 
5855  //==================================================================
5856  /// Check the father element for any required nodes which
5857  /// already exist
5858  //==================================================================
5859  template<unsigned INITIAL_NNODE_1D>
5861  Mesh*& mesh_pt, Vector<Node*>& new_node_pt)
5862  {
5863  using namespace OcTreeNames;
5864 
5865  // Get the number of 1d nodes
5866  unsigned n_p = nnode_1d();
5867 
5868  // Check whether static father_bound needs to be created
5869  if (Father_bound[n_p].nrow() == 0)
5870  {
5871  setup_father_bounds();
5872  }
5873 
5874  // Pointer to my father (in quadtree impersonation)
5875  OcTree* father_pt = dynamic_cast<OcTree*>(octree_pt()->father_pt());
5876 
5877  // What type of son am I? Ask my quadtree representation...
5878  int son_type = Tree_pt->son_type();
5879 
5880  // Has somebody build me already? (If any nodes have not been built)
5881  if (!nodes_built())
5882  {
5883 #ifdef PARANOID
5884  if (father_pt == 0)
5885  {
5886  std::string error_message =
5887  "Something fishy here: I have no father and yet \n";
5888  error_message += "I have no nodes. Who has created me then?!\n";
5889 
5890  throw OomphLibError(
5891  error_message,
5892  "PRefineableQElement<3,INITIAL_NNODE_1D>::pre_build()",
5893  OOMPH_EXCEPTION_LOCATION);
5894  }
5895 #endif
5896 
5897  // Return pointer to father element
5898  RefineableQElement<3>* father_el_pt =
5899  dynamic_cast<RefineableQElement<3>*>(father_pt->object_pt());
5900 
5901  // Timestepper should be the same for all nodes in father
5902  // element -- use it create timesteppers for new nodes
5903  TimeStepper* time_stepper_pt =
5904  father_el_pt->node_pt(0)->time_stepper_pt();
5905 
5906  // Number of history values (incl. present)
5907  unsigned ntstorage = time_stepper_pt->ntstorage();
5908 
5909  /// / Pass pointer to time object:
5910  // this->time_pt()=father_el_pt->time_pt();
5911 
5912  Vector<double> s_lo(3);
5913  Vector<double> s_hi(3);
5914  Vector<double> s(3);
5915  Vector<double> x(3);
5916 
5917  // Setup vertex coordinates in father element:
5918  //--------------------------------------------
5919  switch (son_type)
5920  {
5921  case LDB:
5922  s_lo[0] = -1.0;
5923  s_hi[0] = 0.0;
5924  s_lo[1] = -1.0;
5925  s_hi[1] = 0.0;
5926  s_lo[2] = -1.0;
5927  s_hi[2] = 0.0;
5928  break;
5929 
5930  case LDF:
5931  s_lo[0] = -1.0;
5932  s_hi[0] = 0.0;
5933  s_lo[1] = -1.0;
5934  s_hi[1] = 0.0;
5935  s_lo[2] = 0.0;
5936  s_hi[2] = 1.0;
5937  break;
5938 
5939  case LUB:
5940  s_lo[0] = -1.0;
5941  s_hi[0] = 0.0;
5942  s_lo[1] = 0.0;
5943  s_hi[1] = 1.0;
5944  s_lo[2] = -1.0;
5945  s_hi[2] = 0.0;
5946  break;
5947 
5948  case LUF:
5949  s_lo[0] = -1.0;
5950  s_hi[0] = 0.0;
5951  s_lo[1] = 0.0;
5952  s_hi[1] = 1.0;
5953  s_lo[2] = 0.0;
5954  s_hi[2] = 1.0;
5955  break;
5956 
5957  case RDB:
5958  s_lo[0] = 0.0;
5959  s_hi[0] = 1.0;
5960  s_lo[1] = -1.0;
5961  s_hi[1] = 0.0;
5962  s_lo[2] = -1.0;
5963  s_hi[2] = 0.0;
5964  break;
5965 
5966  case RDF:
5967  s_lo[0] = 0.0;
5968  s_hi[0] = 1.0;
5969  s_lo[1] = -1.0;
5970  s_hi[1] = 0.0;
5971  s_lo[2] = 0.0;
5972  s_hi[2] = 1.0;
5973  break;
5974 
5975  case RUB:
5976  s_lo[0] = 0.0;
5977  s_hi[0] = 1.0;
5978  s_lo[1] = 0.0;
5979  s_hi[1] = 1.0;
5980  s_lo[2] = -1.0;
5981  s_hi[2] = 0.0;
5982  break;
5983 
5984  case RUF:
5985  s_lo[0] = 0.0;
5986  s_hi[0] = 1.0;
5987  s_lo[1] = 0.0;
5988  s_hi[1] = 1.0;
5989  s_lo[2] = 0.0;
5990  s_hi[2] = 1.0;
5991  break;
5992  }
5993 
5994  /// / Pass macro element pointer on to sons and
5995  /// / set coordinates in macro element
5996  /// / hierher why can I see this?
5997  // if(father_el_pt->macro_elem_pt()!=0)
5998  // {
5999  // set_macro_elem_pt(father_el_pt->macro_elem_pt());
6000  // for(unsigned i=0;i<2;i++)
6001  // {
6002  // s_macro_ll(i)= father_el_pt->s_macro_ll(i)+
6003  // 0.5*(s_lo[i]+1.0)*(father_el_pt->s_macro_ur(i)-
6004  // father_el_pt->s_macro_ll(i));
6005  // s_macro_ur(i)= father_el_pt->s_macro_ll(i)+
6006  // 0.5*(s_hi[i]+1.0)*(father_el_pt->s_macro_ur(i)-
6007  // father_el_pt->s_macro_ll(i));
6008  // }
6009  // }
6010 
6011 
6012  // If the father element hasn't been generated yet, we're stuck...
6013  if (father_el_pt->node_pt(0) == 0)
6014  {
6015  throw OomphLibError(
6016  "Trouble: father_el_pt->node_pt(0)==0\n Can't build son element!\n",
6017  "PRefineableQElement<3,INITIAL_NNODE_1D>::pre_build()",
6018  OOMPH_EXCEPTION_LOCATION);
6019  }
6020  else
6021  {
6022  unsigned jnod = 0;
6023 
6024  Vector<double> s_fraction(3);
6025  // Loop over nodes in element
6026  for (unsigned i0 = 0; i0 < n_p; i0++)
6027  {
6028  // Get the fractional position of the node in the direction of s[0]
6029  s_fraction[0] = this->local_one_d_fraction_of_node(i0, 0);
6030  // Local coordinate in father element
6031  s[0] = s_lo[0] + (s_hi[0] - s_lo[0]) * s_fraction[0];
6032 
6033  for (unsigned i1 = 0; i1 < n_p; i1++)
6034  {
6035  // Get the fractional position of the node in the direction of s[1]
6036  s_fraction[1] = this->local_one_d_fraction_of_node(i1, 1);
6037  // Local coordinate in father element
6038  s[1] = s_lo[1] + (s_hi[1] - s_lo[1]) * s_fraction[1];
6039 
6040  for (unsigned i2 = 0; i2 < n_p; i2++)
6041  {
6042  // Get the fractional position of the node in the direction of
6043  // s[2]
6044  s_fraction[2] = this->local_one_d_fraction_of_node(i2, 2);
6045  // Local coordinate in father element
6046  s[2] = s_lo[2] + (s_hi[2] - s_lo[2]) * s_fraction[2];
6047 
6048  // Local node number
6049  jnod = i0 + n_p * i1 + n_p * n_p * i2;
6050 
6051  // Get the pointer to the node in the father, returns NULL
6052  // if there is not node
6053  Node* created_node_pt =
6054  father_el_pt->get_node_at_local_coordinate(s);
6055 
6056  // Does this node already exist in father element?
6057  //------------------------------------------------
6058  if (created_node_pt != 0)
6059  {
6060  // Copy node across
6061  this->node_pt(jnod) = created_node_pt;
6062 
6063  // Make sure that we update the values at the node so that
6064  // they are consistent with the present representation.
6065  // This is only need for mixed interpolation where the value
6066  // at the father could now become active.
6067 
6068  // Loop over all history values
6069  for (unsigned t = 0; t < ntstorage; t++)
6070  {
6071  // Get values from father element
6072  // Note: get_interpolated_values() sets Vector size itself.
6073  Vector<double> prev_values;
6074  father_el_pt->get_interpolated_values(t, s, prev_values);
6075  // Find the minimum number of values
6076  //(either those stored at the node, or those returned by
6077  // the function)
6078  unsigned n_val_at_node = created_node_pt->nvalue();
6079  unsigned n_val_from_function = prev_values.size();
6080  // Use the ternary conditional operator here
6081  unsigned n_var = n_val_at_node < n_val_from_function ?
6082  n_val_at_node :
6083  n_val_from_function;
6084  // Assign the values that we can
6085  for (unsigned k = 0; k < n_var; k++)
6086  {
6087  created_node_pt->set_value(t, k, prev_values[k]);
6088  }
6089  }
6090  }
6091  } // End of loop i2
6092  } // End of loop i1
6093  } // End of loop i0
6094  } // Sanity check: Father element has been generated
6095 
6096  } // End of nodes not built
6097  }
6098 
6099  //==================================================================
6100  /// p-refine the element inc times. (If inc<0 then p-unrefinement
6101  /// is performed.)
6102  //==================================================================
6103  template<unsigned INITIAL_NNODE_1D>
6105  const int& inc, Mesh* const& mesh_pt, GeneralisedElement* const& clone_pt)
6106  {
6107  // Number of dimensions
6108  unsigned n_dim = 3;
6109 
6110  // Cast clone to correct type
6112  dynamic_cast<PRefineableQElement<3, INITIAL_NNODE_1D>*>(clone_pt);
6113 
6114  // Check if we can use it
6115  if (clone_el_pt == 0)
6116  {
6117  throw OomphLibError(
6118  "Cloned copy must be a PRefineableQElement<3,INITIAL_NNODE_1D>!",
6119  OOMPH_CURRENT_FUNCTION,
6120  OOMPH_EXCEPTION_LOCATION);
6121  }
6122 #ifdef PARANOID
6123  // Clone exists, so check that it is infact a copy of me
6124  else
6125  {
6126  // Flag to keep track of check
6127  bool clone_is_ok = true;
6128 
6129  // Does the clone have the correct p-order?
6130  clone_is_ok = clone_is_ok && (clone_el_pt->p_order() == this->p_order());
6131 
6132  if (!clone_is_ok)
6133  {
6134  std::ostringstream err_stream;
6135  err_stream << "Clone element has a different p-order from me,"
6136  << std::endl
6137  << "but it is supposed to be a copy!" << std::endl;
6138 
6139  throw OomphLibError(
6140  err_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
6141  }
6142 
6143  // Does the clone have the same number of nodes as me?
6144  clone_is_ok = clone_is_ok && (clone_el_pt->nnode() == this->nnode());
6145 
6146  if (!clone_is_ok)
6147  {
6148  std::ostringstream err_stream;
6149  err_stream << "Clone element has a different number of nodes from me,"
6150  << std::endl
6151  << "but it is supposed to be a copy!" << std::endl;
6152 
6153  throw OomphLibError(
6154  err_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
6155  }
6156 
6157  // Does the clone have the same nodes as me?
6158  for (unsigned n = 0; n < this->nnode(); n++)
6159  {
6160  clone_is_ok =
6161  clone_is_ok && (clone_el_pt->node_pt(n) == this->node_pt(n));
6162  }
6163 
6164  if (!clone_is_ok)
6165  {
6166  std::ostringstream err_stream;
6167  err_stream << "The nodes belonging to the clone element are different"
6168  << std::endl
6169  << "from mine, but it is supposed to be a copy!"
6170  << std::endl;
6171 
6172  throw OomphLibError(
6173  err_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
6174  }
6175 
6176  // If we get to here then the clone has all the information we require
6177  }
6178 #endif
6179 
6180  // Currently we can't handle the case of generalised coordinates
6181  // since we haven't established how they should be interpolated.
6182  // Buffer this case:
6183  if (clone_el_pt->node_pt(0)->nposition_type() != 1)
6184  {
6185  throw OomphLibError("Can't handle generalised nodal positions (yet).",
6186  OOMPH_CURRENT_FUNCTION,
6187  OOMPH_EXCEPTION_LOCATION);
6188  }
6189 
6190  // Timestepper should be the same for all nodes -- use it
6191  // to create timesteppers for new nodes
6192  TimeStepper* time_stepper_pt = this->node_pt(0)->time_stepper_pt();
6193 
6194  // Get number of history values (incl. present)
6195  unsigned ntstorage = time_stepper_pt->ntstorage();
6196 
6197  // Increment p-order of the element
6198  this->P_order += inc;
6199 
6200  // Change integration scheme
6201  delete this->integral_pt();
6202  switch (this->P_order)
6203  {
6204  case 2:
6205  this->set_integration_scheme(new GaussLobattoLegendre<3, 2>);
6206  break;
6207  case 3:
6208  this->set_integration_scheme(new GaussLobattoLegendre<3, 3>);
6209  break;
6210  case 4:
6211  this->set_integration_scheme(new GaussLobattoLegendre<3, 4>);
6212  break;
6213  case 5:
6214  this->set_integration_scheme(new GaussLobattoLegendre<3, 5>);
6215  break;
6216  case 6:
6217  this->set_integration_scheme(new GaussLobattoLegendre<3, 6>);
6218  break;
6219  case 7:
6220  this->set_integration_scheme(new GaussLobattoLegendre<3, 7>);
6221  break;
6222  default:
6223  std::ostringstream error_message;
6224  error_message << "\nERROR: Exceeded maximum polynomial order for";
6225  error_message << "\n integration scheme.\n";
6226  throw OomphLibError(error_message.str(),
6227  OOMPH_CURRENT_FUNCTION,
6228  OOMPH_EXCEPTION_LOCATION);
6229  }
6230 
6231  // Allocate new space for Nodes (at the element level)
6232  this->set_n_node(this->P_order * this->P_order * this->P_order);
6233 
6234  // Copy vertex nodes and create new edge and internal nodes
6235  //---------------------------------------------------------
6236 
6237  // Setup vertex coordinates in element:
6238  //-------------------------------------
6239  Vector<double> s_lo(n_dim, 0.0);
6240  Vector<double> s_hi(n_dim, 0.0);
6241  s_lo[0] = -1.0;
6242  s_hi[0] = 1.0;
6243  s_lo[1] = -1.0;
6244  s_hi[1] = 1.0;
6245  s_lo[2] = -1.0;
6246  s_hi[2] = 1.0;
6247 
6248  // Local coordinate in element
6249  Vector<double> s(n_dim, 0.0);
6250 
6251  unsigned jnod = 0;
6252 
6253  Vector<double> s_fraction(n_dim, 0.0);
6254  // Loop over nodes in element
6255  for (unsigned i0 = 0; i0 < this->P_order; i0++)
6256  {
6257  // Get the fractional position of the node in the direction of s[0]
6258  s_fraction[0] = this->local_one_d_fraction_of_node(i0, 0);
6259  // Local coordinate
6260  s[0] = s_lo[0] + (s_hi[0] - s_lo[0]) * s_fraction[0];
6261 
6262  for (unsigned i1 = 0; i1 < this->P_order; i1++)
6263  {
6264  // Get the fractional position of the node in the direction of s[1]
6265  s_fraction[1] = this->local_one_d_fraction_of_node(i1, 1);
6266  // Local coordinate
6267  s[1] = s_lo[1] + (s_hi[1] - s_lo[1]) * s_fraction[1];
6268 
6269  for (unsigned i2 = 0; i2 < this->P_order; i2++)
6270  {
6271  // Get the fractional position of the node in the direction of s[2]
6272  s_fraction[2] = this->local_one_d_fraction_of_node(i2, 2);
6273  // Local coordinate
6274  s[2] = s_lo[2] + (s_hi[2] - s_lo[2]) * s_fraction[2];
6275 
6276  // Local node number
6277  jnod = i0 + this->P_order * i1 + this->P_order * this->P_order * i2;
6278 
6279  // Initialise flag: So far, this node hasn't been built
6280  // or copied yet
6281  bool node_done = false;
6282 
6283  // Get the pointer to the node in this element (or rather, its clone),
6284  // returns NULL if there is not node
6285  Node* created_node_pt = clone_el_pt->get_node_at_local_coordinate(s);
6286  // created_node_pt = 0;
6287 
6288  // Does this node already exist in this element?
6289  //----------------------------------------------
6290  if (created_node_pt != 0)
6291  {
6292  // Copy node across
6293  this->node_pt(jnod) = created_node_pt;
6294 
6295  // Make sure that we update the values at the node so that
6296  // they are consistent with the present representation.
6297  // This is only need for mixed interpolation where the value
6298  // at the father could now become active.
6299 
6300  // Loop over all history values
6301  for (unsigned t = 0; t < ntstorage; t++)
6302  {
6303  // Get values from father element
6304  // Note: get_interpolated_values() sets Vector size itself.
6305  Vector<double> prev_values;
6306  clone_el_pt->get_interpolated_values(t, s, prev_values);
6307  // Find the minimum number of values
6308  //(either those stored at the node, or those returned by
6309  // the function)
6310  unsigned n_val_at_node = created_node_pt->nvalue();
6311  unsigned n_val_from_function = prev_values.size();
6312  // Use the ternary conditional operator here
6313  unsigned n_var = n_val_at_node < n_val_from_function ?
6314  n_val_at_node :
6315  n_val_from_function;
6316  // Assign the values that we can
6317  for (unsigned k = 0; k < n_var; k++)
6318  {
6319  created_node_pt->set_value(t, k, prev_values[k]);
6320  }
6321  }
6322 
6323  // Node has been created by copy
6324  node_done = true;
6325  }
6326  // Node does not exist in this element but might already
6327  //------------------------------------------------------
6328  // have been created by neighbouring elements
6329  //-------------------------------------------
6330  else
6331  {
6332  // Was the node created by one of its neighbours
6333  // Whether or not the node lies on an edge can be calculated
6334  // by from the fractional position
6335  bool is_periodic = false;
6336  created_node_pt =
6337  this->node_created_by_neighbour(s_fraction, is_periodic);
6338 
6339  // If the node was so created, assign the pointers
6340  if (created_node_pt != 0)
6341  {
6342  // If the node is periodic
6343  if (is_periodic)
6344  {
6345  // Now the node must be on a boundary, but we don't know which
6346  // one
6347  // The returned created_node_pt is actually the neighbouring
6348  // periodic node
6349  Node* neighbour_node_pt = created_node_pt;
6350 
6351  // Determine the edge on which the new node will live
6352  //(cannot be a vertex node)
6353  int my_bound = Tree::OMEGA;
6354  // If we are on the left face
6355  if (i0 == 0)
6356  {
6357  my_bound = OcTreeNames::L;
6358  }
6359  // If we are on the right face
6360  else if (i0 == this->P_order - 1)
6361  {
6362  my_bound = OcTreeNames::R;
6363  }
6364 
6365  // If we are on the bottom face
6366  if (i1 == 0)
6367  {
6368  // If we already have already set the boundary, we're on an
6369  // edge
6370  switch (my_bound)
6371  {
6372  case OcTreeNames::L:
6373  my_bound = OcTreeNames::LD;
6374  break;
6375  case OcTreeNames::R:
6376  my_bound = OcTreeNames::RD;
6377  break;
6378  // Boundary not set
6379  default:
6380  my_bound = OcTreeNames::D;
6381  break;
6382  }
6383  }
6384  // If we are the top face
6385  else if (i1 == this->P_order - 1)
6386  {
6387  // If we already have a boundary
6388  switch (my_bound)
6389  {
6390  case OcTreeNames::L:
6391  my_bound = OcTreeNames::LU;
6392  break;
6393  case OcTreeNames::R:
6394  my_bound = OcTreeNames::RU;
6395  break;
6396  default:
6397  my_bound = OcTreeNames::U;
6398  break;
6399  }
6400  }
6401 
6402  // If we are on the back face
6403  if (i2 == 0)
6404  {
6405  // If we already have already set the boundary, we're on an
6406  // edge
6407  switch (my_bound)
6408  {
6409  case OcTreeNames::L:
6410  my_bound = OcTreeNames::LB;
6411  break;
6412  case OcTreeNames::LD:
6413  my_bound = OcTreeNames::LDB;
6414  break;
6415  case OcTreeNames::LU:
6416  my_bound = OcTreeNames::LUB;
6417  break;
6418  case OcTreeNames::R:
6419  my_bound = OcTreeNames::RB;
6420  break;
6421  case OcTreeNames::RD:
6422  my_bound = OcTreeNames::RDB;
6423  break;
6424  case OcTreeNames::RU:
6425  my_bound = OcTreeNames::RUB;
6426  break;
6427  case OcTreeNames::D:
6428  my_bound = OcTreeNames::DB;
6429  break;
6430  case OcTreeNames::U:
6431  my_bound = OcTreeNames::UB;
6432  break;
6433  // Boundary not set
6434  default:
6435  my_bound = OcTreeNames::B;
6436  break;
6437  }
6438  }
6439  // If we are the front face
6440  else if (i2 == this->P_order - 1)
6441  {
6442  // If we already have a boundary
6443  switch (my_bound)
6444  {
6445  case OcTreeNames::L:
6446  my_bound = OcTreeNames::LF;
6447  break;
6448  case OcTreeNames::LD:
6449  my_bound = OcTreeNames::LDF;
6450  break;
6451  case OcTreeNames::LU:
6452  my_bound = OcTreeNames::LUF;
6453  break;
6454  case OcTreeNames::R:
6455  my_bound = OcTreeNames::RF;
6456  break;
6457  case OcTreeNames::RD:
6458  my_bound = OcTreeNames::RDF;
6459  break;
6460  case OcTreeNames::RU:
6461  my_bound = OcTreeNames::RUF;
6462  break;
6463  case OcTreeNames::D:
6464  my_bound = OcTreeNames::DF;
6465  break;
6466  case OcTreeNames::U:
6467  my_bound = OcTreeNames::UF;
6468  break;
6469  default:
6470  my_bound = OcTreeNames::F;
6471  break;
6472  }
6473  }
6474 
6475  // Storage for the set of Mesh boundaries on which the
6476  // appropriate edge lives.
6477  // [New nodes should always be mid-edge nodes and therefore
6478  // only live on one boundary but just to play it safe...]
6479  std::set<unsigned> boundaries;
6480  // Only get the boundaries if we are at the edge of
6481  // an element. Nodes in the centre of an element cannot be
6482  // on Mesh boundaries
6483  if (my_bound != Tree::OMEGA)
6484  {
6485  clone_el_pt->get_boundaries(my_bound, boundaries);
6486  }
6487 
6488 #ifdef PARANOID
6489  // Case where a new node lives on more than one boundary
6490  // seems fishy enough to flag
6491  if (boundaries.size() > 2)
6492  {
6493  throw OomphLibError(
6494  "boundaries.size()>2 seems a bit strange..\n",
6495  OOMPH_CURRENT_FUNCTION,
6496  OOMPH_EXCEPTION_LOCATION);
6497  }
6498 
6499  // Case when there are no boundaries, we are in big trouble
6500  if (boundaries.size() == 0)
6501  {
6502  std::ostringstream error_stream;
6503  error_stream << "Periodic node is not on a boundary...\n"
6504  << "Coordinates: " << created_node_pt->x(0)
6505  << " " << created_node_pt->x(1) << "\n";
6506  throw OomphLibError(error_stream.str(),
6507  OOMPH_CURRENT_FUNCTION,
6508  OOMPH_EXCEPTION_LOCATION);
6509  }
6510 #endif
6511 
6512  // Create node and set the pointer to it from the element
6513  created_node_pt =
6514  this->construct_boundary_node(jnod, time_stepper_pt);
6515  // Make the node periodic from the neighbour
6516  created_node_pt->make_periodic(neighbour_node_pt);
6517 
6518  // Loop over # of history values
6519  for (unsigned t = 0; t < ntstorage; t++)
6520  {
6521  // Get position from father element -- this uses the macro
6522  // element representation if appropriate. If the node
6523  // turns out to be a hanging node later on, then
6524  // its position gets adjusted in line with its
6525  // hanging node interpolation.
6526  Vector<double> x_prev(n_dim, 0.0);
6527  clone_el_pt->get_x(t, s, x_prev);
6528  // Set previous positions of the new node
6529  for (unsigned i = 0; i < n_dim; i++)
6530  {
6531  created_node_pt->x(t, i) = x_prev[i];
6532  }
6533  }
6534 
6535  // Check if we need to add nodes to the mesh
6536  if (mesh_pt != 0)
6537  {
6538  // Next, we Update the boundary lookup schemes
6539  // Loop over the boundaries stored in the set
6540  for (std::set<unsigned>::iterator it = boundaries.begin();
6541  it != boundaries.end();
6542  ++it)
6543  {
6544  // Add the node to the boundary
6545  mesh_pt->add_boundary_node(*it, created_node_pt);
6546 
6547  // If we have set an intrinsic coordinate on this
6548  // mesh boundary then it must also be interpolated on
6549  // the new node
6550  // Now interpolate the intrinsic boundary coordinate
6551  if (mesh_pt->boundary_coordinate_exists(*it) == true)
6552  {
6553  Vector<double> zeta(2, 0.0);
6554  clone_el_pt->interpolated_zeta_on_face(
6555  *it, my_bound, s, zeta);
6556 
6557  created_node_pt->set_coordinates_on_boundary(*it, zeta);
6558  }
6559  }
6560 
6561  // Make sure that we add the node to the mesh
6562  mesh_pt->add_node_pt(created_node_pt);
6563  }
6564  } // End of periodic case
6565  // Otherwise the node is not periodic, so just set the
6566  // pointer to the neighbours node
6567  else
6568  {
6569  this->node_pt(jnod) = created_node_pt;
6570  }
6571  // Node has been created
6572  node_done = true;
6573  }
6574  // Node does not exist in neighbour element but might already
6575  //-----------------------------------------------------------
6576  // have been created by a son of a neighbouring element
6577  //-----------------------------------------------------
6578  else
6579  {
6580  // Was the node created by one of its neighbours' sons
6581  // Whether or not the node lies on an edge can be calculated
6582  // by from the fractional position
6583  bool is_periodic = false;
6584  created_node_pt =
6585  this->node_created_by_son_of_neighbour(s_fraction, is_periodic);
6586 
6587  // If the node was so created, assign the pointers
6588  if (created_node_pt != 0)
6589  {
6590  // If the node is periodic
6591  if (is_periodic)
6592  {
6593  // Now the node must be on a boundary, but we don't know which
6594  // one
6595  // The returned created_node_pt is actually the neighbouring
6596  // periodic node
6597  Node* neighbour_node_pt = created_node_pt;
6598 
6599  // Determine the edge on which the new node will live
6600  //(cannot be a vertex node)
6601  int my_bound = Tree::OMEGA;
6602  // If we are on the left face
6603  if (i0 == 0)
6604  {
6605  my_bound = OcTreeNames::L;
6606  }
6607  // If we are on the right face
6608  else if (i0 == this->P_order - 1)
6609  {
6610  my_bound = OcTreeNames::R;
6611  }
6612 
6613  // If we are on the bottom face
6614  if (i1 == 0)
6615  {
6616  // If we already have already set the boundary, we're on an
6617  // edge
6618  switch (my_bound)
6619  {
6620  case OcTreeNames::L:
6621  my_bound = OcTreeNames::LD;
6622  break;
6623  case OcTreeNames::R:
6624  my_bound = OcTreeNames::RD;
6625  break;
6626  // Boundary not set
6627  default:
6628  my_bound = OcTreeNames::D;
6629  break;
6630  }
6631  }
6632  // If we are the top face
6633  else if (i1 == this->P_order - 1)
6634  {
6635  // If we already have a boundary
6636  switch (my_bound)
6637  {
6638  case OcTreeNames::L:
6639  my_bound = OcTreeNames::LU;
6640  break;
6641  case OcTreeNames::R:
6642  my_bound = OcTreeNames::RU;
6643  break;
6644  default:
6645  my_bound = OcTreeNames::U;
6646  break;
6647  }
6648  }
6649 
6650  // If we are on the back face
6651  if (i2 == 0)
6652  {
6653  // If we already have already set the boundary, we're on an
6654  // edge
6655  switch (my_bound)
6656  {
6657  case OcTreeNames::L:
6658  my_bound = OcTreeNames::LB;
6659  break;
6660  case OcTreeNames::LD:
6661  my_bound = OcTreeNames::LDB;
6662  break;
6663  case OcTreeNames::LU:
6664  my_bound = OcTreeNames::LUB;
6665  break;
6666  case OcTreeNames::R:
6667  my_bound = OcTreeNames::RB;
6668  break;
6669  case OcTreeNames::RD:
6670  my_bound = OcTreeNames::RDB;
6671  break;
6672  case OcTreeNames::RU:
6673  my_bound = OcTreeNames::RUB;
6674  break;
6675  case OcTreeNames::D:
6676  my_bound = OcTreeNames::DB;
6677  break;
6678  case OcTreeNames::U:
6679  my_bound = OcTreeNames::UB;
6680  break;
6681  // Boundary not set
6682  default:
6683  my_bound = OcTreeNames::B;
6684  break;
6685  }
6686  }
6687  // If we are the front face
6688  else if (i2 == this->P_order - 1)
6689  {
6690  // If we already have a boundary
6691  switch (my_bound)
6692  {
6693  case OcTreeNames::L:
6694  my_bound = OcTreeNames::LF;
6695  break;
6696  case OcTreeNames::LD:
6697  my_bound = OcTreeNames::LDF;
6698  break;
6699  case OcTreeNames::LU:
6700  my_bound = OcTreeNames::LUF;
6701  break;
6702  case OcTreeNames::R:
6703  my_bound = OcTreeNames::RF;
6704  break;
6705  case OcTreeNames::RD:
6706  my_bound = OcTreeNames::RDF;
6707  break;
6708  case OcTreeNames::RU:
6709  my_bound = OcTreeNames::RUF;
6710  break;
6711  case OcTreeNames::D:
6712  my_bound = OcTreeNames::DF;
6713  break;
6714  case OcTreeNames::U:
6715  my_bound = OcTreeNames::UF;
6716  break;
6717  default:
6718  my_bound = OcTreeNames::F;
6719  break;
6720  }
6721  }
6722 
6723  // Storage for the set of Mesh boundaries on which the
6724  // appropriate edge lives.
6725  // [New nodes should always be mid-edge nodes and therefore
6726  // only live on one boundary but just to play it safe...]
6727  std::set<unsigned> boundaries;
6728  // Only get the boundaries if we are at the edge of
6729  // an element. Nodes in the centre of an element cannot be
6730  // on Mesh boundaries
6731  if (my_bound != Tree::OMEGA)
6732  {
6733  clone_el_pt->get_boundaries(my_bound, boundaries);
6734  }
6735 
6736 #ifdef PARANOID
6737  // Case where a new node lives on more than one boundary
6738  // seems fishy enough to flag
6739  if (boundaries.size() > 2)
6740  {
6741  throw OomphLibError(
6742  "boundaries.size()>2 seems a bit strange..\n",
6743  OOMPH_CURRENT_FUNCTION,
6744  OOMPH_EXCEPTION_LOCATION);
6745  }
6746 
6747  // Case when there are no boundaries, we are in big trouble
6748  if (boundaries.size() == 0)
6749  {
6750  std::ostringstream error_stream;
6751  error_stream << "Periodic node is not on a boundary...\n"
6752  << "Coordinates: " << created_node_pt->x(0)
6753  << " " << created_node_pt->x(1) << "\n";
6754  throw OomphLibError(error_stream.str(),
6755  OOMPH_CURRENT_FUNCTION,
6756  OOMPH_EXCEPTION_LOCATION);
6757  }
6758 #endif
6759 
6760  // Create node and set the pointer to it from the element
6761  created_node_pt =
6762  this->construct_boundary_node(jnod, time_stepper_pt);
6763  // Make the node periodic from the neighbour
6764  created_node_pt->make_periodic(neighbour_node_pt);
6765 
6766  // Loop over # of history values
6767  for (unsigned t = 0; t < ntstorage; t++)
6768  {
6769  // Get position from father element -- this uses the macro
6770  // element representation if appropriate. If the node
6771  // turns out to be a hanging node later on, then
6772  // its position gets adjusted in line with its
6773  // hanging node interpolation.
6774  Vector<double> x_prev(n_dim);
6775  clone_el_pt->get_x(t, s, x_prev);
6776  // Set previous positions of the new node
6777  for (unsigned i = 0; i < n_dim; i++)
6778  {
6779  created_node_pt->x(t, i) = x_prev[i];
6780  }
6781  }
6782 
6783  // Check if we need to add nodes to the mesh
6784  if (mesh_pt != 0)
6785  {
6786  // Next, we Update the boundary lookup schemes
6787  // Loop over the boundaries stored in the set
6788  for (std::set<unsigned>::iterator it = boundaries.begin();
6789  it != boundaries.end();
6790  ++it)
6791  {
6792  // Add the node to the boundary
6793  mesh_pt->add_boundary_node(*it, created_node_pt);
6794 
6795  // If we have set an intrinsic coordinate on this
6796  // mesh boundary then it must also be interpolated on
6797  // the new node
6798  // Now interpolate the intrinsic boundary coordinate
6799  if (mesh_pt->boundary_coordinate_exists(*it) == true)
6800  {
6801  Vector<double> zeta(2, 0.0);
6802  clone_el_pt->interpolated_zeta_on_face(
6803  *it, my_bound, s, zeta);
6804 
6805  created_node_pt->set_coordinates_on_boundary(*it, zeta);
6806  }
6807  }
6808 
6809  // Make sure that we add the node to the mesh
6810  mesh_pt->add_node_pt(created_node_pt);
6811  }
6812  } // End of periodic case
6813  // Otherwise the node is not periodic, so just set the
6814  // pointer to the neighbours node
6815  else
6816  {
6817  this->node_pt(jnod) = created_node_pt;
6818  }
6819  // Node has been created
6820  node_done = true;
6821  } // Node does not exist in son of neighbouring element
6822  } // Node does not exist in neighbouring element
6823  } // Node does not exist in this element
6824 
6825  // Node has not been built anywhere ---> build it here
6826  if (!node_done)
6827  {
6828  // Firstly, we need to determine whether or not a node lies
6829  // on the boundary before building it, because
6830  // we actually assign a different type of node on boundaries.
6831 
6832  // Initially none
6833  int my_bound = Tree::OMEGA;
6834  // If we are on the left face
6835  if (i0 == 0)
6836  {
6837  my_bound = OcTreeNames::L;
6838  }
6839  // If we are on the right face
6840  else if (i0 == this->P_order - 1)
6841  {
6842  my_bound = OcTreeNames::R;
6843  }
6844 
6845  // If we are on the bottom face
6846  if (i1 == 0)
6847  {
6848  // If we already have already set the boundary, we're on an edge
6849  switch (my_bound)
6850  {
6851  case OcTreeNames::L:
6852  my_bound = OcTreeNames::LD;
6853  break;
6854  case OcTreeNames::R:
6855  my_bound = OcTreeNames::RD;
6856  break;
6857  // Boundary not set
6858  default:
6859  my_bound = OcTreeNames::D;
6860  break;
6861  }
6862  }
6863  // If we are the top face
6864  else if (i1 == this->P_order - 1)
6865  {
6866  // If we already have a boundary
6867  switch (my_bound)
6868  {
6869  case OcTreeNames::L:
6870  my_bound = OcTreeNames::LU;
6871  break;
6872  case OcTreeNames::R:
6873  my_bound = OcTreeNames::RU;
6874  break;
6875  default:
6876  my_bound = OcTreeNames::U;
6877  break;
6878  }
6879  }
6880 
6881  // If we are on the back face
6882  if (i2 == 0)
6883  {
6884  // If we already have already set the boundary, we're on an edge
6885  switch (my_bound)
6886  {
6887  case OcTreeNames::L:
6888  my_bound = OcTreeNames::LB;
6889  break;
6890  case OcTreeNames::LD:
6891  my_bound = OcTreeNames::LDB;
6892  break;
6893  case OcTreeNames::LU:
6894  my_bound = OcTreeNames::LUB;
6895  break;
6896  case OcTreeNames::R:
6897  my_bound = OcTreeNames::RB;
6898  break;
6899  case OcTreeNames::RD:
6900  my_bound = OcTreeNames::RDB;
6901  break;
6902  case OcTreeNames::RU:
6903  my_bound = OcTreeNames::RUB;
6904  break;
6905  case OcTreeNames::D:
6906  my_bound = OcTreeNames::DB;
6907  break;
6908  case OcTreeNames::U:
6909  my_bound = OcTreeNames::UB;
6910  break;
6911  // Boundary not set
6912  default:
6913  my_bound = OcTreeNames::B;
6914  break;
6915  }
6916  }
6917  // If we are the front face
6918  else if (i2 == this->P_order - 1)
6919  {
6920  // If we already have a boundary
6921  switch (my_bound)
6922  {
6923  case OcTreeNames::L:
6924  my_bound = OcTreeNames::LF;
6925  break;
6926  case OcTreeNames::LD:
6927  my_bound = OcTreeNames::LDF;
6928  break;
6929  case OcTreeNames::LU:
6930  my_bound = OcTreeNames::LUF;
6931  break;
6932  case OcTreeNames::R:
6933  my_bound = OcTreeNames::RF;
6934  break;
6935  case OcTreeNames::RD:
6936  my_bound = OcTreeNames::RDF;
6937  break;
6938  case OcTreeNames::RU:
6939  my_bound = OcTreeNames::RUF;
6940  break;
6941  case OcTreeNames::D:
6942  my_bound = OcTreeNames::DF;
6943  break;
6944  case OcTreeNames::U:
6945  my_bound = OcTreeNames::UF;
6946  break;
6947  default:
6948  my_bound = OcTreeNames::F;
6949  break;
6950  }
6951  }
6952 
6953  // Storage for the set of Mesh boundaries on which the
6954  // appropriate edge lives.
6955  // [New nodes should always be mid-edge nodes and therefore
6956  // only live on one boundary but just to play it safe...]
6957  std::set<unsigned> boundaries;
6958  // Only get the boundaries if we are at the edge of
6959  // an element. Nodes in the centre of an element cannot be
6960  // on Mesh boundaries
6961  if (my_bound != Tree::OMEGA)
6962  clone_el_pt->get_boundaries(my_bound, boundaries);
6963 
6964 #ifdef PARANOID
6965  // Case where a new node lives on more than two boundaries
6966  // seems fishy enough to flag
6967  if (boundaries.size() > 2)
6968  {
6969  throw OomphLibError(
6970  "boundaries.size()>2 seems a bit strange..\n",
6971  "PRefineableQElement<3,INITIAL_NNODE_1D>::p_refine()",
6972  OOMPH_EXCEPTION_LOCATION);
6973  }
6974 #endif
6975 
6976  // If the node lives on a mesh boundary,
6977  // then we need to create a boundary node
6978  if (boundaries.size() > 0)
6979  {
6980  // Create node and set the pointer to it from the element
6981  created_node_pt =
6982  this->construct_boundary_node(jnod, time_stepper_pt);
6983 
6984  // Now we need to work out whether to pin the values at
6985  // the new node based on the boundary conditions applied at
6986  // its Mesh boundary
6987 
6988  // Get the boundary conditions from the father
6989  Vector<int> bound_cons(this->ncont_interpolated_values());
6990  clone_el_pt->get_bcs(my_bound, bound_cons);
6991 
6992  // Loop over the values and pin, if necessary
6993  unsigned n_value = created_node_pt->nvalue();
6994  for (unsigned k = 0; k < n_value; k++)
6995  {
6996  if (bound_cons[k])
6997  {
6998  created_node_pt->pin(k);
6999  }
7000  }
7001 
7002  // Solid node? If so, deal with the positional boundary
7003  // conditions:
7004  SolidNode* solid_node_pt =
7005  dynamic_cast<SolidNode*>(created_node_pt);
7006  if (solid_node_pt != 0)
7007  {
7008  // Get the positional boundary conditions from the father:
7009  unsigned n_dim = created_node_pt->ndim();
7010  Vector<int> solid_bound_cons(n_dim);
7011  RefineableSolidQElement<3>* clone_solid_el_pt =
7012  dynamic_cast<RefineableSolidQElement<3>*>(clone_el_pt);
7013 #ifdef PARANOID
7014  if (clone_solid_el_pt == 0)
7015  {
7016  std::string error_message =
7017  "We have a SolidNode outside a refineable SolidElement\n";
7018  error_message +=
7019  "during mesh refinement -- this doesn't make sense";
7020 
7021  throw OomphLibError(
7022  error_message,
7023  "PRefineableQElement<3,INITIAL_NNODE_1D>::p_refine()",
7024  OOMPH_EXCEPTION_LOCATION);
7025  }
7026 #endif
7027  clone_solid_el_pt->get_solid_bcs(my_bound, solid_bound_cons);
7028 
7029  // Loop over the positions and pin, if necessary
7030  for (unsigned k = 0; k < n_dim; k++)
7031  {
7032  if (solid_bound_cons[k])
7033  {
7034  solid_node_pt->pin_position(k);
7035  }
7036  }
7037  } // End of if solid_node_pt
7038 
7039  // Next, we Update the boundary lookup schemes
7040 
7041  // Check if we need to add nodes to the mesh
7042  if (mesh_pt != 0)
7043  {
7044  // Loop over the boundaries stored in the set
7045  for (std::set<unsigned>::iterator it = boundaries.begin();
7046  it != boundaries.end();
7047  ++it)
7048  {
7049  // Add the node to the boundary
7050  mesh_pt->add_boundary_node(*it, created_node_pt);
7051 
7052  // If we have set an intrinsic coordinate on this
7053  // mesh boundary then it must also be interpolated on
7054  // the new node
7055  // Now interpolate the intrinsic boundary coordinate
7056  if (mesh_pt->boundary_coordinate_exists(*it) == true)
7057  {
7058  Vector<double> zeta(2);
7059  clone_el_pt->interpolated_zeta_on_face(
7060  *it, my_bound, s, zeta);
7061 
7062  created_node_pt->set_coordinates_on_boundary(*it, zeta);
7063  }
7064  }
7065  }
7066  }
7067  // Otherwise the node is not on a Mesh boundary and
7068  // we create a normal "bulk" node
7069  else
7070  {
7071  // Create node and set the pointer to it from the element
7072  created_node_pt = this->construct_node(jnod, time_stepper_pt);
7073  }
7074 
7075  // Now we set the position and values at the newly created node
7076 
7077  // In the first instance use macro element or FE representation
7078  // to create past and present nodal positions.
7079  // (THIS STEP SHOULD NOT BE SKIPPED FOR ALGEBRAIC
7080  // ELEMENTS AS NOT ALL OF THEM NECESSARILY IMPLEMENT
7081  // NONTRIVIAL NODE UPDATE FUNCTIONS. CALLING
7082  // THE NODE UPDATE FOR SUCH ELEMENTS/NODES WILL LEAVE
7083  // THEIR NODAL POSITIONS WHERE THEY WERE (THIS IS APPROPRIATE
7084  // ONCE THEY HAVE BEEN GIVEN POSITIONS) BUT WILL
7085  // NOT ASSIGN SENSIBLE INITIAL POSITONS!
7086 
7087  // Loop over # of history values
7088  for (unsigned t = 0; t < ntstorage; t++)
7089  {
7090  // Get position from father element -- this uses the macro
7091  // element representation if appropriate. If the node
7092  // turns out to be a hanging node later on, then
7093  // its position gets adjusted in line with its
7094  // hanging node interpolation.
7095  Vector<double> x_prev(3);
7096  clone_el_pt->get_x(t, s, x_prev);
7097 
7098  // Set previous positions of the new node
7099  for (unsigned i = 0; i < 3; i++)
7100  {
7101  created_node_pt->x(t, i) = x_prev[i];
7102  }
7103  }
7104 
7105  // Loop over all history values
7106  for (unsigned t = 0; t < ntstorage; t++)
7107  {
7108  // Get values from father element
7109  // Note: get_interpolated_values() sets Vector size itself.
7110  Vector<double> prev_values;
7111  clone_el_pt->get_interpolated_values(t, s, prev_values);
7112 
7113  // Initialise the values at the new node
7114  unsigned n_value = created_node_pt->nvalue();
7115  for (unsigned k = 0; k < n_value; k++)
7116  {
7117  created_node_pt->set_value(t, k, prev_values[k]);
7118  }
7119  }
7120 
7121  // Add new node to mesh (if requested)
7122  if (mesh_pt != 0)
7123  {
7124  mesh_pt->add_node_pt(created_node_pt);
7125  }
7126 
7127  AlgebraicElementBase* alg_el_pt =
7128  dynamic_cast<AlgebraicElementBase*>(this);
7129 
7130  // If we do have an algebraic element
7131  if (alg_el_pt != 0)
7132  {
7133  std::string error_message =
7134  "Have not implemented p-refinement for";
7135  error_message += "Algebraic p-refineable elements yet\n";
7136 
7137  throw OomphLibError(
7138  error_message,
7139  "PRefineableQElement<3,INITIAL_NNODE_1D>::p_refine()",
7140  OOMPH_EXCEPTION_LOCATION);
7141  }
7142 
7143  } // End of case when we build the node ourselves
7144 
7145  // Check if the element is an algebraic element
7146  AlgebraicElementBase* alg_el_pt =
7147  dynamic_cast<AlgebraicElementBase*>(this);
7148 
7149  // If the element is an algebraic element, setup
7150  // node position (past and present) from algebraic node update
7151  // function. This over-writes previous assingments that
7152  // were made based on the macro-element/FE representation.
7153  // NOTE: YES, THIS NEEDS TO BE CALLED REPEATEDLY IF THE
7154  // NODE IS MEMBER OF MULTIPLE ELEMENTS: THEY ALL ASSIGN
7155  // THE SAME NODAL POSITIONS BUT WE NEED TO ADD THE REMESH
7156  // INFO FOR *ALL* ROOT ELEMENTS!
7157  if (alg_el_pt != 0)
7158  {
7159  // Build algebraic node update info for new node
7160  // This sets up the node update data for all node update
7161  // functions that are shared by all nodes in the father
7162  // element
7163  alg_el_pt->setup_algebraic_node_update(
7164  this->node_pt(jnod), s, clone_el_pt);
7165  }
7166 
7167  } // End of vertical loop over nodes in element (i2)
7168 
7169  } // End of horizontal loop over nodes in element (i1)
7170 
7171  } // End of horizontal loop over nodes in element (i0)
7172 
7173 
7174  // Loop over all nodes in element again, to re-set the positions
7175  // This must be done using the new element's macro-element
7176  // representation, rather than the old version which may be
7177  // of a different p-order!
7178  for (unsigned i0 = 0; i0 < this->P_order; i0++)
7179  {
7180  // Get the fractional position of the node in the direction of s[0]
7181  s_fraction[0] = this->local_one_d_fraction_of_node(i0, 0);
7182  // Local coordinate
7183  s[0] = s_lo[0] + (s_hi[0] - s_lo[0]) * s_fraction[0];
7184 
7185  for (unsigned i1 = 0; i1 < this->P_order; i1++)
7186  {
7187  // Get the fractional position of the node in the direction of s[1]
7188  s_fraction[1] = this->local_one_d_fraction_of_node(i1, 1);
7189  // Local coordinate
7190  s[1] = s_lo[1] + (s_hi[1] - s_lo[1]) * s_fraction[1];
7191 
7192  for (unsigned i2 = 0; i2 < this->P_order; i2++)
7193  {
7194  // Get the fractional position of the node in the direction of s[2]
7195  s_fraction[2] = this->local_one_d_fraction_of_node(i2, 2);
7196  // Local coordinate
7197  s[2] = s_lo[2] + (s_hi[2] - s_lo[2]) * s_fraction[2];
7198 
7199  // Local node number
7200  jnod = i0 + this->P_order * i1 + this->P_order * this->P_order * i2;
7201 
7202  // Loop over # of history values
7203  for (unsigned t = 0; t < ntstorage; t++)
7204  {
7205  // Get position from father element -- this uses the macro
7206  // element representation if appropriate. If the node
7207  // turns out to be a hanging node later on, then
7208  // its position gets adjusted in line with its
7209  // hanging node interpolation.
7210  Vector<double> x_prev(3);
7211  this->get_x(t, s, x_prev);
7212 
7213  // Set previous positions of the new node
7214  for (unsigned i = 0; i < 3; i++)
7215  {
7216  this->node_pt(jnod)->x(t, i) = x_prev[i];
7217  }
7218  }
7219  }
7220  }
7221  }
7222 
7223 
7224  // If the element is a MacroElementNodeUpdateElement, set
7225  // the update parameters for the current element's nodes --
7226  // all this needs is the vector of (pointers to the)
7227  // geometric objects that affect the MacroElement-based
7228  // node update -- this needs to be done to set the node
7229  // update info for newly created nodes
7230  MacroElementNodeUpdateElementBase* clone_m_el_pt =
7231  dynamic_cast<MacroElementNodeUpdateElementBase*>(clone_el_pt);
7232  if (clone_m_el_pt != 0)
7233  {
7234  // Get vector of geometric objects from father (construct vector
7235  // via copy operation)
7236  Vector<GeomObject*> geom_object_pt(clone_m_el_pt->geom_object_pt());
7237 
7238  // Cast current element to MacroElementNodeUpdateElement:
7240  dynamic_cast<MacroElementNodeUpdateElementBase*>(this);
7241 
7242 #ifdef PARANOID
7243  if (m_el_pt == 0)
7244  {
7245  std::string error_message =
7246  "Failed to cast to MacroElementNodeUpdateElementBase*\n";
7247  error_message +=
7248  "Strange -- if my clone is a MacroElementNodeUpdateElement\n";
7249  error_message += "then I should be too....\n";
7250 
7251  throw OomphLibError(
7252  error_message,
7253  "PRefineableQElement<3,INITIAL_NNODE_1D>::p_refine()",
7254  OOMPH_EXCEPTION_LOCATION);
7255  }
7256 #endif
7257  // Build update info by passing vector of geometric objects:
7258  // This sets the current element to be the update element
7259  // for all of the element's nodes -- this is reversed
7260  // if the element is ever un-refined in the father element's
7261  // rebuild_from_sons() function which overwrites this
7262  // assignment to avoid nasty segmentation faults that occur
7263  // when a node tries to update itself via an element that no
7264  // longer exists...
7265  m_el_pt->set_node_update_info(geom_object_pt);
7266  }
7267 
7268  // Not necessary to delete the old nodes since all original nodes are in the
7269  // current mesh and so will be pruned as part of the mesh adaption process.
7270 
7271  // Do any further-build required
7272  this->further_build();
7273  }
7274 
7275  //=======================================================================
7276  /// Shape functions for PRefineableQElement<DIM>
7277  //=======================================================================
7278  template<unsigned INITIAL_NNODE_1D>
7280  Shape& psi) const
7281  {
7282  switch (P_order)
7283  {
7284  case 2:
7285  {
7286  // Call the OneDimensional Shape functions
7288  OneDimensionalLegendreShape<2> psi1(s[0]), psi2(s[1]), psi3(s[2]);
7289 
7290  // Now let's loop over the nodal points in the element
7291  // and copy the values back in
7292  for (unsigned i = 0; i < P_order; i++)
7293  {
7294  for (unsigned j = 0; j < P_order; j++)
7295  {
7296  for (unsigned k = 0; k < P_order; k++)
7297  {
7298  psi(P_order * P_order * i + P_order * j + k) =
7299  psi3[i] * psi2[j] * psi1[k];
7300  }
7301  }
7302  }
7303  break;
7304  }
7305  case 3:
7306  {
7307  // Call the OneDimensional Shape functions
7309  OneDimensionalLegendreShape<3> psi1(s[0]), psi2(s[1]), psi3(s[2]);
7310 
7311  // Now let's loop over the nodal points in the element
7312  // and copy the values back in
7313  for (unsigned i = 0; i < P_order; i++)
7314  {
7315  for (unsigned j = 0; j < P_order; j++)
7316  {
7317  for (unsigned k = 0; k < P_order; k++)
7318  {
7319  psi(P_order * P_order * i + P_order * j + k) =
7320  psi3[i] * psi2[j] * psi1[k];
7321  }
7322  }
7323  }
7324  break;
7325  }
7326  case 4:
7327  {
7328  // Call the OneDimensional Shape functions
7330  OneDimensionalLegendreShape<4> psi1(s[0]), psi2(s[1]), psi3(s[2]);
7331 
7332  // Now let's loop over the nodal points in the element
7333  // and copy the values back in
7334  for (unsigned i = 0; i < P_order; i++)
7335  {
7336  for (unsigned j = 0; j < P_order; j++)
7337  {
7338  for (unsigned k = 0; k < P_order; k++)
7339  {
7340  psi(P_order * P_order * i + P_order * j + k) =
7341  psi3[i] * psi2[j] * psi1[k];
7342  }
7343  }
7344  }
7345  break;
7346  }
7347  case 5:
7348  {
7349  // Call the OneDimensional Shape functions
7351  OneDimensionalLegendreShape<5> psi1(s[0]), psi2(s[1]), psi3(s[2]);
7352 
7353  // Now let's loop over the nodal points in the element
7354  // and copy the values back in
7355  for (unsigned i = 0; i < P_order; i++)
7356  {
7357  for (unsigned j = 0; j < P_order; j++)
7358  {
7359  for (unsigned k = 0; k < P_order; k++)
7360  {
7361  psi(P_order * P_order * i + P_order * j + k) =
7362  psi3[i] * psi2[j] * psi1[k];
7363  }
7364  }
7365  }
7366  break;
7367  }
7368  case 6:
7369  {
7370  // Call the OneDimensional Shape functions
7372  OneDimensionalLegendreShape<6> psi1(s[0]), psi2(s[1]), psi3(s[2]);
7373 
7374  // Now let's loop over the nodal points in the element
7375  // and copy the values back in
7376  for (unsigned i = 0; i < P_order; i++)
7377  {
7378  for (unsigned j = 0; j < P_order; j++)
7379  {
7380  for (unsigned k = 0; k < P_order; k++)
7381  {
7382  psi(P_order * P_order * i + P_order * j + k) =
7383  psi3[i] * psi2[j] * psi1[k];
7384  }
7385  }
7386  }
7387  break;
7388  }
7389  case 7:
7390  {
7391  // Call the OneDimensional Shape functions
7393  OneDimensionalLegendreShape<7> psi1(s[0]), psi2(s[1]), psi3(s[2]);
7394 
7395  // Now let's loop over the nodal points in the element
7396  // and copy the values back in
7397  for (unsigned i = 0; i < P_order; i++)
7398  {
7399  for (unsigned j = 0; j < P_order; j++)
7400  {
7401  for (unsigned k = 0; k < P_order; k++)
7402  {
7403  psi(P_order * P_order * i + P_order * j + k) =
7404  psi3[i] * psi2[j] * psi1[k];
7405  }
7406  }
7407  }
7408  break;
7409  }
7410  default:
7411  std::ostringstream error_message;
7412  error_message << "\nERROR: Exceeded maximum polynomial order for";
7413  error_message << "\n polynomial order for shape functions.\n";
7414  throw OomphLibError(error_message.str(),
7415  OOMPH_CURRENT_FUNCTION,
7416  OOMPH_EXCEPTION_LOCATION);
7417  }
7418  }
7419 
7420  //=======================================================================
7421  /// Derivatives of shape functions for PRefineableQElement<DIM>
7422  //=======================================================================
7423  template<unsigned INITIAL_NNODE_1D>
7425  const Vector<double>& s, Shape& psi, DShape& dpsids) const
7426  {
7427  switch (P_order)
7428  {
7429  case 2:
7430  {
7431  // Call the shape functions and derivatives
7433  OneDimensionalLegendreShape<2> psi1(s[0]), psi2(s[1]), psi3(s[2]);
7434  OneDimensionalLegendreDShape<2> dpsi1ds(s[0]), dpsi2ds(s[1]),
7435  dpsi3ds(s[2]);
7436 
7437  // Index for the shape functions
7438  unsigned index = 0;
7439  // Loop over shape functions in element
7440  for (unsigned i = 0; i < P_order; i++)
7441  {
7442  for (unsigned j = 0; j < P_order; j++)
7443  {
7444  for (unsigned k = 0; k < P_order; k++)
7445  {
7446  // Assign the values
7447  dpsids(index, 0) = psi3[i] * psi2[j] * dpsi1ds[k];
7448  dpsids(index, 1) = psi3[i] * dpsi2ds[j] * psi1[k];
7449  dpsids(index, 2) = dpsi3ds[i] * psi2[j] * psi1[k];
7450  psi[index] = psi3[i] * psi2[j] * psi1[k];
7451  // Increment the index
7452  ++index;
7453  }
7454  }
7455  }
7456  break;
7457  }
7458  case 3:
7459  {
7460  // Call the shape functions and derivatives
7462  OneDimensionalLegendreShape<3> psi1(s[0]), psi2(s[1]), psi3(s[2]);
7463  OneDimensionalLegendreDShape<3> dpsi1ds(s[0]), dpsi2ds(s[1]),
7464  dpsi3ds(s[2]);
7465 
7466  // Index for the shape functions
7467  unsigned index = 0;
7468  // Loop over shape functions in element
7469  for (unsigned i = 0; i < P_order; i++)
7470  {
7471  for (unsigned j = 0; j < P_order; j++)
7472  {
7473  for (unsigned k = 0; k < P_order; k++)
7474  {
7475  // Assign the values
7476  dpsids(index, 0) = psi3[i] * psi2[j] * dpsi1ds[k];
7477  dpsids(index, 1) = psi3[i] * dpsi2ds[j] * psi1[k];
7478  dpsids(index, 2) = dpsi3ds[i] * psi2[j] * psi1[k];
7479  psi[index] = psi3[i] * psi2[j] * psi1[k];
7480  // Increment the index
7481  ++index;
7482  }
7483  }
7484  }
7485  break;
7486  }
7487  case 4:
7488  {
7489  // Call the shape functions and derivatives
7491  OneDimensionalLegendreShape<4> psi1(s[0]), psi2(s[1]), psi3(s[2]);
7492  OneDimensionalLegendreDShape<4> dpsi1ds(s[0]), dpsi2ds(s[1]),
7493  dpsi3ds(s[2]);
7494 
7495  // Index for the shape functions
7496  unsigned index = 0;
7497  // Loop over shape functions in element
7498  for (unsigned i = 0; i < P_order; i++)
7499  {
7500  for (unsigned j = 0; j < P_order; j++)
7501  {
7502  for (unsigned k = 0; k < P_order; k++)
7503  {
7504  // Assign the values
7505  dpsids(index, 0) = psi3[i] * psi2[j] * dpsi1ds[k];
7506  dpsids(index, 1) = psi3[i] * dpsi2ds[j] * psi1[k];
7507  dpsids(index, 2) = dpsi3ds[i] * psi2[j] * psi1[k];
7508  psi[index] = psi3[i] * psi2[j] * psi1[k];
7509  // Increment the index
7510  ++index;
7511  }
7512  }
7513  }
7514  break;
7515  }
7516  case 5:
7517  {
7518  // Call the shape functions and derivatives
7520  OneDimensionalLegendreShape<5> psi1(s[0]), psi2(s[1]), psi3(s[2]);
7521  OneDimensionalLegendreDShape<5> dpsi1ds(s[0]), dpsi2ds(s[1]),
7522  dpsi3ds(s[2]);
7523 
7524  // Index for the shape functions
7525  unsigned index = 0;
7526  // Loop over shape functions in element
7527  for (unsigned i = 0; i < P_order; i++)
7528  {
7529  for (unsigned j = 0; j < P_order; j++)
7530  {
7531  for (unsigned k = 0; k < P_order; k++)
7532  {
7533  // Assign the values
7534  dpsids(index, 0) = psi3[i] * psi2[j] * dpsi1ds[k];
7535  dpsids(index, 1) = psi3[i] * dpsi2ds[j] * psi1[k];
7536  dpsids(index, 2) = dpsi3ds[i] * psi2[j] * psi1[k];
7537  psi[index] = psi3[i] * psi2[j] * psi1[k];
7538  // Increment the index
7539  ++index;
7540  }
7541  }
7542  }
7543  break;
7544  }
7545  case 6:
7546  {
7547  // Call the shape functions and derivatives
7549  OneDimensionalLegendreShape<6> psi1(s[0]), psi2(s[1]), psi3(s[2]);
7550  OneDimensionalLegendreDShape<6> dpsi1ds(s[0]), dpsi2ds(s[1]),
7551  dpsi3ds(s[2]);
7552 
7553  // Index for the shape functions
7554  unsigned index = 0;
7555  // Loop over shape functions in element
7556  for (unsigned i = 0; i < P_order; i++)
7557  {
7558  for (unsigned j = 0; j < P_order; j++)
7559  {
7560  for (unsigned k = 0; k < P_order; k++)
7561  {
7562  // Assign the values
7563  dpsids(index, 0) = psi3[i] * psi2[j] * dpsi1ds[k];
7564  dpsids(index, 1) = psi3[i] * dpsi2ds[j] * psi1[k];
7565  dpsids(index, 2) = dpsi3ds[i] * psi2[j] * psi1[k];
7566  psi[index] = psi3[i] * psi2[j] * psi1[k];
7567  // Increment the index
7568  ++index;
7569  }
7570  }
7571  }
7572  break;
7573  }
7574  case 7:
7575  {
7576  // Call the shape functions and derivatives
7578  OneDimensionalLegendreShape<7> psi1(s[0]), psi2(s[1]), psi3(s[2]);
7579  OneDimensionalLegendreDShape<7> dpsi1ds(s[0]), dpsi2ds(s[1]),
7580  dpsi3ds(s[2]);
7581 
7582  // Index for the shape functions
7583  unsigned index = 0;
7584  // Loop over shape functions in element
7585  for (unsigned i = 0; i < P_order; i++)
7586  {
7587  for (unsigned j = 0; j < P_order; j++)
7588  {
7589  for (unsigned k = 0; k < P_order; k++)
7590  {
7591  // Assign the values
7592  dpsids(index, 0) = psi3[i] * psi2[j] * dpsi1ds[k];
7593  dpsids(index, 1) = psi3[i] * dpsi2ds[j] * psi1[k];
7594  dpsids(index, 2) = dpsi3ds[i] * psi2[j] * psi1[k];
7595  psi[index] = psi3[i] * psi2[j] * psi1[k];
7596  // Increment the index
7597  ++index;
7598  }
7599  }
7600  }
7601  break;
7602  }
7603  default:
7604  std::ostringstream error_message;
7605  error_message << "\nERROR: Exceeded maximum polynomial order for";
7606  error_message << "\n polynomial order for shape functions.\n";
7607  throw OomphLibError(error_message.str(),
7608  OOMPH_CURRENT_FUNCTION,
7609  OOMPH_EXCEPTION_LOCATION);
7610  }
7611  }
7612 
7613  //=======================================================================
7614  /// Second derivatives of shape functions for PRefineableQElement<DIM>
7615  /// d2psids(i,0) = \f$ d^2 \psi_j / d s^2 \f$
7616  //=======================================================================
7617  template<unsigned INITIAL_NNODE_1D>
7619  const Vector<double>& s, Shape& psi, DShape& dpsids, DShape& d2psids) const
7620  {
7621  std::ostringstream error_message;
7622  error_message
7623  << "\nd2shape_local currently not implemented for this element\n";
7624  throw OomphLibError(
7625  error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
7626  }
7627 
7628  //=======================================================================
7629  /// Rebuild the element from nodes found in its sons
7630  /// Adjusts its p-order to be the maximum of its sons' p-orders
7631  //=======================================================================
7632  template<unsigned INITIAL_NNODE_1D>
7634  Mesh*& mesh_pt)
7635  {
7636  // Get p-orders of sons
7637  unsigned n_sons = this->tree_pt()->nsons();
7638  Vector<unsigned> son_p_order(n_sons);
7639  unsigned max_son_p_order = 0;
7640  for (unsigned ison = 0; ison < n_sons; ison++)
7641  {
7642  PRefineableElement* el_pt = dynamic_cast<PRefineableElement*>(
7643  this->tree_pt()->son_pt(ison)->object_pt());
7644  son_p_order[ison] = el_pt->p_order();
7645  if (son_p_order[ison] > max_son_p_order)
7646  max_son_p_order = son_p_order[ison];
7647  }
7648 
7649  unsigned old_Nnode = this->nnode();
7650  unsigned old_P_order = this->p_order();
7651  // Set p-order of the element
7652  this->p_order() = max_son_p_order;
7653 
7654  // Change integration scheme
7655  delete this->integral_pt();
7656  switch (this->p_order())
7657  {
7658  case 2:
7659  this->set_integration_scheme(new GaussLobattoLegendre<3, 2>);
7660  break;
7661  case 3:
7662  this->set_integration_scheme(new GaussLobattoLegendre<3, 3>);
7663  break;
7664  case 4:
7665  this->set_integration_scheme(new GaussLobattoLegendre<3, 4>);
7666  break;
7667  case 5:
7668  this->set_integration_scheme(new GaussLobattoLegendre<3, 5>);
7669  break;
7670  case 6:
7671  this->set_integration_scheme(new GaussLobattoLegendre<3, 6>);
7672  break;
7673  case 7:
7674  this->set_integration_scheme(new GaussLobattoLegendre<3, 7>);
7675  break;
7676  default:
7677  std::ostringstream error_message;
7678  error_message << "\nERROR: Exceeded maximum polynomial order for";
7679  error_message << "\n integration scheme.\n";
7680  throw OomphLibError(
7681  error_message.str(),
7682  "PRefineableQElement<3,INITIAL_NNODE_1D>::rebuild_from_sons()",
7683  OOMPH_EXCEPTION_LOCATION);
7684  }
7685 
7686  // Back up pointers to old nodes before they are lost
7687  Vector<Node*> old_node_pt(old_Nnode);
7688  for (unsigned n = 0; n < old_Nnode; n++)
7689  {
7690  old_node_pt[n] = this->node_pt(n);
7691  }
7692 
7693  // Allocate new space for Nodes (at the element level)
7694  this->set_n_node(this->p_order() * this->p_order() * this->p_order());
7695 
7696  // Copy vertex nodes which were populated in the pre-build
7697  this->node_pt(0) = old_node_pt[0];
7698  this->node_pt(this->p_order() - 1) = old_node_pt[old_P_order - 1];
7699  this->node_pt(this->p_order() * (this->p_order() - 1)) =
7700  old_node_pt[(old_P_order) * (old_P_order - 1)];
7701  this->node_pt(this->p_order() * this->p_order() - 1) =
7702  old_node_pt[(old_P_order) * (old_P_order)-1];
7703  this->node_pt(this->p_order() * this->p_order() * (this->p_order() - 1)) =
7704  old_node_pt[old_P_order * old_P_order * (old_P_order - 1)];
7705  this->node_pt((this->p_order() * this->p_order() + 1) *
7706  (this->p_order() - 1)) =
7707  old_node_pt[(old_P_order * old_P_order + 1) * (old_P_order - 1)];
7708  this->node_pt(this->p_order() * (this->p_order() + 1) *
7709  (this->p_order() - 1)) =
7710  old_node_pt[old_P_order * (old_P_order + 1) * (old_P_order - 1)];
7711  this->node_pt(this->p_order() * this->p_order() * this->p_order() - 1) =
7712  old_node_pt[old_P_order * old_P_order * old_P_order - 1];
7713 
7714  // Copy midpoint nodes from sons if new p-order is odd
7715  if (this->p_order() % 2 == 1)
7716  {
7717  // Work out which is midpoint node
7718  unsigned n_p = this->p_order();
7719  unsigned m = (n_p - 1) / 2;
7720 
7721  unsigned s0space = m;
7722  unsigned s1space = m * n_p;
7723  unsigned s2space = m * n_p * n_p;
7724 
7725  // Back face
7726  // DB edge
7727  this->node_pt(1 * s0space + 0 * s1space + 0 * s2space) =
7728  dynamic_cast<RefineableQElement<3>*>(
7729  octree_pt()->son_pt(OcTreeNames::RDB)->object_pt())
7730  ->vertex_node_pt(0);
7731  // LB edge
7732  this->node_pt(0 * s0space + 1 * s1space + 0 * s2space) =
7733  dynamic_cast<RefineableQElement<3>*>(
7734  octree_pt()->son_pt(OcTreeNames::LUB)->object_pt())
7735  ->vertex_node_pt(0);
7736  // B centre
7737  this->node_pt(1 * s0space + 1 * s1space + 0 * s2space) =
7738  dynamic_cast<RefineableQElement<3>*>(
7739  octree_pt()->son_pt(OcTreeNames::RUB)->object_pt())
7740  ->vertex_node_pt(0);
7741  // RB edge
7742  this->node_pt(2 * s0space + 1 * s1space + 0 * s2space) =
7743  dynamic_cast<RefineableQElement<3>*>(
7744  octree_pt()->son_pt(OcTreeNames::RUB)->object_pt())
7745  ->vertex_node_pt(1);
7746  // UB edge
7747  this->node_pt(1 * s0space + 2 * s1space + 0 * s2space) =
7748  dynamic_cast<RefineableQElement<3>*>(
7749  octree_pt()->son_pt(OcTreeNames::RUB)->object_pt())
7750  ->vertex_node_pt(2);
7751 
7752  // Mid-way between between back and front faces
7753  // LD edge
7754  this->node_pt(0 * s0space + 0 * s1space + 1 * s2space) =
7755  dynamic_cast<RefineableQElement<3>*>(
7756  octree_pt()->son_pt(OcTreeNames::LDF)->object_pt())
7757  ->vertex_node_pt(0);
7758  // D centre
7759  this->node_pt(1 * s0space + 0 * s1space + 1 * s2space) =
7760  dynamic_cast<RefineableQElement<3>*>(
7761  octree_pt()->son_pt(OcTreeNames::LDF)->object_pt())
7762  ->vertex_node_pt(1);
7763  // RD edge
7764  this->node_pt(2 * s0space + 0 * s1space + 1 * s2space) =
7765  dynamic_cast<RefineableQElement<3>*>(
7766  octree_pt()->son_pt(OcTreeNames::RDF)->object_pt())
7767  ->vertex_node_pt(1);
7768  // L centre
7769  this->node_pt(0 * s0space + 1 * s1space + 1 * s2space) =
7770  dynamic_cast<RefineableQElement<3>*>(
7771  octree_pt()->son_pt(OcTreeNames::LUF)->object_pt())
7772  ->vertex_node_pt(0);
7773  // Centre
7774  this->node_pt(1 * s0space + 1 * s1space + 1 * s2space) =
7775  dynamic_cast<RefineableQElement<3>*>(
7776  octree_pt()->son_pt(OcTreeNames::RUF)->object_pt())
7777  ->vertex_node_pt(0);
7778  // R centre
7779  this->node_pt(2 * s0space + 1 * s1space + 1 * s2space) =
7780  dynamic_cast<RefineableQElement<3>*>(
7781  octree_pt()->son_pt(OcTreeNames::RUF)->object_pt())
7782  ->vertex_node_pt(1);
7783  // LU edge
7784  this->node_pt(0 * s0space + 2 * s1space + 1 * s2space) =
7785  dynamic_cast<RefineableQElement<3>*>(
7786  octree_pt()->son_pt(OcTreeNames::LUF)->object_pt())
7787  ->vertex_node_pt(2);
7788  // U center
7789  this->node_pt(1 * s0space + 2 * s1space + 1 * s2space) =
7790  dynamic_cast<RefineableQElement<3>*>(
7791  octree_pt()->son_pt(OcTreeNames::RUF)->object_pt())
7792  ->vertex_node_pt(2);
7793  // RU edge
7794  this->node_pt(2 * s0space + 2 * s1space + 1 * s2space) =
7795  dynamic_cast<RefineableQElement<3>*>(
7796  octree_pt()->son_pt(OcTreeNames::RUF)->object_pt())
7797  ->vertex_node_pt(3);
7798 
7799  // Front face
7800  // DF edge
7801  this->node_pt(1 * s0space + 0 * s1space + 2 * s2space) =
7802  dynamic_cast<RefineableQElement<3>*>(
7803  octree_pt()->son_pt(OcTreeNames::LDF)->object_pt())
7804  ->vertex_node_pt(5);
7805  // LF edge
7806  this->node_pt(0 * s0space + 1 * s1space + 2 * s2space) =
7807  dynamic_cast<RefineableQElement<3>*>(
7808  octree_pt()->son_pt(OcTreeNames::LUF)->object_pt())
7809  ->vertex_node_pt(4);
7810  // F centre
7811  this->node_pt(1 * s0space + 1 * s1space + 2 * s2space) =
7812  dynamic_cast<RefineableQElement<3>*>(
7813  octree_pt()->son_pt(OcTreeNames::RUF)->object_pt())
7814  ->vertex_node_pt(4);
7815  // RF edge
7816  this->node_pt(2 * s0space + 1 * s1space + 2 * s2space) =
7817  dynamic_cast<RefineableQElement<3>*>(
7818  octree_pt()->son_pt(OcTreeNames::RUF)->object_pt())
7819  ->vertex_node_pt(5);
7820  // UF edge
7821  this->node_pt(1 * s0space + 2 * s1space + 2 * s2space) =
7822  dynamic_cast<RefineableQElement<3>*>(
7823  octree_pt()->son_pt(OcTreeNames::RUF)->object_pt())
7824  ->vertex_node_pt(6);
7825  }
7826 
7827  // The timestepper should be the same for all nodes and node 0 should
7828  // never be deleted.
7829  if (this->node_pt(0) == 0)
7830  {
7831  throw OomphLibError(
7832  "The Corner node (0) does not exist",
7833  "PRefineableQElement<3,INITIAL_NNODE_1D>::rebuild_from_sons()",
7834  OOMPH_EXCEPTION_LOCATION);
7835  }
7836 
7837  TimeStepper* time_stepper_pt = this->node_pt(0)->time_stepper_pt();
7838  unsigned ntstorage = time_stepper_pt->ntstorage();
7839 
7840  unsigned jnod = 0;
7841  Vector<double> s_fraction(3), s(3);
7842  // Loop over the nodes in the element
7843  unsigned n_p = this->nnode_1d();
7844  for (unsigned i0 = 0; i0 < n_p; i0++)
7845  {
7846  // Get the fractional position of the node
7847  s_fraction[0] = this->local_one_d_fraction_of_node(i0, 0);
7848  // Local coordinate
7849  s[0] = -1.0 + 2.0 * s_fraction[0];
7850 
7851  for (unsigned i1 = 0; i1 < n_p; i1++)
7852  {
7853  // Get the fractional position of the node in the direction of s[1]
7854  s_fraction[1] = this->local_one_d_fraction_of_node(i1, 1);
7855  // Local coordinate in father element
7856  s[1] = -1.0 + 2.0 * s_fraction[1];
7857 
7858  for (unsigned i2 = 0; i2 < n_p; i2++)
7859  {
7860  // Get the fractional position of the node in the direction of s[2]
7861  s_fraction[2] = this->local_one_d_fraction_of_node(i2, 2);
7862  // Local coordinate in father element
7863  s[2] = -1.0 + 2.0 * s_fraction[2];
7864 
7865  // Set the local node number
7866  jnod = i0 + n_p * i1 + n_p * n_p * i2;
7867 
7868  // Initialise flag: So far, this node hasn't been built
7869  // or copied yet
7870  bool node_done = false;
7871 
7872  // Get the pointer to the node in this element, returns NULL
7873  // if there is not node
7874  Node* created_node_pt = this->get_node_at_local_coordinate(s);
7875 
7876  // Does this node already exist in this element?
7877  //----------------------------------------------
7878  if (created_node_pt != 0)
7879  {
7880  // Copy node across
7881  this->node_pt(jnod) = created_node_pt;
7882 
7883  // Node has been created by copy
7884  node_done = true;
7885  }
7886  // Node does not exist in this element but might already
7887  //------------------------------------------------------
7888  // have been created by neighbouring elements
7889  //-------------------------------------------
7890  else
7891  {
7892  // Was the node created by one of its neighbours
7893  // Whether or not the node lies on an edge can be calculated
7894  // by from the fractional position
7895  bool is_periodic = false;
7896  created_node_pt =
7897  node_created_by_neighbour(s_fraction, is_periodic);
7898 
7899  // If the node was so created, assign the pointers
7900  if (created_node_pt != 0)
7901  {
7902  // If the node is periodic
7903  if (is_periodic)
7904  {
7905  throw OomphLibError("Cannot handle periodic nodes yet",
7906  OOMPH_CURRENT_FUNCTION,
7907  OOMPH_EXCEPTION_LOCATION);
7908  }
7909  // Non-periodic case, just set the pointer
7910  else
7911  {
7912  this->node_pt(jnod) = created_node_pt;
7913  }
7914  // Node has been created
7915  node_done = true;
7916  }
7917  } // Node does not exist in this element
7918 
7919  // Node has not been built anywhere ---> build it here
7920  if (!node_done)
7921  {
7922  // First, find the son element in which the node should live
7923 
7924  // Find coordinates in the sons
7925  Vector<double> s_in_son(3);
7926  // using namespace OcTreeNames;
7927  int son = -10;
7928  // On the left
7929  if (s_fraction[0] < 0.5)
7930  {
7931  // On the bottom
7932  if (s_fraction[1] < 0.5)
7933  {
7934  // On the back
7935  if (s_fraction[2] < 0.5)
7936  {
7937  // It's the LDB son
7938  son = OcTreeNames::LDB;
7939  s_in_son[0] = -1.0 + 4.0 * s_fraction[0];
7940  s_in_son[1] = -1.0 + 4.0 * s_fraction[1];
7941  s_in_son[2] = -1.0 + 4.0 * s_fraction[2];
7942  }
7943  // On the front
7944  else
7945  {
7946  // It's the LDF son
7947  son = OcTreeNames::LDF;
7948  s_in_son[0] = -1.0 + 4.0 * s_fraction[0];
7949  s_in_son[1] = -1.0 + 4.0 * s_fraction[1];
7950  s_in_son[2] = -1.0 + 4.0 * (s_fraction[2] - 0.5);
7951  }
7952  }
7953  // On the top
7954  else
7955  {
7956  // On the back
7957  if (s[2] < 0.0)
7958  {
7959  // It's the LUB son
7960  son = OcTreeNames::LUB;
7961  s_in_son[0] = -1.0 + 4.0 * s_fraction[0];
7962  s_in_son[1] = -1.0 + 4.0 * (s_fraction[1] - 0.5);
7963  s_in_son[2] = -1.0 + 4.0 * s_fraction[2];
7964  }
7965  // On the front
7966  else
7967  {
7968  // It's the LUF son
7969  son = OcTreeNames::LUF;
7970  s_in_son[0] = -1.0 + 4.0 * s_fraction[0];
7971  s_in_son[1] = -1.0 + 4.0 * (s_fraction[1] - 0.5);
7972  s_in_son[2] = -1.0 + 4.0 * (s_fraction[2] - 0.5);
7973  }
7974  }
7975  }
7976  // On the right
7977  else
7978  {
7979  // On the bottom
7980  if (s[1] < 0.0)
7981  {
7982  // On the back
7983  if (s[2] < 0.0)
7984  {
7985  // It's the RDB son
7986  son = OcTreeNames::RDB;
7987  s_in_son[0] = -1.0 + 4.0 * (s_fraction[0] - 0.5);
7988  s_in_son[1] = -1.0 + 4.0 * s_fraction[1];
7989  s_in_son[2] = -1.0 + 4.0 * s_fraction[2];
7990  }
7991  // On the front
7992  else
7993  {
7994  // It's the RDF son
7995  son = OcTreeNames::RDF;
7996  s_in_son[0] = -1.0 + 4.0 * (s_fraction[0] - 0.5);
7997  s_in_son[1] = -1.0 + 4.0 * s_fraction[1];
7998  s_in_son[2] = -1.0 + 4.0 * (s_fraction[2] - 0.5);
7999  }
8000  }
8001  // On the top
8002  else
8003  {
8004  // On the back
8005  if (s[2] < 0.0)
8006  {
8007  // It's the RUB son
8008  son = OcTreeNames::RUB;
8009  s_in_son[0] = -1.0 + 4.0 * (s_fraction[0] - 0.5);
8010  s_in_son[1] = -1.0 + 4.0 * (s_fraction[1] - 0.5);
8011  s_in_son[2] = -1.0 + 4.0 * s_fraction[2];
8012  }
8013  // On the front
8014  else
8015  {
8016  // It's the RUF son
8017  son = OcTreeNames::RUF;
8018  s_in_son[0] = -1.0 + 4.0 * (s_fraction[0] - 0.5);
8019  s_in_son[1] = -1.0 + 4.0 * (s_fraction[1] - 0.5);
8020  s_in_son[2] = -1.0 + 4.0 * (s_fraction[2] - 0.5);
8021  }
8022  }
8023  }
8024 
8025  // Get the pointer to the son element in which the new node
8026  // would live
8029  this->tree_pt()->son_pt(son)->object_pt());
8030 
8031  // If we are rebuilding, then worry about the boundary conditions
8032  // Find the boundary of the node
8033  // Initially none
8034  int boundary = Tree::OMEGA;
8035  // If we are on the left face
8036  if (i0 == 0)
8037  {
8038  boundary = OcTreeNames::L;
8039  }
8040  // If we are on the right face
8041  else if (i0 == n_p - 1)
8042  {
8043  boundary = OcTreeNames::R;
8044  }
8045 
8046  // If we are on the bottom face
8047  if (i1 == 0)
8048  {
8049  // If we already have already set the boundary, we're on an edge
8050  switch (boundary)
8051  {
8052  case OcTreeNames::L:
8053  boundary = OcTreeNames::LD;
8054  break;
8055  case OcTreeNames::R:
8056  boundary = OcTreeNames::RD;
8057  break;
8058  // Boundary not set
8059  default:
8060  boundary = OcTreeNames::D;
8061  break;
8062  }
8063  }
8064  // If we are the top face
8065  else if (i1 == n_p - 1)
8066  {
8067  // If we already have a boundary
8068  switch (boundary)
8069  {
8070  case OcTreeNames::L:
8071  boundary = OcTreeNames::LU;
8072  break;
8073  case OcTreeNames::R:
8074  boundary = OcTreeNames::RU;
8075  break;
8076  default:
8077  boundary = OcTreeNames::U;
8078  break;
8079  }
8080  }
8081 
8082  // If we are on the back face
8083  if (i2 == 0)
8084  {
8085  // If we already have already set the boundary, we're on an edge
8086  switch (boundary)
8087  {
8088  case OcTreeNames::L:
8089  boundary = OcTreeNames::LB;
8090  break;
8091  case OcTreeNames::LD:
8092  boundary = OcTreeNames::LDB;
8093  break;
8094  case OcTreeNames::LU:
8095  boundary = OcTreeNames::LUB;
8096  break;
8097  case OcTreeNames::R:
8098  boundary = OcTreeNames::RB;
8099  break;
8100  case OcTreeNames::RD:
8101  boundary = OcTreeNames::RDB;
8102  break;
8103  case OcTreeNames::RU:
8104  boundary = OcTreeNames::RUB;
8105  break;
8106  case OcTreeNames::D:
8107  boundary = OcTreeNames::DB;
8108  break;
8109  case OcTreeNames::U:
8110  boundary = OcTreeNames::UB;
8111  break;
8112  // Boundary not set
8113  default:
8114  boundary = OcTreeNames::B;
8115  break;
8116  }
8117  }
8118  // If we are the front face
8119  else if (i2 == n_p - 1)
8120  {
8121  // If we already have a boundary
8122  switch (boundary)
8123  {
8124  case OcTreeNames::L:
8125  boundary = OcTreeNames::LF;
8126  break;
8127  case OcTreeNames::LD:
8128  boundary = OcTreeNames::LDF;
8129  break;
8130  case OcTreeNames::LU:
8131  boundary = OcTreeNames::LUF;
8132  break;
8133  case OcTreeNames::R:
8134  boundary = OcTreeNames::RF;
8135  break;
8136  case OcTreeNames::RD:
8137  boundary = OcTreeNames::RDF;
8138  break;
8139  case OcTreeNames::RU:
8140  boundary = OcTreeNames::RUF;
8141  break;
8142  case OcTreeNames::D:
8143  boundary = OcTreeNames::DF;
8144  break;
8145  case OcTreeNames::U:
8146  boundary = OcTreeNames::UF;
8147  break;
8148  default:
8149  boundary = OcTreeNames::F;
8150  break;
8151  }
8152  }
8153 
8154  // set of boundaries that this edge in the son lives on
8155  std::set<unsigned> boundaries;
8156 
8157  // Now get the boundary conditions from the son
8158  // The boundaries will be common to the son because there can be
8159  // no rotations here
8160  if (boundary != Tree::OMEGA)
8161  {
8162  son_el_pt->get_boundaries(boundary, boundaries);
8163  }
8164 
8165  // If the node lives on a boundary:
8166  // Construct a boundary node,
8167  // Get boundary conditions and
8168  // update all lookup schemes
8169  if (boundaries.size() > 0)
8170  {
8171  // Construct the new node
8172  created_node_pt =
8173  this->construct_boundary_node(jnod, time_stepper_pt);
8174 
8175  // Get the boundary conditions from the son
8176  Vector<int> bound_cons(this->ncont_interpolated_values());
8177  son_el_pt->get_bcs(boundary, bound_cons);
8178 
8179  // Loop over the values and pin if necessary
8180  unsigned nval = created_node_pt->nvalue();
8181  for (unsigned k = 0; k < nval; k++)
8182  {
8183  if (bound_cons[k])
8184  {
8185  created_node_pt->pin(k);
8186  }
8187  }
8188 
8189  // Solid node? If so, deal with the positional boundary
8190  // conditions:
8191  SolidNode* solid_node_pt =
8192  dynamic_cast<SolidNode*>(created_node_pt);
8193  if (solid_node_pt != 0)
8194  {
8195  // Get the positional boundary conditions from the father:
8196  unsigned n_dim = created_node_pt->ndim();
8197  Vector<int> solid_bound_cons(n_dim);
8198  RefineableSolidQElement<3>* son_solid_el_pt =
8199  dynamic_cast<RefineableSolidQElement<3>*>(son_el_pt);
8200 #ifdef PARANOID
8201  if (son_solid_el_pt == 0)
8202  {
8203  std::string error_message =
8204  "We have a SolidNode outside a refineable SolidElement\n";
8205  error_message +=
8206  "during mesh refinement -- this doesn't make sense\n";
8207 
8208  throw OomphLibError(error_message,
8209  "PRefineableQElement<3,INITIAL_NNODE_1D>:"
8210  ":rebuild_from_sons()",
8211  OOMPH_EXCEPTION_LOCATION);
8212  }
8213 #endif
8214  son_solid_el_pt->get_solid_bcs(boundary, solid_bound_cons);
8215 
8216  // Loop over the positions and pin, if necessary
8217  for (unsigned k = 0; k < n_dim; k++)
8218  {
8219  if (solid_bound_cons[k])
8220  {
8221  solid_node_pt->pin_position(k);
8222  }
8223  }
8224  } // End of if solid_node_pt
8225 
8226 
8227  // Next we update the boundary look-up schemes
8228  // Loop over the boundaries stored in the set
8229  for (std::set<unsigned>::iterator it = boundaries.begin();
8230  it != boundaries.end();
8231  ++it)
8232  {
8233  // Add the node to the boundary
8234  mesh_pt->add_boundary_node(*it, created_node_pt);
8235 
8236  // If we have set an intrinsic coordinate on this
8237  // mesh boundary then it must also be interpolated on
8238  // the new node
8239  // Now interpolate the intrinsic boundary coordinate
8240  if (mesh_pt->boundary_coordinate_exists(*it) == true)
8241  {
8242  Vector<double> zeta(2);
8243  son_el_pt->interpolated_zeta_on_face(
8244  *it, boundary, s_in_son, zeta);
8245 
8246  created_node_pt->set_coordinates_on_boundary(*it, zeta);
8247  }
8248  }
8249  }
8250  // Otherwise the node is not on a Mesh boundary
8251  // and we create a normal "bulk" node
8252  else
8253  {
8254  // Construct the new node
8255  created_node_pt = this->construct_node(jnod, time_stepper_pt);
8256  }
8257 
8258  // Now we set the position and values at the newly created node
8259 
8260  // In the first instance use macro element or FE representation
8261  // to create past and present nodal positions.
8262  // (THIS STEP SHOULD NOT BE SKIPPED FOR ALGEBRAIC
8263  // ELEMENTS AS NOT ALL OF THEM NECESSARILY IMPLEMENT
8264  // NONTRIVIAL NODE UPDATE FUNCTIONS. CALLING
8265  // THE NODE UPDATE FOR SUCH ELEMENTS/NODES WILL LEAVE
8266  // THEIR NODAL POSITIONS WHERE THEY WERE (THIS IS APPROPRIATE
8267  // ONCE THEY HAVE BEEN GIVEN POSITIONS) BUT WILL
8268  // NOT ASSIGN SENSIBLE INITIAL POSITONS!
8269 
8270  // Loop over # of history values
8271  // Loop over # of history values
8272  for (unsigned t = 0; t < ntstorage; t++)
8273  {
8274  using namespace QuadTreeNames;
8275  // Get the position from the son
8276  Vector<double> x_prev(3);
8277 
8278  // Now let's fill in the value
8279  son_el_pt->get_x(t, s_in_son, x_prev);
8280  for (unsigned i = 0; i < 3; i++)
8281  {
8282  created_node_pt->x(t, i) = x_prev[i];
8283  }
8284  }
8285 
8286  // Now set up the values
8287  // Loop over all history values
8288  for (unsigned t = 0; t < ntstorage; t++)
8289  {
8290  // Get values from father element
8291  // Note: get_interpolated_values() sets Vector size itself.
8292  Vector<double> prev_values;
8293  son_el_pt->get_interpolated_values(t, s_in_son, prev_values);
8294 
8295  // Initialise the values at the new node
8296  for (unsigned k = 0; k < created_node_pt->nvalue(); k++)
8297  {
8298  created_node_pt->set_value(t, k, prev_values[k]);
8299  }
8300  }
8301 
8302  // Add the node to the mesh
8303  mesh_pt->add_node_pt(created_node_pt);
8304 
8305  // Check if the element is an algebraic element
8306  AlgebraicElementBase* alg_el_pt =
8307  dynamic_cast<AlgebraicElementBase*>(this);
8308 
8309  // If we do have an algebraic element
8310  if (alg_el_pt != 0)
8311  {
8312  std::string error_message =
8313  "Have not implemented rebuilding from sons for";
8314  error_message += "Algebraic p-refineable elements yet\n";
8315 
8316  throw OomphLibError(
8317  error_message,
8318  "PRefineableQElement<3,INITIAL_NNODE_1D>::rebuild_from_sons()",
8319  OOMPH_EXCEPTION_LOCATION);
8320  }
8321 
8322  } // End of the case when we build the node ourselves
8323  }
8324  }
8325  }
8326  }
8327 
8328  //=================================================================
8329  /// Check inter-element continuity of
8330  /// - nodal positions
8331  /// - (nodally) interpolated function values
8332  /// Overloaded to not check differences in the value. Mortaring
8333  /// doesn't enforce strong continuity between elements.
8334  //====================================================================
8335  template<unsigned INITIAL_NNODE_1D>
8337  double& max_error)
8338  {
8339  // Not yet implemented -- doing nothing for now.
8340 
8341  // Dummy set max_error to 0
8342  max_error = 0.0;
8343  return;
8344  }
8345 
8346  //=================================================================
8347  /// Internal function to set up the hanging nodes on a particular
8348  /// edge of the element. Implements the mortar method.
8349  //=================================================================
8350  template<unsigned INITIAL_NNODE_1D>
8352  const int& value_id, const int& my_face, std::ofstream& output_hangfile)
8353  {
8354  using namespace OcTreeNames;
8355 
8356  Vector<unsigned> translate_s(3);
8357  Vector<double> s_lo_neigh(3);
8358  Vector<double> s_hi_neigh(3);
8359  int neigh_face, diff_level;
8360  bool in_neighbouring_tree;
8361 
8362  // Find pointer to neighbour in this direction
8363  OcTree* neigh_pt;
8364  neigh_pt = this->octree_pt()->gteq_face_neighbour(my_face,
8365  translate_s,
8366  s_lo_neigh,
8367  s_hi_neigh,
8368  neigh_face,
8369  diff_level,
8370  in_neighbouring_tree);
8371 
8372  // Work out master/dependent faces
8373  //----------------------------
8374 
8375  // Set up booleans
8376  // bool h_type_master = false;
8377  bool h_type_dependent = false;
8378  // bool p_type_master = false;
8379  bool p_type_dependent = false;
8380 
8381  // Neighbour exists
8382  if (neigh_pt != 0)
8383  {
8384  // Check if neighbour is bigger than me
8385  if (diff_level != 0)
8386  {
8387  // Dependent at h-type non-conformity
8388  h_type_dependent = true;
8389  }
8390  // Check if neighbour is the same size as me
8391  else if (neigh_pt->nsons() == 0)
8392  {
8393  // Neighbour is same size as me
8394  // Find p-orders of each element
8395  unsigned my_p_order =
8396  dynamic_cast<PRefineableQElement<3, INITIAL_NNODE_1D>*>(this)
8397  ->p_order();
8398  unsigned neigh_p_order =
8400  neigh_pt->object_pt())
8401  ->p_order();
8402 
8403  // Check for p-type non-conformity
8404  if (neigh_p_order == my_p_order)
8405  {
8406  // At a conforming interface
8407  }
8408  else if (neigh_p_order < my_p_order)
8409  {
8410  // Dependent at p-type non-conformity
8411  p_type_dependent = true;
8412  }
8413  else
8414  {
8415  // Master at p-type non-conformity
8416  // p_type_master = true;
8417  }
8418  }
8419  // Neighbour must be smaller than me
8420  else
8421  {
8422  // Master at h-type non-conformity
8423  // h_type_master = true;
8424  }
8425  }
8426  else
8427  {
8428  // Face is on a boundary
8429  }
8430 
8431  // Work out master/dependent edges
8432  //----------------------------
8433  if (h_type_dependent || p_type_dependent || true)
8434  {
8435  // Get edges of face and the face that shares that edge
8436  Vector<unsigned> face_edge(4), face_edge_other_face(4);
8437  switch (my_face)
8438  {
8439  case L:
8440  face_edge[0] = LB;
8441  face_edge_other_face[0] = B;
8442  face_edge[1] = LF;
8443  face_edge_other_face[1] = F;
8444  face_edge[2] = LD;
8445  face_edge_other_face[2] = D;
8446  face_edge[3] = LU;
8447  face_edge_other_face[3] = U;
8448  break;
8449  case R:
8450  face_edge[0] = RB;
8451  face_edge_other_face[0] = B;
8452  face_edge[1] = RF;
8453  face_edge_other_face[1] = F;
8454  face_edge[2] = RD;
8455  face_edge_other_face[2] = D;
8456  face_edge[3] = RU;
8457  face_edge_other_face[3] = U;
8458  break;
8459  case U:
8460  face_edge[0] = UB;
8461  face_edge_other_face[0] = B;
8462  face_edge[1] = UF;
8463  face_edge_other_face[1] = F;
8464  face_edge[2] = LU;
8465  face_edge_other_face[2] = L;
8466  face_edge[3] = RU;
8467  face_edge_other_face[3] = R;
8468  break;
8469  case D:
8470  face_edge[0] = DB;
8471  face_edge_other_face[0] = B;
8472  face_edge[1] = DF;
8473  face_edge_other_face[1] = F;
8474  face_edge[2] = LD;
8475  face_edge_other_face[2] = L;
8476  face_edge[3] = RD;
8477  face_edge_other_face[3] = R;
8478  break;
8479  case B:
8480  face_edge[0] = DB;
8481  face_edge_other_face[0] = D;
8482  face_edge[1] = UB;
8483  face_edge_other_face[1] = U;
8484  face_edge[2] = LB;
8485  face_edge_other_face[2] = L;
8486  face_edge[3] = RB;
8487  face_edge_other_face[3] = R;
8488  break;
8489  case F:
8490  face_edge[0] = DF;
8491  face_edge_other_face[0] = D;
8492  face_edge[1] = UF;
8493  face_edge_other_face[1] = U;
8494  face_edge[2] = LF;
8495  face_edge_other_face[2] = L;
8496  face_edge[3] = RF;
8497  face_edge_other_face[3] = R;
8498  break;
8499  default:
8500  throw OomphLibError(
8501  "my_face not L, R, D, U, B, F\n",
8502  "PRefineableQElement<3,INITIAL_NNODE_1D>::oc_hang_helper()",
8503  OOMPH_EXCEPTION_LOCATION);
8504  }
8505 
8506  // Loop over edges of face
8507  for (unsigned i = 0; i < 4; i++)
8508  {
8509  // Get edge
8510  unsigned my_edge = face_edge[i];
8511 
8512  // Separate storage for edge mortaring
8513  OcTree* edge_neigh_pt = 0;
8514  Vector<unsigned> edge_translate_s(3);
8515  Vector<double> edge_s_lo_neigh(3);
8516  Vector<double> edge_s_hi_neigh(3);
8517  int neigh_edge = 0, edge_diff_level = 0;
8518  unsigned edge_p_order =
8519  dynamic_cast<PRefineableQElement<3, INITIAL_NNODE_1D>*>(this)
8520  ->p_order();
8521 
8522  // Temporary storage to keep track of master edge
8523  Vector<unsigned> tmp_edge_translate_s(3);
8524  Vector<double> tmp_edge_s_lo_neigh(3);
8525  Vector<double> tmp_edge_s_hi_neigh(3);
8526  int tmp_neigh_edge, tmp_edge_diff_level;
8527 
8528  // Initially return the zero-th true edge neighbour
8529  unsigned i_root_edge_neighbour = 0;
8530 
8531  // Initialise the total number of true edge neighbours
8532  unsigned nroot_edge_neighbour = 0;
8533 
8534  // Flag to keep track of master status of my_edge
8535  bool my_edge_is_master = true;
8536  // unsigned master_edge_index=0;
8537 
8538  // Keep searching until we've found the node or until we've checked
8539  // all available edge neighbours
8540  bool keep_searching = true;
8541  bool search_faces = false;
8542  bool first_face_searched = false;
8543  // unsigned index=0;
8544  while (keep_searching)
8545  {
8546  // Pointer to edge neighbouring OcTree
8547  OcTree* tmp_edge_neigh_pt;
8548 
8549  // Looking in edge neighbours that are also face neighbours
8550  // if(index==0 || index==1)
8551  if (search_faces)
8552  {
8553  if (!first_face_searched)
8554  {
8555  // Find pointer to neighbour in this direction
8556  tmp_edge_neigh_pt =
8557  this->octree_pt()->gteq_face_neighbour(my_face,
8558  tmp_edge_translate_s,
8559  tmp_edge_s_lo_neigh,
8560  tmp_edge_s_hi_neigh,
8561  tmp_neigh_edge,
8562  tmp_edge_diff_level,
8563  in_neighbouring_tree);
8564 
8565  // Mark first face as searched
8566  first_face_searched = true;
8567  }
8568  else
8569  {
8570  // Find pointer to neighbour in this direction
8571  tmp_edge_neigh_pt =
8572  this->octree_pt()->gteq_face_neighbour(face_edge_other_face[i],
8573  tmp_edge_translate_s,
8574  tmp_edge_s_lo_neigh,
8575  tmp_edge_s_hi_neigh,
8576  tmp_neigh_edge,
8577  tmp_edge_diff_level,
8578  in_neighbouring_tree);
8579 
8580  // Search is finally exhausted
8581  keep_searching = false;
8582  }
8583  }
8584  // Looking in a true edge neighbour
8585  else
8586  {
8587  // Find pointer to neighbour in this direction
8588  tmp_edge_neigh_pt =
8589  this->octree_pt()->gteq_true_edge_neighbour(my_edge,
8590  i_root_edge_neighbour,
8591  nroot_edge_neighbour,
8592  tmp_edge_translate_s,
8593  tmp_edge_s_lo_neigh,
8594  tmp_edge_s_hi_neigh,
8595  tmp_neigh_edge,
8596  tmp_edge_diff_level);
8597  }
8598 
8599  // Set up booleans
8600  // bool h_type_edge_master = false;
8601  // bool h_type_edge_dependent = false;
8602  // bool p_type_edge_master = false;
8603  // bool p_type_edge_dependent = false;
8604 
8605  // Flag to check if we have a new edge master
8606  bool new_edge_master = false;
8607 
8608  // Edge neighbour exists
8609  if (tmp_edge_neigh_pt != 0)
8610  {
8611  // Check if neighbour is bigger than my biggest neighbour
8612  if (tmp_edge_diff_level < edge_diff_level)
8613  {
8614  // Dependent at h-type non-conformity
8615  // h_type_edge_dependent = true;
8616  new_edge_master = true;
8617  // Update edge_diff_level and p-order
8618  edge_diff_level = tmp_edge_diff_level;
8619  edge_p_order =
8621  tmp_edge_neigh_pt->object_pt())
8622  ->p_order();
8623  }
8624  // Check if neighbour is the same size as my biggest neighbour
8625  else if (tmp_edge_diff_level == edge_diff_level &&
8626  tmp_edge_neigh_pt->nsons() == 0)
8627  {
8628  // Neighbour is same size as me
8629  // Find p-orders of each element
8630  // unsigned my_p_order =
8631  // dynamic_cast<PRefineableQElement<3,INITIAL_NNODE_1D>*>
8632  // (this)->p_order();
8633  unsigned tmp_edge_neigh_p_order =
8635  tmp_edge_neigh_pt->object_pt())
8636  ->p_order();
8637 
8638  // Check for p-type non-conformity
8639  if (tmp_edge_neigh_p_order == edge_p_order)
8640  {
8641  // At a conforming interface
8642  }
8643  else if (tmp_edge_neigh_p_order < edge_p_order)
8644  {
8645  // Dependent at p-type non-conformity
8646  // p_type_edge_dependent = true;
8647  new_edge_master = true;
8648  // Update edge_diff_level and p-order
8649  edge_diff_level = tmp_edge_diff_level;
8650  edge_p_order =
8652  tmp_edge_neigh_pt->object_pt())
8653  ->p_order();
8654  }
8655  else
8656  {
8657  // Master at p-type non-conformity
8658  // p_type_edge_master = true;
8659  }
8660  }
8661  // Neighbour must be smaller than me
8662  else
8663  {
8664  // Master at h-type non-conformity
8665  // h_type_edge_master = true;
8666  }
8667  }
8668  else
8669  {
8670  // Edge is on a boundary
8671  }
8672 
8673  // Update master neighbour information
8674  if (new_edge_master)
8675  {
8676  // Store new master edge information
8677  edge_neigh_pt = tmp_edge_neigh_pt;
8678  edge_translate_s = tmp_edge_translate_s;
8679  edge_s_lo_neigh = tmp_edge_s_lo_neigh;
8680  edge_s_hi_neigh = tmp_edge_s_hi_neigh;
8681  neigh_edge = tmp_neigh_edge;
8682  edge_diff_level = tmp_edge_diff_level;
8683 
8684  // Set this edge as dependent
8685  my_edge_is_master = false;
8686  }
8687 
8688  // Keep searching, but only if there are further edge neighbours
8689  // Try next root edge neighbour
8690  i_root_edge_neighbour++;
8691 
8692  // Increment counter
8693  // index++;
8694 
8695  // Have we exhausted the search over true edge neighbours
8696  // if (index>2 && i_root_edge_neighbour>=nroot_edge_neighbour)
8697  if (i_root_edge_neighbour >= nroot_edge_neighbour)
8698  {
8699  // keep_searching = false;
8700  // Extend search to face neighours (these are edge neighbours too)
8701  search_faces = true;
8702  }
8703 
8704  } // End of while keep searching over all face and true edge neighbours
8705 
8706  // Now do edge mortaring to enforce the mortar vertex matching condition
8707  if (!my_edge_is_master)
8708  {
8709  // Compute the active coordinate index along the this side of mortar
8710  unsigned active_coord_index;
8711  switch (my_edge)
8712  {
8713  case DB:
8714  case DF:
8715  case UB:
8716  case UF:
8717  active_coord_index = 0;
8718  break;
8719  case LB:
8720  case RB:
8721  case LF:
8722  case RF:
8723  active_coord_index = 1;
8724  break;
8725  case LD:
8726  case RD:
8727  case LU:
8728  case RU:
8729  active_coord_index = 2;
8730  break;
8731  default:
8732  throw OomphLibError(
8733  "Cannot transform coordinates",
8734  "PRefineableQElement<3,INITIAL_NNODE_1D>::oc_hang_helper()",
8735  OOMPH_EXCEPTION_LOCATION);
8736  }
8737 
8738  // Get pointer to neighbouring master element (in p-refineable form)
8739  PRefineableQElement<3, INITIAL_NNODE_1D>* edge_neigh_obj_pt;
8740  edge_neigh_obj_pt =
8742  edge_neigh_pt->object_pt());
8743 
8744  // Create vector of master and dependent nodes
8745  //----------------------------------------
8746  Vector<Node*> master_node_pt, dependent_node_pt;
8747  Vector<unsigned> master_node_number, dependent_node_number;
8748  Vector<Vector<double>> dependent_node_s_fraction;
8749 
8750  // Number of nodes in one dimension
8751  const unsigned my_n_p = this->ninterpolating_node_1d(value_id);
8752  const unsigned neigh_n_p =
8753  edge_neigh_obj_pt->ninterpolating_node_1d(value_id);
8754 
8755  // Storage for pointers to the nodes and their numbers along the
8756  // master edge
8757  unsigned neighbour_node_number = 0;
8758  Node* neighbour_node_pt = 0;
8759 
8760  // Loop over nodes along the edge
8761  bool master_is_not_edge = false;
8762  for (unsigned i0 = 0; i0 < neigh_n_p; i0++)
8763  {
8764  const unsigned s0space = 1;
8765  const unsigned s1space = neigh_n_p;
8766  const unsigned s2space = neigh_n_p * neigh_n_p;
8767 
8768  // Find the neighbour's node
8769  switch (neigh_edge)
8770  {
8771  case DB:
8772  neighbour_node_number = i0 * s0space;
8773  neighbour_node_pt = edge_neigh_obj_pt->interpolating_node_pt(
8774  neighbour_node_number, value_id);
8775  break;
8776  case UB:
8777  neighbour_node_number =
8778  (neigh_n_p - 1) * s1space + i0 * s0space;
8779  neighbour_node_pt = edge_neigh_obj_pt->interpolating_node_pt(
8780  neighbour_node_number, value_id);
8781  break;
8782  case DF:
8783  neighbour_node_number =
8784  (neigh_n_p - 1) * s2space + i0 * s0space;
8785  neighbour_node_pt = edge_neigh_obj_pt->interpolating_node_pt(
8786  neighbour_node_number, value_id);
8787  break;
8788  case UF:
8789  neighbour_node_number = (neigh_n_p - 1) * s1space +
8790  (neigh_n_p - 1) * s2space +
8791  i0 * s0space;
8792  neighbour_node_pt = edge_neigh_obj_pt->interpolating_node_pt(
8793  neighbour_node_number, value_id);
8794  break;
8795 
8796  case LB:
8797  neighbour_node_number = i0 * s1space;
8798  neighbour_node_pt = edge_neigh_obj_pt->interpolating_node_pt(
8799  neighbour_node_number, value_id);
8800  break;
8801  case RB:
8802  neighbour_node_number =
8803  (neigh_n_p - 1) * s0space + i0 * s1space;
8804  neighbour_node_pt = edge_neigh_obj_pt->interpolating_node_pt(
8805  neighbour_node_number, value_id);
8806  break;
8807  case LF:
8808  neighbour_node_number =
8809  (neigh_n_p - 1) * s2space + i0 * s1space;
8810  neighbour_node_pt = edge_neigh_obj_pt->interpolating_node_pt(
8811  neighbour_node_number, value_id);
8812  break;
8813  case RF:
8814  neighbour_node_number = (neigh_n_p - 1) * s0space +
8815  (neigh_n_p - 1) * s2space +
8816  i0 * s1space;
8817  neighbour_node_pt = edge_neigh_obj_pt->interpolating_node_pt(
8818  neighbour_node_number, value_id);
8819  break;
8820 
8821  case LD:
8822  neighbour_node_number = i0 * s2space;
8823  neighbour_node_pt = edge_neigh_obj_pt->interpolating_node_pt(
8824  neighbour_node_number, value_id);
8825  break;
8826  case RD:
8827  neighbour_node_number =
8828  (neigh_n_p - 1) * s0space + i0 * s2space;
8829  neighbour_node_pt = edge_neigh_obj_pt->interpolating_node_pt(
8830  neighbour_node_number, value_id);
8831  break;
8832  case LU:
8833  neighbour_node_number =
8834  (neigh_n_p - 1) * s1space + i0 * s2space;
8835  neighbour_node_pt = edge_neigh_obj_pt->interpolating_node_pt(
8836  neighbour_node_number, value_id);
8837  break;
8838  case RU:
8839  neighbour_node_number = (neigh_n_p - 1) * s0space +
8840  (neigh_n_p - 1) * s1space +
8841  i0 * s2space;
8842  neighbour_node_pt = edge_neigh_obj_pt->interpolating_node_pt(
8843  neighbour_node_number, value_id);
8844  break;
8845 
8846  default:
8847  // Master 'edge' may be a face instead, so no need to throw an
8848  // error
8849  master_is_not_edge = true;
8850  }
8851 
8852  if (master_is_not_edge) break;
8853 
8854  // Set node as master node
8855  master_node_number.push_back(neighbour_node_number);
8856  master_node_pt.push_back(neighbour_node_pt);
8857  }
8858 
8859  // Now if edge is really a face (from an edge neighbour that isn't
8860  // a true edge neighbour) each node on the face is (potentially) a
8861  // master
8862  if (master_is_not_edge)
8863  {
8864  // Loop over nodes along the face
8865  for (unsigned i0 = 0; i0 < neigh_n_p; i0++)
8866  {
8867  // Loop over nodes along the face
8868  for (unsigned i1 = 0; i1 < neigh_n_p; i1++)
8869  {
8870  const unsigned s0space = 1;
8871  const unsigned s1space = neigh_n_p;
8872  const unsigned s2space = neigh_n_p * neigh_n_p;
8873 
8874  // Find the neighbour's node
8875  switch (neigh_edge)
8876  {
8877  case B:
8878  neighbour_node_number = i0 * s0space + i1 * s1space;
8879  neighbour_node_pt =
8880  edge_neigh_obj_pt->interpolating_node_pt(
8881  neighbour_node_number, value_id);
8882  break;
8883  case F:
8884  neighbour_node_number =
8885  (neigh_n_p - 1) * s2space + i0 * s0space + i1 * s1space;
8886  neighbour_node_pt =
8887  edge_neigh_obj_pt->interpolating_node_pt(
8888  neighbour_node_number, value_id);
8889  break;
8890  case D:
8891  neighbour_node_number = i0 * s0space + i1 * s2space;
8892  neighbour_node_pt =
8893  edge_neigh_obj_pt->interpolating_node_pt(
8894  neighbour_node_number, value_id);
8895  break;
8896  case U:
8897  neighbour_node_number =
8898  (neigh_n_p - 1) * s1space + i0 * s0space + i1 * s2space;
8899  neighbour_node_pt =
8900  edge_neigh_obj_pt->interpolating_node_pt(
8901  neighbour_node_number, value_id);
8902  break;
8903  case L:
8904  neighbour_node_number = i0 * s1space + i1 * s2space;
8905  neighbour_node_pt =
8906  edge_neigh_obj_pt->interpolating_node_pt(
8907  neighbour_node_number, value_id);
8908  break;
8909  case R:
8910  neighbour_node_number =
8911  (neigh_n_p - 1) * s0space + i0 * s1space + i1 * s2space;
8912  neighbour_node_pt =
8913  edge_neigh_obj_pt->interpolating_node_pt(
8914  neighbour_node_number, value_id);
8915  break;
8916 
8917  default:
8918  throw OomphLibError("neigh_edge not recognised\n",
8919  "PRefineableQElement<3,INITIAL_NNODE_"
8920  "1D>::oc_hang_helper()",
8921  OOMPH_EXCEPTION_LOCATION);
8922  }
8923 
8924  // Set node as master node
8925  master_node_number.push_back(neighbour_node_number);
8926  master_node_pt.push_back(neighbour_node_pt);
8927  }
8928  }
8929  }
8930 
8931  // Storage for pointers to the local nodes and their numbers along my
8932  // edge
8933  unsigned local_node_number = 0;
8934  Node* local_node_pt = 0;
8935 
8936  // Loop over the nodes along my edge
8937  for (unsigned i0 = 0; i0 < my_n_p; i0++)
8938  {
8939  // Storage for the fractional position of the node in the element
8940  Vector<double> s_fraction(3);
8941 
8942  const unsigned s0space = 1;
8943  const unsigned s1space = my_n_p;
8944  const unsigned s2space = my_n_p * my_n_p;
8945 
8946  // Find the local node and the fractional position of the node
8947  // which depends on the edge, of course
8948  switch (my_edge)
8949  {
8950  case DB:
8951  s_fraction[0] =
8952  local_one_d_fraction_of_interpolating_node(i0, 0, value_id);
8953  s_fraction[1] = 0.0;
8954  s_fraction[2] = 0.0;
8955  local_node_number = i0 * s0space;
8956  local_node_pt =
8957  this->interpolating_node_pt(local_node_number, value_id);
8958  break;
8959  case UB:
8960  s_fraction[0] =
8961  local_one_d_fraction_of_interpolating_node(i0, 0, value_id);
8962  s_fraction[1] = 1.0;
8963  s_fraction[2] = 0.0;
8964  local_node_number = (my_n_p - 1) * s1space + i0 * s0space;
8965  local_node_pt =
8966  this->interpolating_node_pt(local_node_number, value_id);
8967  break;
8968  case DF:
8969  s_fraction[0] =
8970  local_one_d_fraction_of_interpolating_node(i0, 0, value_id);
8971  s_fraction[1] = 0.0;
8972  s_fraction[2] = 1.0;
8973  local_node_number = (my_n_p - 1) * s2space + i0 * s0space;
8974  local_node_pt =
8975  this->interpolating_node_pt(local_node_number, value_id);
8976  break;
8977  case UF:
8978  s_fraction[0] =
8979  local_one_d_fraction_of_interpolating_node(i0, 0, value_id);
8980  s_fraction[1] = 1.0;
8981  s_fraction[2] = 1.0;
8982  local_node_number = (my_n_p - 1) * s1space +
8983  (my_n_p - 1) * s2space + i0 * s0space;
8984  local_node_pt =
8985  this->interpolating_node_pt(local_node_number, value_id);
8986  break;
8987 
8988  case LB:
8989  s_fraction[0] = 0.0;
8990  s_fraction[1] =
8991  local_one_d_fraction_of_interpolating_node(i0, 1, value_id);
8992  s_fraction[2] = 0.0;
8993  local_node_number = i0 * s1space;
8994  local_node_pt =
8995  this->interpolating_node_pt(local_node_number, value_id);
8996  break;
8997  case RB:
8998  s_fraction[0] = 1.0;
8999  s_fraction[1] =
9000  local_one_d_fraction_of_interpolating_node(i0, 1, value_id);
9001  s_fraction[2] = 0.0;
9002  local_node_number = (my_n_p - 1) * s0space + i0 * s1space;
9003  local_node_pt =
9004  this->interpolating_node_pt(local_node_number, value_id);
9005  break;
9006  case LF:
9007  s_fraction[0] = 0.0;
9008  s_fraction[1] =
9009  local_one_d_fraction_of_interpolating_node(i0, 1, value_id);
9010  s_fraction[2] = 1.0;
9011  local_node_number = (my_n_p - 1) * s2space + i0 * s1space;
9012  local_node_pt =
9013  this->interpolating_node_pt(local_node_number, value_id);
9014  break;
9015  case RF:
9016  s_fraction[0] = 1.0;
9017  s_fraction[1] =
9018  local_one_d_fraction_of_interpolating_node(i0, 1, value_id);
9019  s_fraction[2] = 1.0;
9020  local_node_number = (my_n_p - 1) * s0space +
9021  (my_n_p - 1) * s2space + i0 * s1space;
9022  local_node_pt =
9023  this->interpolating_node_pt(local_node_number, value_id);
9024  break;
9025 
9026  case LD:
9027  s_fraction[0] = 0.0;
9028  s_fraction[1] = 0.0;
9029  s_fraction[2] =
9030  local_one_d_fraction_of_interpolating_node(i0, 2, value_id);
9031  local_node_number = i0 * s2space;
9032  local_node_pt =
9033  this->interpolating_node_pt(local_node_number, value_id);
9034  break;
9035  case RD:
9036  s_fraction[0] = 1.0;
9037  s_fraction[1] = 0.0;
9038  s_fraction[2] =
9039  local_one_d_fraction_of_interpolating_node(i0, 2, value_id);
9040  local_node_number = (my_n_p - 1) * s0space + i0 * s2space;
9041  local_node_pt =
9042  this->interpolating_node_pt(local_node_number, value_id);
9043  break;
9044  case LU:
9045  s_fraction[0] = 0.0;
9046  s_fraction[1] = 1.0;
9047  s_fraction[2] =
9048  local_one_d_fraction_of_interpolating_node(i0, 2, value_id);
9049  local_node_number = (my_n_p - 1) * s1space + i0 * s2space;
9050  local_node_pt =
9051  this->interpolating_node_pt(local_node_number, value_id);
9052  break;
9053  case RU:
9054  s_fraction[0] = 1.0;
9055  s_fraction[1] = 1.0;
9056  s_fraction[2] =
9057  local_one_d_fraction_of_interpolating_node(i0, 2, value_id);
9058  local_node_number = (my_n_p - 1) * s0space +
9059  (my_n_p - 1) * s1space + i0 * s2space;
9060  local_node_pt =
9061  this->interpolating_node_pt(local_node_number, value_id);
9062  break;
9063 
9064  default:
9065  throw OomphLibError(
9066  "my_edge not recognised\n",
9067  "PRefineableQElement<3,INITIAL_NNODE_1D>::oc_hang_helper()",
9068  OOMPH_EXCEPTION_LOCATION);
9069  }
9070 
9071  // Add node to vector of dependent element nodes
9072  dependent_node_number.push_back(local_node_number);
9073  dependent_node_pt.push_back(local_node_pt);
9074 
9075  // Store node's local fraction
9076  dependent_node_s_fraction.push_back(s_fraction);
9077  }
9078 
9079  // Store the number of dependent and master nodes for use later
9080  const unsigned n_dependent_nodes = dependent_node_pt.size();
9081  const unsigned n_master_nodes = master_node_pt.size();
9082  const unsigned dependent_element_nnode_1d = my_n_p;
9083  const unsigned master_element_nnode_1d = neigh_n_p;
9084 
9085  // Storage for master shapes
9086  Shape master_shapes(edge_neigh_obj_pt->ninterpolating_node(value_id));
9087 
9088  // Get master and dependent nodal positions
9089  //-------------------------------------
9090  Vector<double> dependent_nodal_position;
9091  Vector<double> dependent_weight(dependent_element_nnode_1d);
9092  Orthpoly::gll_nodes(dependent_element_nnode_1d,
9093  dependent_nodal_position,
9094  dependent_weight);
9095  Vector<double> master_nodal_position;
9096  Vector<double> master_weight(master_element_nnode_1d);
9098  master_element_nnode_1d, master_nodal_position, master_weight);
9099 
9100  // Apply the (1D) vertex matching condition
9101  //-----------------------------------------
9102  // Vertiex matching is ensured automatically in cases where there is a
9103  // node at each end of the mortar that is shared between the master
9104  // and dependent elements. Where this is not the case, the vertex
9105  // matching condition must be enforced by constraining the value of
9106  // the unknown at the node on the dependent side to be the same as the
9107  // value at that location in the master.
9108 
9109  // Store positions of the mortar vertex/non-vertex nodes in the
9110  // dependent element
9111  const unsigned n_mortar_vertices = 2;
9112  Vector<unsigned> vertex_pos(n_mortar_vertices);
9113  vertex_pos[0] = 0;
9114  vertex_pos[1] = this->ninterpolating_node_1d(value_id) - 1;
9115  Vector<unsigned> non_vertex_pos(my_n_p - n_mortar_vertices);
9116  for (unsigned i = 0; i < my_n_p - n_mortar_vertices; i++)
9117  {
9118  non_vertex_pos[i] = i + 1;
9119  }
9120 
9121  // If the node is on a master edge, we may be setting the
9122  // hanging info incorrectly. Hanging schemes (if they are
9123  // required) for such nodes are instead computed by the
9124  // dependent edge. We dont't want to overwrite them here!
9125  std::vector<bool> mortar_vertex_on_master_edge(n_mortar_vertices);
9126  for (unsigned v = 0; v < n_mortar_vertices; v++)
9127  {
9128  // Check if each node is on the master edge
9129  mortar_vertex_on_master_edge[v] = true;
9130  unsigned non_extreme_coordinate = 0;
9131  Vector<double> s_in_neigh(3);
9132  for (unsigned i = 0; i < 3; i++)
9133  {
9134  // Work out this node's location in the master
9135  s_in_neigh[i] =
9136  edge_s_lo_neigh[i] +
9137  dependent_node_s_fraction[vertex_pos[v]][edge_translate_s[i]] *
9138  (edge_s_hi_neigh[i] - edge_s_lo_neigh[i]);
9139 
9140  // Check if local coordinate in master element takes non-extreme
9141  // value
9142  if (std::fabs(std::fabs(s_in_neigh[i]) - 1.0) > 1.0e-14)
9143  {
9144  non_extreme_coordinate++;
9145  if (non_extreme_coordinate > 1)
9146  {
9147  mortar_vertex_on_master_edge[v] = false;
9148  break;
9149  }
9150  }
9151  }
9152  }
9153 
9154  // Now work out if my edge coincides with the master edge
9155  bool my_edge_coincides_with_master = true;
9156  for (unsigned v = 0; v < n_mortar_vertices; v++)
9157  {
9158  my_edge_coincides_with_master =
9159  my_edge_coincides_with_master && mortar_vertex_on_master_edge[v];
9160  }
9161 
9162  // Check if we need to apply the (1D) vertex matching condition at the
9163  // mortar vertices. This is trivially satisfied if the node is shared
9164  // with the master, but if not then we need to constrain it.
9165  for (unsigned v = 0; v < n_mortar_vertices; v++)
9166  {
9167  // Don't make hanging node if my edge doesn't coincide with
9168  // the master edge *and* this node is on the master edge!
9169  // (We are not in a position to determine its hanging status.)
9170  if ((!my_edge_coincides_with_master) &&
9171  mortar_vertex_on_master_edge[v])
9172  continue;
9173 
9174  // Search master node storage for the node
9175  bool node_is_shared = false;
9176  for (unsigned i = 0; i < master_node_pt.size(); i++)
9177  {
9178  if (dependent_node_pt[vertex_pos[v]] == master_node_pt[i])
9179  {
9180  node_is_shared = true;
9181  break;
9182  }
9183  }
9184 
9185  // If the node is not shared then we must constrain its value by
9186  // setting up a hanging scheme
9187  if (!node_is_shared)
9188  {
9189  // Calculate weights. These are just the master shapes evaluated
9190  // at this dependent node's position
9191 
9192  // Work out this node's location in the master
9193  Vector<double> s_in_neigh(3);
9194  for (unsigned i = 0; i < 3; i++)
9195  {
9196  s_in_neigh[i] = edge_s_lo_neigh[i] +
9197  dependent_node_s_fraction[vertex_pos[v]]
9198  [edge_translate_s[i]] *
9199  (edge_s_hi_neigh[i] - edge_s_lo_neigh[i]);
9200  }
9201 
9202  // Get master shapes at dependent nodal positions
9203  edge_neigh_obj_pt->interpolating_basis(
9204  s_in_neigh, master_shapes, value_id);
9205 
9206  // Remove any existing hanging node info
9207  // (This may be a bit wasteful, but guarantees correctness)
9208  dependent_node_pt[vertex_pos[v]]->set_nonhanging();
9209 
9210  // Don't include master nodes with zero weights
9211  Vector<unsigned> master_node_zero_weight;
9212  for (unsigned m = 0; m < n_master_nodes; m++)
9213  {
9214  // Compare weights to some (small) tolerance
9215  if (std::fabs(master_shapes[master_node_number[m]]) < 1.0e-14)
9216  {
9217  // Store
9218  master_node_zero_weight.push_back(m);
9219  }
9220  }
9221 
9222  // Set up hanging scheme for this node
9223  HangInfo* explicit_hang_pt =
9224  new HangInfo(n_master_nodes - master_node_zero_weight.size());
9225  unsigned mindex = 0;
9226  for (unsigned m = 0; m < n_master_nodes; m++)
9227  {
9228  // Check that master doesn't have zero weight
9229  bool skip = false;
9230  for (unsigned i = 0; i < master_node_zero_weight.size(); i++)
9231  {
9232  if (m == master_node_zero_weight[i]) skip = true;
9233  }
9234 
9235  // Add pointer and weight to hang info
9236  if (!skip)
9237  explicit_hang_pt->set_master_node_pt(
9238  mindex++,
9239  master_node_pt[m],
9240  master_shapes[master_node_number[m]]);
9241  }
9242 
9243  /// / Set up hanging scheme for this node
9244  // HangInfo* explicit_hang_pt = new HangInfo(n_master_nodes);
9245  // for(unsigned m=0; m<n_master_nodes; m++)
9246  // {
9247  // explicit_hang_pt->set_master_node_pt(m,master_node_pt[m],master_shapes[master_node_number[m]]);
9248  // }
9249 
9250  // Make node hang
9251  dependent_node_pt[vertex_pos[v]]->set_hanging_pt(explicit_hang_pt,
9252  -1);
9253 
9254  /// / Print out hanging scheme
9255  // std::cout << "Hanging node: "
9256  // << dependent_node_pt[vertex_pos[v]]->x(0) << " "
9257  // << dependent_node_pt[vertex_pos[v]]->x(1) << " "
9258  // << dependent_node_pt[vertex_pos[v]]->x(2) << " "
9259  // << std::endl;
9260  // for(unsigned m=0; m<explicit_hang_pt->nmaster(); m++)
9261  // {
9262  // std::cout << " m = " << m << ": "
9263  // << explicit_hang_pt->master_node_pt(m)->x(0) << " "
9264  // << explicit_hang_pt->master_node_pt(m)->x(1) << " "
9265  // << explicit_hang_pt->master_node_pt(m)->x(2) << " "
9266  // << "w = " << explicit_hang_pt->master_weight(m) << "
9267  // "
9268  // << std::endl;
9269  // }
9270 
9271  // Check there are no zero weights at this stage
9272  for (unsigned m = 0; m < explicit_hang_pt->nmaster(); m++)
9273  {
9274  if (std::fabs(explicit_hang_pt->master_weight(m)) < 1.0e-14)
9275  {
9276  throw OomphLibError(
9277  "Master has zero weight!",
9278  "PRefineableQElement<3,INITIAL_NNODE_1D>::oc_hang_helper()",
9279  OOMPH_EXCEPTION_LOCATION);
9280  }
9281  }
9282  }
9283  }
9284 
9285  // Check that there are actually dependent nodes for which we still
9286  // need to construct a hanging scheme. If not then there is nothing
9287  // more to do.
9288  if (n_dependent_nodes - n_mortar_vertices > 0)
9289  {
9290  // Assemble mass matrix for mortar
9291  //--------------------------------
9292  Vector<double> psi(n_dependent_nodes - n_mortar_vertices);
9293  Vector<double> diag_M(n_dependent_nodes - n_mortar_vertices);
9294  Vector<Vector<double>> shared_node_M(n_mortar_vertices);
9295  for (unsigned i = 0; i < shared_node_M.size(); i++)
9296  {
9297  shared_node_M[i].resize(n_dependent_nodes - n_mortar_vertices);
9298  }
9299 
9300  // Fill in part corresponding to dependent nodal positions (unknown)
9301  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
9302  {
9303  // Use L'Hosptal's rule:
9304  psi[i] =
9305  pow(-1.0, int((dependent_element_nnode_1d - 1) - i - 1)) *
9307  dependent_element_nnode_1d - 1,
9308  dependent_nodal_position[non_vertex_pos[i]]);
9309  // Put in contribution
9310  diag_M[i] = psi[i] * dependent_weight[non_vertex_pos[i]];
9311  }
9312 
9313  // Fill in part corresponding to dependent element vertices (known)
9314  for (unsigned v = 0; v < shared_node_M.size(); v++)
9315  {
9316  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices;
9317  i++)
9318  {
9319  // Check if denominator is zero
9320  if (std::fabs(dependent_nodal_position[non_vertex_pos[i]] -
9321  dependent_nodal_position[vertex_pos[v]]) >=
9322  1.0e-8)
9323  {
9324  // We're ok
9325  psi[i] =
9326  pow(-1.0, int((dependent_element_nnode_1d - 1) - i - 1)) *
9328  dependent_element_nnode_1d - 1,
9329  dependent_nodal_position[vertex_pos[v]]) /
9330  (dependent_nodal_position[non_vertex_pos[i]] -
9331  dependent_nodal_position[vertex_pos[v]]);
9332  }
9333  // Check if numerator is zero
9334  else if (std::fabs(Orthpoly::dlegendre(
9335  dependent_element_nnode_1d - 1,
9336  dependent_nodal_position[vertex_pos[v]])) < 1.0e-8)
9337  {
9338  // We can use l'hopital's rule
9339  psi[i] =
9340  pow(-1.0, int((dependent_element_nnode_1d - 1) - i - 1)) *
9342  dependent_element_nnode_1d - 1,
9343  dependent_nodal_position[non_vertex_pos[i]]);
9344  }
9345  else
9346  {
9347  // We can't use l'hopital's rule
9348  throw OomphLibError(
9349  "Cannot use l'Hopital's rule. Dividing by zero is not "
9350  "allowed!",
9351  "PRefineableQElement<3,INITIAL_NNODE_1D>::oc_hang_helper()",
9352  OOMPH_EXCEPTION_LOCATION);
9353  }
9354  // Put in contribution
9355  shared_node_M[v][i] = psi[i] * dependent_weight[vertex_pos[v]];
9356  }
9357  }
9358 
9359  // Assemble local projection matrix for mortar
9360  //--------------------------------------------
9361 
9362  // Have only one local projection matrix because there is just one
9363  // master
9364  Vector<Vector<double>> P(n_dependent_nodes - n_mortar_vertices);
9365  for (unsigned i = 0; i < P.size(); i++)
9366  {
9367  P[i].resize(n_master_nodes, 0.0);
9368  }
9369 
9370  // Storage for local coordinate
9371  Vector<double> s(3);
9372 
9373  // Sum contributions from master element shapes (quadrature).
9374  // The order of quadrature must be high enough to evaluate a
9375  // polynomial of order N_s + N_m - 3 exactly, where N_s =
9376  // n_dependent_nodes, N_m = n_master_nodes. (Use pointers for the
9377  // quadrature knots and weights so that data is not unnecessarily
9378  // copied)
9379  // unsigned quadrature_order =
9380  // std::max(dependent_element_nnode_1d,master_element_nnode_1d);
9381  Vector<double>*quadrature_knot, *quadrature_weight;
9382  if (dependent_element_nnode_1d >= master_element_nnode_1d)
9383  {
9384  // Use the same quadrature order as the dependent element (me)
9385  quadrature_knot = &dependent_nodal_position;
9386  quadrature_weight = &dependent_weight;
9387  }
9388  else
9389  {
9390  // Use the same quadrature order as the master element (neighbour)
9391  quadrature_knot = &master_nodal_position;
9392  quadrature_weight = &master_weight;
9393  }
9394 
9395  // Quadrature loop
9396  for (unsigned q = 0; q < (*quadrature_weight).size(); q++)
9397  {
9398  // Evaluate mortar test functions at the quadrature knots in the
9399  // dependent
9400  // s[active_coord_index] = (*quadrature_knot)[q];
9401  Vector<double> s_on_mortar(1);
9402  s_on_mortar[0] = (*quadrature_knot)[q];
9403 
9404  // Get psi
9405  for (unsigned k = 0; k < n_dependent_nodes - n_mortar_vertices;
9406  k++)
9407  {
9408  // Check if denominator is zero
9409  if (std::fabs(dependent_nodal_position[non_vertex_pos[k]] -
9410  s_on_mortar[0]) >= 1.0e-08)
9411  {
9412  // We're ok
9413  psi[k] =
9414  pow(-1.0, int((dependent_element_nnode_1d - 1) - k - 1)) *
9415  Orthpoly::dlegendre(dependent_element_nnode_1d - 1,
9416  s_on_mortar[0]) /
9417  (dependent_nodal_position[non_vertex_pos[k]] -
9418  s_on_mortar[0]);
9419  }
9420  // Check if numerator is zero
9421  else if (std::fabs(Orthpoly::dlegendre(
9422  dependent_element_nnode_1d - 1, s_on_mortar[0])) <
9423  1.0e-8)
9424  {
9425  // We can use l'Hopital's rule
9426  psi[k] =
9427  pow(-1.0, int((dependent_element_nnode_1d - 1) - k - 1)) *
9428  -Orthpoly::ddlegendre(dependent_element_nnode_1d - 1,
9429  s_on_mortar[0]);
9430  }
9431  else
9432  {
9433  // We can't use l'hopital's rule
9434  throw OomphLibError(
9435  "Cannot use l'Hopital's rule. Dividing by zero is not "
9436  "allowed!",
9437  "PRefineableQElement<3,INITIAL_NNODE_1D>::oc_hang_helper()",
9438  OOMPH_EXCEPTION_LOCATION);
9439  }
9440  }
9441 
9442  // Convert coordinate on mortar to local fraction in dependent
9443  // element
9444  Vector<double> s_fraction(3);
9445  for (unsigned i = 0; i < 3; i++)
9446  {
9447  s_fraction[i] = (i == active_coord_index) ?
9448  0.5 * (s_on_mortar[0] + 1.0) :
9449  dependent_node_s_fraction[vertex_pos[0]][i];
9450  }
9451 
9452  // Project active coordinate into master element
9453  Vector<double> s_in_neigh(3);
9454  for (unsigned i = 0; i < 3; i++)
9455  {
9456  s_in_neigh[i] = edge_s_lo_neigh[i] +
9457  s_fraction[edge_translate_s[i]] *
9458  (edge_s_hi_neigh[i] - edge_s_lo_neigh[i]);
9459  }
9460 
9461  // Evaluate master shapes at projections of local quadrature knots
9462  edge_neigh_obj_pt->interpolating_basis(
9463  s_in_neigh, master_shapes, value_id);
9464 
9465  // Populate local projection matrix
9466  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices;
9467  i++)
9468  {
9469  for (unsigned j = 0; j < n_master_nodes; j++)
9470  {
9471  P[i][j] += master_shapes[master_node_number[j]] * psi[i] *
9472  (*quadrature_weight)[q];
9473  }
9474  }
9475  }
9476 
9477  /// / Print out local projection matrix
9478  // std::cout << "P_e:" << std::endl;
9479  // for(unsigned i=0; i<P.size(); i++)
9480  // {
9481  // for(unsigned j=0; j<P[i].size(); j++)
9482  // {
9483  // std::cout << " " << P[i][j];
9484  // }
9485  // }
9486  // std::cout << std::endl;
9487 
9488  // Assemble global projection matrices for mortar
9489  //-----------------------------------------------
9490  // Need to subtract contributions from the "known unknowns"
9491  // corresponding to the nodes at the vertices of the mortar
9492 
9493  // Assemble contributions from mortar vertex nodes
9494  for (unsigned v = 0; v < n_mortar_vertices; v++)
9495  {
9496  // Convert coordinate on mortar to local fraction in dependent
9497  // element
9498  Vector<double> s_fraction(3);
9499  for (unsigned i = 0; i < 3; i++)
9500  {
9501  s_fraction[i] =
9502  (i == active_coord_index) ?
9503  0.5 * (dependent_nodal_position[vertex_pos[v]] + 1.0) :
9504  dependent_node_s_fraction[vertex_pos[0]][i];
9505  }
9506 
9507  // Project active coordinate into master element
9508  Vector<double> s_in_neigh(3);
9509  for (unsigned i = 0; i < 3; i++)
9510  {
9511  s_in_neigh[i] = edge_s_lo_neigh[i] +
9512  s_fraction[edge_translate_s[i]] *
9513  (edge_s_hi_neigh[i] - edge_s_lo_neigh[i]);
9514  }
9515 
9516  // Get master shapes at dependent nodal positions
9517  edge_neigh_obj_pt->interpolating_basis(
9518  s_in_neigh, master_shapes, value_id);
9519 
9520  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices;
9521  i++)
9522  {
9523  for (unsigned k = 0; k < n_master_nodes; k++)
9524  {
9525  P[i][k] -=
9526  master_shapes[master_node_number[k]] * shared_node_M[v][i];
9527  }
9528  }
9529  }
9530 
9531  /// / Print out global projection matrix
9532  // std::cout << "P:" << std::endl;
9533  // for(unsigned i=0; i<P.size(); i++)
9534  // {
9535  // for(unsigned j=0; j<P[i].size(); j++)
9536  // {
9537  // std::cout << " " << P[i][j];
9538  // }
9539  // std::cout << std::endl;
9540  // }
9541  // std::cout << std::endl;
9542 
9543  // Solve mortar system
9544  //--------------------
9545  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
9546  {
9547  for (unsigned j = 0; j < n_master_nodes; j++)
9548  {
9549  P[i][j] /= diag_M[i];
9550  }
9551  }
9552 
9553  /// / Print out solved global projection matrix
9554  // std::cout << "solved P:" << std::endl;
9555  // for(unsigned i=0; i<P.size(); i++)
9556  // {
9557  // for(unsigned j=0; j<P[i].size(); j++)
9558  // {
9559  // std::cout << " " << P[i][j];
9560  // }
9561  // std::cout << std::endl;
9562  // }
9563  // std::cout << std::endl;
9564 
9565  // Create and populate structures to hold the hanging info
9566  //--------------------------------------------------------
9567  Vector<HangInfo*> hang_info_pt(n_dependent_nodes);
9568  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
9569  {
9570  // Don't include master nodes with zero weights
9571  Vector<unsigned> master_node_zero_weight;
9572  for (unsigned m = 0; m < n_master_nodes; m++)
9573  {
9574  // Compare weights to some (small) tolerance
9575  if (std::fabs(P[i][m]) < 1.0e-14)
9576  {
9577  // Store
9578  master_node_zero_weight.push_back(m);
9579  }
9580  }
9581 
9582  // Set up hanging scheme for this node
9583  hang_info_pt[i] =
9584  new HangInfo(n_master_nodes - master_node_zero_weight.size());
9585  unsigned mindex = 0;
9586  for (unsigned m = 0; m < n_master_nodes; m++)
9587  {
9588  // Check that master doesn't have zero weight
9589  bool skip = false;
9590  for (unsigned k = 0; k < master_node_zero_weight.size(); k++)
9591  {
9592  if (m == master_node_zero_weight[k]) skip = true;
9593  }
9594 
9595  // Add pointer and weight to hang info
9596  if (!skip)
9597  hang_info_pt[i]->set_master_node_pt(
9598  mindex++, master_node_pt[m], P[i][m]);
9599  }
9600  }
9601 
9602  /// / Create structures to hold the hanging info
9603  /// /-------------------------------------------
9604  // Vector<HangInfo*> hang_info_pt(n_dependent_nodes);
9605  // for (unsigned i=0; i<n_dependent_nodes-n_mortar_vertices; i++)
9606  // {
9607  // hang_info_pt[i] = new HangInfo(n_master_nodes);
9608  // }
9609  //
9610  /// / Copy information to hanging nodes
9611  /// /----------------------------------
9612  // for(unsigned i=0; i<n_dependent_nodes-n_mortar_vertices; i++)
9613  // {
9614  // for(unsigned j=0; j<n_master_nodes; j++)
9615  // {
9616  // hang_info_pt[i]->set_master_node_pt(j,master_node_pt[j],P[i][j]);
9617  // }
9618  // }
9619 
9620  // Set pointers to hanging info
9621  //-----------------------------
9622  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
9623  {
9624  // Check that the node shoule actually hang.
9625  // That is, if the polynomial orders of the elements at a p-type
9626  // non-conormity are both odd then the middle node on the edge is
9627  // shared but a hanging scheme has been constructed for it.
9628  bool node_is_really_shared = false;
9629  for (unsigned m = 0; m < hang_info_pt[i]->nmaster(); m++)
9630  {
9631  // We can simply check if the hanging scheme lists itself as a
9632  // master
9633  if (hang_info_pt[i]->master_node_pt(m) ==
9634  dependent_node_pt[non_vertex_pos[i]])
9635  {
9636  node_is_really_shared = true;
9637 
9638 #ifdef PARANOID
9639  // Also check the corresponding weight: it should be 1
9640  if (std::fabs(hang_info_pt[i]->master_weight(m) - 1.0) >
9641  1.0e-06)
9642  {
9643  throw OomphLibError("Something fishy here -- with shared "
9644  "node at a mortar vertex",
9645  "PRefineableQElemen<2,INITIAL_NNODE_1D>"
9646  "t::quad_hang_helper()",
9647  OOMPH_EXCEPTION_LOCATION);
9648  }
9649 #endif
9650  }
9651  }
9652 
9653  // Now we can make the node hang, if it isn't a shared node
9654  if (!node_is_really_shared)
9655  {
9656  dependent_node_pt[non_vertex_pos[i]]->set_hanging_pt(
9657  hang_info_pt[i], -1);
9658 
9659  /// / Print out hanging scheme
9660  // std::cout << "Hanging node: "
9661  // << dependent_node_pt[non_vertex_pos[i]]->x(0) << " "
9662  // << dependent_node_pt[non_vertex_pos[i]]->x(1) << " "
9663  // << dependent_node_pt[non_vertex_pos[i]]->x(2) << " "
9664  // << std::endl;
9665  // for(unsigned m=0; m<hang_info_pt[i]->nmaster(); m++)
9666  // {
9667  // std::cout << " m = " << m << ": "
9668  // << hang_info_pt[i]->master_node_pt(m)->x(0) << " "
9669  // << hang_info_pt[i]->master_node_pt(m)->x(1) << " "
9670  // << hang_info_pt[i]->master_node_pt(m)->x(2) << " "
9671  // << "w = " << hang_info_pt[i]->master_weight(m) <<
9672  // " "
9673  // << std::endl;
9674  // }
9675  }
9676  }
9677 
9678  } // End of case where there are still dependent nodes
9679 
9680  } // End of edge is dependent
9681 
9682  } // End of loop over face edges
9683 
9684  } // End of if face is dependent
9685 
9686  // Now do the mortaring
9687  //---------------------
9688  if (h_type_dependent || p_type_dependent)
9689  {
9690  // Compute the active coordinate indices along the this side of mortar
9691  Vector<unsigned> active_coord_index(2);
9692  if (my_face == B || my_face == F)
9693  {
9694  active_coord_index[0] = 0;
9695  active_coord_index[1] = 1;
9696  }
9697  else if (my_face == D || my_face == U)
9698  {
9699  active_coord_index[0] = 0;
9700  active_coord_index[1] = 2;
9701  }
9702  else if (my_face == L || my_face == R)
9703  {
9704  active_coord_index[0] = 1;
9705  active_coord_index[1] = 2;
9706  }
9707  else
9708  {
9709  throw OomphLibError(
9710  "Cannot transform coordinates",
9711  "PRefineableQElement<3,INITIAL_NNODE_1D>::oc_hang_helper()",
9712  OOMPH_EXCEPTION_LOCATION);
9713  }
9714 
9715  // Get pointer to neighbouring master element (in p-refineable form)
9717  neigh_obj_pt = dynamic_cast<PRefineableQElement<3, INITIAL_NNODE_1D>*>(
9718  neigh_pt->object_pt());
9719 
9720  // Create vector of master and dependent nodes
9721  //----------------------------------------
9722  Vector<Node*> master_node_pt, dependent_node_pt;
9723  Vector<unsigned> master_node_number, dependent_node_number;
9724  Vector<Vector<double>> dependent_node_s_fraction;
9725 
9726  // Number of nodes in one dimension
9727  const unsigned my_n_p = this->ninterpolating_node_1d(value_id);
9728  const unsigned neigh_n_p = neigh_obj_pt->ninterpolating_node_1d(value_id);
9729 
9730  // Storage for pointers to the nodes and their numbers along the master
9731  // edge
9732  unsigned neighbour_node_number = 0;
9733  Node* neighbour_node_pt = 0;
9734 
9735  // Loop over nodes on the face
9736  for (unsigned i0 = 0; i0 < neigh_n_p; i0++)
9737  {
9738  for (unsigned i1 = 0; i1 < neigh_n_p; i1++)
9739  {
9740  const unsigned s0space = 1;
9741  const unsigned s1space = neigh_n_p;
9742  const unsigned s2space = neigh_n_p * neigh_n_p;
9743 
9744  // Find the neighbour's node
9745  switch (neigh_face)
9746  {
9747  case B:
9748  neighbour_node_number = i0 * s0space + i1 * s1space;
9749  neighbour_node_pt = neigh_obj_pt->interpolating_node_pt(
9750  neighbour_node_number, value_id);
9751  break;
9752 
9753  case F:
9754  neighbour_node_number =
9755  (neigh_n_p - 1) * s2space + i0 * s0space + i1 * s1space;
9756  neighbour_node_pt = neigh_obj_pt->interpolating_node_pt(
9757  neighbour_node_number, value_id);
9758  break;
9759 
9760  case D:
9761  neighbour_node_number = i0 * s0space + i1 * s2space;
9762  neighbour_node_pt = neigh_obj_pt->interpolating_node_pt(
9763  neighbour_node_number, value_id);
9764  break;
9765 
9766  case U:
9767  neighbour_node_number =
9768  (neigh_n_p - 1) * s1space + i0 * s0space + i1 * s2space;
9769  neighbour_node_pt = neigh_obj_pt->interpolating_node_pt(
9770  neighbour_node_number, value_id);
9771  break;
9772 
9773  case L:
9774  neighbour_node_number = i0 * s1space + i1 * s2space;
9775  neighbour_node_pt = neigh_obj_pt->interpolating_node_pt(
9776  neighbour_node_number, value_id);
9777  break;
9778 
9779  case R:
9780  neighbour_node_number =
9781  (neigh_n_p - 1) * s0space + i0 * s1space + i1 * s2space;
9782  neighbour_node_pt = neigh_obj_pt->interpolating_node_pt(
9783  neighbour_node_number, value_id);
9784  break;
9785 
9786  default:
9787  throw OomphLibError(
9788  "my_face not L, R, D, U, B, F\n",
9789  "PRefineableQElement<3,INITIAL_NNODE_1D>::oc_hang_helper()",
9790  OOMPH_EXCEPTION_LOCATION);
9791  }
9792 
9793  // Set node as master node
9794  master_node_number.push_back(neighbour_node_number);
9795  master_node_pt.push_back(neighbour_node_pt);
9796  }
9797  }
9798 
9799  // Storage for pointers to the local nodes and their numbers along my edge
9800  unsigned local_node_number = 0;
9801  Node* local_node_pt = 0;
9802 
9803  // Loop over the nodes along my edge
9804  for (unsigned i0 = 0; i0 < my_n_p; i0++)
9805  {
9806  for (unsigned i1 = 0; i1 < my_n_p; i1++)
9807  {
9808  // Storage for the fractional position of the node in the element
9809  Vector<double> s_fraction(3);
9810 
9811  const unsigned s0space = 1;
9812  const unsigned s1space = my_n_p;
9813  const unsigned s2space = my_n_p * my_n_p;
9814 
9815  // Find the local node and the fractional position of the node
9816  // which depends on the edge, of course
9817  switch (my_face)
9818  {
9819  case B:
9820  s_fraction[0] =
9821  local_one_d_fraction_of_interpolating_node(i0, 0, value_id);
9822  s_fraction[1] =
9823  local_one_d_fraction_of_interpolating_node(i1, 1, value_id);
9824  s_fraction[2] = 0.0;
9825  local_node_number = i0 * s0space + i1 * s1space;
9826  local_node_pt =
9827  this->interpolating_node_pt(local_node_number, value_id);
9828  break;
9829 
9830  case F:
9831  s_fraction[0] =
9832  local_one_d_fraction_of_interpolating_node(i0, 0, value_id);
9833  s_fraction[1] =
9834  local_one_d_fraction_of_interpolating_node(i1, 1, value_id);
9835  s_fraction[2] = 1.0;
9836  local_node_number =
9837  (my_n_p - 1) * s2space + i0 * s0space + i1 * s1space;
9838  local_node_pt =
9839  this->interpolating_node_pt(local_node_number, value_id);
9840  break;
9841 
9842  case D:
9843  s_fraction[0] =
9844  local_one_d_fraction_of_interpolating_node(i0, 0, value_id);
9845  s_fraction[1] = 0.0;
9846  s_fraction[2] =
9847  local_one_d_fraction_of_interpolating_node(i1, 2, value_id);
9848  local_node_number = i0 * s0space + i1 * s2space;
9849  local_node_pt =
9850  this->interpolating_node_pt(local_node_number, value_id);
9851  break;
9852 
9853  case U:
9854  s_fraction[0] =
9855  local_one_d_fraction_of_interpolating_node(i0, 0, value_id);
9856  s_fraction[1] = 1.0;
9857  s_fraction[2] =
9858  local_one_d_fraction_of_interpolating_node(i1, 2, value_id);
9859  local_node_number =
9860  (my_n_p - 1) * s1space + i0 * s0space + i1 * s2space;
9861  local_node_pt =
9862  this->interpolating_node_pt(local_node_number, value_id);
9863  break;
9864 
9865  case L:
9866  s_fraction[0] = 0.0;
9867  s_fraction[1] =
9868  local_one_d_fraction_of_interpolating_node(i0, 1, value_id);
9869  s_fraction[2] =
9870  local_one_d_fraction_of_interpolating_node(i1, 2, value_id);
9871  local_node_number = i0 * s1space + i1 * s2space;
9872  local_node_pt =
9873  this->interpolating_node_pt(local_node_number, value_id);
9874  break;
9875 
9876  case R:
9877  s_fraction[0] = 1.0;
9878  s_fraction[1] =
9879  local_one_d_fraction_of_interpolating_node(i0, 1, value_id);
9880  s_fraction[2] =
9881  local_one_d_fraction_of_interpolating_node(i1, 2, value_id);
9882  local_node_number =
9883  (my_n_p - 1) * s0space + i0 * s1space + i1 * s2space;
9884  local_node_pt =
9885  this->interpolating_node_pt(local_node_number, value_id);
9886  break;
9887 
9888  default:
9889  throw OomphLibError(
9890  "my_face not L, R, D, U, B, F\n",
9891  "PRefineableQElement<3,INITIAL_NNODE_1D>::oc_hang_helper()",
9892  OOMPH_EXCEPTION_LOCATION);
9893  }
9894 
9895  // Add node to vector of dependent element nodes
9896  dependent_node_number.push_back(local_node_number);
9897  dependent_node_pt.push_back(local_node_pt);
9898 
9899  // Store node's local fraction
9900  dependent_node_s_fraction.push_back(s_fraction);
9901  }
9902  }
9903 
9904  // Store the number of dependent and master nodes for use later
9905  const unsigned n_dependent_nodes = dependent_node_pt.size();
9906  const unsigned n_master_nodes = master_node_pt.size();
9907  const unsigned dependent_element_nnode_1d = my_n_p;
9908  const unsigned master_element_nnode_1d = neigh_n_p;
9909 
9910  /// / Print out dependent and master node coords
9911  // std::cout << "Dependent nodes on face: " <<
9912  // OcTree::Direct_string[my_face] << std::endl; for(unsigned i=0;
9913  // i<dependent_node_pt.size(); i++)
9914  // {
9915  // std::cout << i << ": "
9916  // << dependent_node_pt[i]->x(0) << " "
9917  // << dependent_node_pt[i]->x(1) << " "
9918  // << dependent_node_pt[i]->x(2) << " "
9919  // << std::endl;
9920  // }
9921  // std::cout << "Master nodes on face: " << OcTree::Direct_string[my_face]
9922  // << std::endl; for(unsigned i=0; i<master_node_pt.size(); i++)
9923  // {
9924  // std::cout << i << ": "
9925  // << master_node_pt[i]->x(0) << " "
9926  // << master_node_pt[i]->x(1) << " "
9927  // << master_node_pt[i]->x(2) << " "
9928  // << std::endl;
9929  // }
9930 
9931  // Storage for master shapes
9932  Shape master_shapes(neigh_obj_pt->ninterpolating_node(value_id));
9933 
9934  // Get master and dependent nodal positions
9935  //-------------------------------------
9936  // Get in 1D
9937  Vector<double> dependent_nodal_position_1d;
9938  Vector<double> dependent_weight_1d(dependent_element_nnode_1d);
9939  Orthpoly::gll_nodes(dependent_element_nnode_1d,
9940  dependent_nodal_position_1d,
9941  dependent_weight_1d);
9942  Vector<double> master_nodal_position_1d;
9943  Vector<double> master_weight_1d(master_element_nnode_1d);
9945  master_element_nnode_1d, master_nodal_position_1d, master_weight_1d);
9946 
9947  // Storage for 2D
9948  Vector<Vector<double>> dependent_nodal_position(
9949  dependent_element_nnode_1d * dependent_element_nnode_1d);
9950  for (unsigned i = 0; i < dependent_nodal_position.size(); i++)
9951  {
9952  dependent_nodal_position[i].resize(2);
9953  }
9954  Vector<double> dependent_weight(dependent_element_nnode_1d *
9955  dependent_element_nnode_1d);
9956  Vector<Vector<double>> master_nodal_position(master_element_nnode_1d *
9957  master_element_nnode_1d);
9958  for (unsigned i = 0; i < master_nodal_position.size(); i++)
9959  {
9960  master_nodal_position[i].resize(2);
9961  }
9962  Vector<double> master_weight(master_element_nnode_1d *
9963  master_element_nnode_1d);
9964 
9965  // Fill in coordinates and weights in 2D
9966  unsigned dependent_index = 0;
9967  for (unsigned i = 0; i < dependent_element_nnode_1d; i++)
9968  {
9969  for (unsigned j = 0; j < dependent_element_nnode_1d; j++)
9970  {
9971  dependent_nodal_position[dependent_index][0] =
9972  dependent_nodal_position_1d[i];
9973  dependent_nodal_position[dependent_index][1] =
9974  dependent_nodal_position_1d[j];
9975  dependent_weight[dependent_index] =
9976  dependent_weight_1d[i] * dependent_weight_1d[j];
9977  dependent_index++;
9978  }
9979  }
9980  unsigned master_index = 0;
9981  for (unsigned i = 0; i < master_element_nnode_1d; i++)
9982  {
9983  for (unsigned j = 0; j < master_element_nnode_1d; j++)
9984  {
9985  master_nodal_position[master_index][0] = master_nodal_position_1d[i];
9986  master_nodal_position[master_index][1] = master_nodal_position_1d[j];
9987  master_weight[master_index] =
9988  master_weight_1d[i] * master_weight_1d[j];
9989  master_index++;
9990  }
9991  }
9992 
9993  // Apply the vertex matching condition
9994  //------------------------------------
9995  // Vertiex matching is ensured automatically in cases where there is a
9996  // node at each end of the mortar that is shared between the master and
9997  // dependent elements. Where this is not the case, the vertex matching
9998  // condition must be enforced by constraining the value of the unknown at
9999  // the node on the dependent side to be the same as the value at that
10000  // location in the master.
10001 
10002  // Store positions of the mortar vertex/non-vertex nodes in the dependent
10003  // element
10004  // const unsigned n_mortar_vertices = 4;
10005  // Vector<unsigned> vertex_pos(n_mortar_vertices);
10006  // vertex_pos[0] = 0;
10007  // vertex_pos[1] = my_n_p-1;
10008  // vertex_pos[2] = my_n_p*(my_n_p-1);
10009  // vertex_pos[3] = my_n_p*my_n_p-1;
10010  Vector<unsigned> non_vertex_pos((dependent_element_nnode_1d - 2) *
10011  (dependent_element_nnode_1d - 2));
10012  unsigned nvindex = 0;
10013  for (unsigned i = 1; i < dependent_element_nnode_1d - 1; i++)
10014  {
10015  for (unsigned j = 1; j < dependent_element_nnode_1d - 1; j++)
10016  {
10017  non_vertex_pos[nvindex++] = i * dependent_element_nnode_1d + j;
10018  }
10019  }
10020  Vector<unsigned> vertex_pos;
10021  for (unsigned i = 0; i < n_dependent_nodes; i++)
10022  {
10023  // Check if node number is in the non-vertex storage
10024  bool node_is_vertex = true;
10025  for (unsigned j = 0; j < non_vertex_pos.size(); j++)
10026  {
10027  if (i == non_vertex_pos[j])
10028  {
10029  // Node is not a vertex
10030  node_is_vertex = false;
10031  break;
10032  }
10033  }
10034  // If we get here and the node is a vertex then add it's index
10035  if (node_is_vertex)
10036  {
10037  vertex_pos.push_back(i);
10038  }
10039  }
10040  // Store number of mortar vertices
10041  const unsigned n_mortar_vertices = vertex_pos.size();
10042 
10043  // Check that there are actually dependent nodes for which we still need
10044  // to construct a hanging scheme. If not then there is nothing more to do.
10045  if (n_dependent_nodes - n_mortar_vertices > 0)
10046  {
10047  // Assemble mass matrix for mortar
10048  //--------------------------------
10049  Vector<double> psi(n_dependent_nodes - n_mortar_vertices);
10050  Vector<double> diag_M(n_dependent_nodes - n_mortar_vertices);
10051  Vector<Vector<double>> shared_node_M(n_mortar_vertices);
10052  for (unsigned i = 0; i < shared_node_M.size(); i++)
10053  {
10054  shared_node_M[i].resize(n_dependent_nodes - n_mortar_vertices);
10055  }
10056 
10057  // Fill in part corresponding to dependent nodal positions (unknown)
10058  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
10059  {
10060  // Mortar test functions in 2D are just the cross product of the 1D
10061  // test functions Initialise to 1
10062  psi[i] = 1.0;
10063  // Take product in each direction
10064  for (unsigned dir = 0; dir < 2; dir++)
10065  {
10066  unsigned index1d =
10067  (dir == 0) ? i : i % (dependent_element_nnode_1d - 2);
10068  // Use L'Hosptal's rule:
10069  psi[i] *=
10070  pow(-1.0, int((dependent_element_nnode_1d - 1) - index1d - 1)) *
10072  dependent_element_nnode_1d - 1,
10073  dependent_nodal_position[non_vertex_pos[i]][dir]);
10074  }
10075  // Put in contribution
10076  diag_M[i] = psi[i] * dependent_weight[non_vertex_pos[i]];
10077  }
10078 
10079  /// / Print out diag(M)
10080  // std::cout << "diag(M):" << std::endl;
10081  // for(unsigned i=0; i<diag_M.size(); i++)
10082  // {
10083  // std::cout << " " << diag_M[i];
10084  // }
10085  // std::cout << std::endl;
10086 
10087  // Fill in part corresponding to dependent element vertices (known)
10088  for (unsigned v = 0; v < shared_node_M.size(); v++)
10089  {
10090  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
10091  {
10092  // Mortar test functions in 2D are just the cross product of the 1D
10093  // test functions Initialise to 1
10094  psi[i] = 1.0;
10095  // Take product in each direction
10096  for (unsigned dir = 0; dir < 2; dir++)
10097  {
10098  unsigned index1d =
10099  (dir == 0) ? i : i % (dependent_element_nnode_1d - 2);
10100  // Check if denominator is zero
10101  if (std::fabs(dependent_nodal_position[non_vertex_pos[i]][dir] -
10102  dependent_nodal_position[vertex_pos[v]][dir]) >=
10103  1.0e-8)
10104  {
10105  // We're ok
10106  psi[i] *=
10107  pow(-1.0,
10108  int((dependent_element_nnode_1d - 1) - index1d - 1)) *
10110  dependent_element_nnode_1d - 1,
10111  dependent_nodal_position[vertex_pos[v]][dir]) /
10112  (dependent_nodal_position[non_vertex_pos[i]][dir] -
10113  dependent_nodal_position[vertex_pos[v]][dir]);
10114  }
10115  // Check if numerator is zero
10116  else if (std::fabs(Orthpoly::dlegendre(
10117  dependent_element_nnode_1d - 1,
10118  dependent_nodal_position[vertex_pos[v]][dir])) <
10119  1.0e-8)
10120  {
10121  // We can use l'hopital's rule
10122  psi[i] *=
10123  pow(-1.0,
10124  int((dependent_element_nnode_1d - 1) - index1d - 1)) *
10126  dependent_element_nnode_1d - 1,
10127  dependent_nodal_position[non_vertex_pos[i]][dir]);
10128  }
10129  else
10130  {
10131  // We can't use l'hopital's rule
10132  throw OomphLibError(
10133  "Cannot use l'Hopital's rule. Dividing by zero is not "
10134  "allowed!",
10135  "PRefineableQElement<3,INITIAL_NNODE_1D>::quad_hang_helper()",
10136  OOMPH_EXCEPTION_LOCATION);
10137  }
10138  }
10139  // Put in contribution
10140  shared_node_M[v][i] = psi[i] * dependent_weight[vertex_pos[v]];
10141  }
10142  }
10143 
10144  /// / Print out diag(M)
10145  // std::cout << "shared node M:" << std::endl;
10146  // for(unsigned i=0; i<shared_node_M.size(); i++)
10147  // {
10148  // for(unsigned j=0; j<shared_node_M[i].size(); j++)
10149  // {
10150  // std::cout << " " << shared_node_M[i][j];
10151  // }
10152  // }
10153  // std::cout << std::endl;
10154 
10155  // Assemble local projection matrix for mortar
10156  //--------------------------------------------
10157 
10158  // Have only one local projection matrix because there is just one
10159  // master
10160  Vector<Vector<double>> P(n_dependent_nodes - n_mortar_vertices);
10161  for (unsigned i = 0; i < P.size(); i++)
10162  {
10163  P[i].resize(n_master_nodes, 0.0);
10164  }
10165 
10166  // Storage for local coordinate
10167  Vector<double> s(3);
10168 
10169  // Sum contributions from master element shapes (quadrature).
10170  // The order of quadrature must be high enough to evaluate a polynomial
10171  // of order N_s + N_m - 3 exactly, where N_s = n_dependent_nodes, N_m =
10172  // n_master_nodes.
10173  // (Use pointers for the quadrature knots and weights so that
10174  // data is not unnecessarily copied)
10175  // unsigned quadrature_order =
10176  // std::max(dependent_element_nnode_1d,master_element_nnode_1d);
10177  Vector<Vector<double>>* quadrature_knot;
10178  Vector<double>* quadrature_weight;
10179  if (dependent_element_nnode_1d >= master_element_nnode_1d)
10180  {
10181  // Use the same quadrature order as the dependent element (me)
10182  quadrature_knot = &dependent_nodal_position;
10183  quadrature_weight = &dependent_weight;
10184  }
10185  else
10186  {
10187  // Use the same quadrature order as the master element (neighbour)
10188  quadrature_knot = &master_nodal_position;
10189  quadrature_weight = &master_weight;
10190  }
10191 
10192  // Quadrature loop
10193  for (unsigned q = 0; q < (*quadrature_weight).size(); q++)
10194  {
10195  // Evaluate mortar test functions at the quadrature knots in the
10196  // dependent
10197  Vector<double> s_on_mortar(2);
10198  for (unsigned i = 0; i < 2; i++)
10199  {
10200  s_on_mortar[i] = (*quadrature_knot)[q][i];
10201  }
10202 
10203  // Get psi
10204  for (unsigned k = 0; k < n_dependent_nodes - n_mortar_vertices; k++)
10205  {
10206  // Mortar test functions in 2D are just the cross product of the 1D
10207  // test functions Initialise to 1
10208  psi[k] = 1.0;
10209  // Take product in each direction
10210  for (unsigned dir = 0; dir < 2; dir++)
10211  {
10212  unsigned index1d =
10213  (dir == 0) ? k : k % (dependent_element_nnode_1d - 2);
10214  // Check if denominator is zero
10215  if (std::fabs(dependent_nodal_position[non_vertex_pos[k]][dir] -
10216  s_on_mortar[dir]) >= 1.0e-08)
10217  {
10218  // We're ok
10219  psi[k] *=
10220  pow(-1.0,
10221  int((dependent_element_nnode_1d - 1) - index1d - 1)) *
10222  Orthpoly::dlegendre(dependent_element_nnode_1d - 1,
10223  s_on_mortar[dir]) /
10224  (dependent_nodal_position[non_vertex_pos[k]][dir] -
10225  s_on_mortar[dir]);
10226  }
10227  // Check if numerator is zero
10228  else if (std::fabs(Orthpoly::dlegendre(
10229  dependent_element_nnode_1d - 1, s_on_mortar[dir])) <
10230  1.0e-8)
10231  {
10232  // We can use l'Hopital's rule
10233  psi[k] *=
10234  pow(-1.0,
10235  int((dependent_element_nnode_1d - 1) - index1d - 1)) *
10236  -Orthpoly::ddlegendre(dependent_element_nnode_1d - 1,
10237  s_on_mortar[dir]);
10238  }
10239  else
10240  {
10241  // We can't use l'hopital's rule
10242  throw OomphLibError(
10243  "Cannot use l'Hopital's rule. Dividing by zero is not "
10244  "allowed!",
10245  "PRefineableQElement<3,INITIAL_NNODE_1D>::quad_hang_helper()",
10246  OOMPH_EXCEPTION_LOCATION);
10247  }
10248  }
10249  }
10250 
10251  // Convert coordinate on mortar to local fraction in dependent element
10252  Vector<double> s_fraction(3);
10253  for (unsigned i = 0; i < 3; i++)
10254  {
10255  if (i == active_coord_index[0])
10256  {
10257  s_fraction[i] = 0.5 * (s_on_mortar[0] + 1.0);
10258  }
10259  else if (i == active_coord_index[1])
10260  {
10261  s_fraction[i] = 0.5 * (s_on_mortar[1] + 1.0);
10262  }
10263  else
10264  {
10265  s_fraction[i] = dependent_node_s_fraction[vertex_pos[0]][i];
10266  }
10267  }
10268 
10269  // Project active coordinate into master element
10270  Vector<double> s_in_neigh(3);
10271  for (unsigned i = 0; i < 3; i++)
10272  {
10273  s_in_neigh[i] = s_lo_neigh[i] + s_fraction[translate_s[i]] *
10274  (s_hi_neigh[i] - s_lo_neigh[i]);
10275  }
10276 
10277  // Evaluate master shapes at projections of local quadrature knots
10278  neigh_obj_pt->interpolating_basis(
10279  s_in_neigh, master_shapes, value_id);
10280 
10281  // Populate local projection matrix
10282  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
10283  {
10284  for (unsigned j = 0; j < n_master_nodes; j++)
10285  {
10286  P[i][j] += master_shapes[master_node_number[j]] * psi[i] *
10287  (*quadrature_weight)[q];
10288  }
10289  }
10290  }
10291 
10292  /// / Print out local projection matrix
10293  // std::cout << "P_e:" << std::endl;
10294  // for(unsigned i=0; i<P.size(); i++)
10295  // {
10296  // for(unsigned j=0; j<P[i].size(); j++)
10297  // {
10298  // std::cout << " " << P[i][j];
10299  // }
10300  // }
10301  // std::cout << std::endl;
10302 
10303  // Assemble global projection matrices for mortar
10304  //-----------------------------------------------
10305  // Need to subtract contributions from the "known unknowns"
10306  // corresponding to the nodes at the vertices of the mortar
10307 
10308  // Assemble contributions from mortar vertex nodes
10309  for (unsigned v = 0; v < n_mortar_vertices; v++)
10310  {
10311  // Convert coordinate on mortar to local fraction in dependent element
10312  Vector<double> s_fraction(3);
10313  for (unsigned i = 0; i < 3; i++)
10314  {
10315  if (i == active_coord_index[0])
10316  {
10317  s_fraction[i] =
10318  0.5 * (dependent_nodal_position[vertex_pos[v]][0] + 1.0);
10319  }
10320  else if (i == active_coord_index[1])
10321  {
10322  s_fraction[i] =
10323  0.5 * (dependent_nodal_position[vertex_pos[v]][1] + 1.0);
10324  }
10325  else
10326  {
10327  s_fraction[i] = dependent_node_s_fraction[vertex_pos[0]][i];
10328  }
10329  }
10330 
10331  // Project active coordinate into master element
10332  Vector<double> s_in_neigh(3);
10333  for (unsigned i = 0; i < 3; i++)
10334  {
10335  s_in_neigh[i] = s_lo_neigh[i] + s_fraction[translate_s[i]] *
10336  (s_hi_neigh[i] - s_lo_neigh[i]);
10337  }
10338 
10339  // Get master shapes at dependent nodal positions
10340  neigh_obj_pt->interpolating_basis(
10341  s_in_neigh, master_shapes, value_id);
10342 
10343  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
10344  {
10345  for (unsigned k = 0; k < n_master_nodes; k++)
10346  {
10347  P[i][k] -=
10348  master_shapes[master_node_number[k]] * shared_node_M[v][i];
10349  }
10350  }
10351  }
10352 
10353  /// / Print out global projection matrix
10354  // std::cout << "P:" << std::endl;
10355  // for(unsigned i=0; i<P.size(); i++)
10356  // {
10357  // for(unsigned j=0; j<P[i].size(); j++)
10358  // {
10359  // std::cout << " " << P[i][j];
10360  // }
10361  // }
10362  // std::cout << std::endl;
10363 
10364  // Solve mortar system
10365  //--------------------
10366  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
10367  {
10368  for (unsigned j = 0; j < n_master_nodes; j++)
10369  {
10370  P[i][j] /= diag_M[i];
10371  }
10372  }
10373 
10374  /// / Print out solved matrix
10375  // std::cout << "solved P:" << std::endl;
10376  // for(unsigned i=0; i<P.size(); i++)
10377  // {
10378  // for(unsigned j=0; j<P[i].size(); j++)
10379  // {
10380  // std::cout << " " << P[i][j];
10381  // }
10382  // }
10383  // std::cout << std::endl;
10384 
10385  // Create structures to hold the hanging info
10386  //-------------------------------------------
10387  Vector<HangInfo*> hang_info_pt(n_dependent_nodes);
10388  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
10389  {
10390  hang_info_pt[i] = new HangInfo(n_master_nodes);
10391  }
10392 
10393  // Copy information to hanging nodes
10394  //----------------------------------
10395  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
10396  {
10397  for (unsigned j = 0; j < n_master_nodes; j++)
10398  {
10399  hang_info_pt[i]->set_master_node_pt(j, master_node_pt[j], P[i][j]);
10400  }
10401  }
10402 
10403  // Set pointers to hanging info
10404  //-----------------------------
10405  for (unsigned i = 0; i < n_dependent_nodes - n_mortar_vertices; i++)
10406  {
10407  // Check that the node shoule actually hang.
10408  // That is, if the polynomial orders of the elements at a p-type
10409  // non-conormity are both odd then the middle node on the edge is
10410  // shared but a hanging scheme has been constructed for it.
10411  bool node_is_really_shared = false;
10412  for (unsigned m = 0; m < hang_info_pt[i]->nmaster(); m++)
10413  {
10414  // We can simply check if the hanging scheme lists itself as a
10415  // master
10416  if (hang_info_pt[i]->master_node_pt(m) ==
10417  dependent_node_pt[non_vertex_pos[i]])
10418  {
10419  node_is_really_shared = true;
10420 
10421 #ifdef PARANOID
10422  // Also check the corresponding weight: it should be 1
10423  if (std::fabs(hang_info_pt[i]->master_weight(m) - 1.0) > 1.0e-06)
10424  {
10425  throw OomphLibError(
10426  "Something fishy here -- with shared node at a mortar vertex",
10427  "PRefineableQElement<3,INITIAL_NNODE_1D>::quad_hang_helper()",
10428  OOMPH_EXCEPTION_LOCATION);
10429  }
10430 #endif
10431  }
10432  }
10433 
10434  // Now we can make the node hang, if it isn't a shared node
10435  if (!node_is_really_shared)
10436  {
10437  dependent_node_pt[non_vertex_pos[i]]->set_hanging_pt(
10438  hang_info_pt[i], -1);
10439  }
10440  }
10441 
10442  } // End of case where there are still dependent nodes
10443 
10444 #ifdef PARANOID
10445  // Check all dependent nodes, hanging or otherwise
10446  for (unsigned i = 0; i < n_dependent_nodes; i++)
10447  {
10448  // Check that weights sum to 1 for those that hang
10449  if (dependent_node_pt[i]->is_hanging())
10450  {
10451  // Check that weights sum to 1 and no zero weights
10452  double weight_sum = 0.0;
10453  bool zero_weight = false;
10454  for (unsigned m = 0;
10455  m < dependent_node_pt[i]->hanging_pt()->nmaster();
10456  m++)
10457  {
10458  weight_sum += dependent_node_pt[i]->hanging_pt()->master_weight(m);
10459  if (std::fabs(dependent_node_pt[i]->hanging_pt()->master_weight(
10460  m)) < 1.0e-14)
10461  {
10462  zero_weight = true;
10463  oomph_info << "In the hanging scheme for dependent node " << i
10464  << ", master node " << m << " has weight "
10465  << dependent_node_pt[i]->hanging_pt()->master_weight(m)
10466  << " < 1.0e-14" << std::endl;
10467  }
10468  }
10469 
10470  // Warn if not
10471  if (std::fabs(weight_sum - 1.0) > 1.0e-08)
10472  {
10473  oomph_info << "Sum of master weights: " << weight_sum << std::endl;
10475  "Weights in hanging scheme do not sum to 1",
10476  "PRefineableQElement<3,INITIAL_NNODE_1D>::oc_hang_helper()",
10477  OOMPH_EXCEPTION_LOCATION);
10478  }
10479  if (zero_weight)
10480  {
10482  "Zero weights present in hanging schemes",
10483  "PRefineableQElement<3,INITIAL_NNODE_1D>::oc_hang_helper()",
10484  OOMPH_EXCEPTION_LOCATION);
10485  }
10486 
10487  // Also check that dependent nodes do not have themselves as masters
10488  // bool dependent_should_not_be_hanging = false;
10489  for (unsigned m = 0;
10490  m < dependent_node_pt[i]->hanging_pt()->nmaster();
10491  m++)
10492  {
10493  if (dependent_node_pt[i] ==
10494  dependent_node_pt[i]->hanging_pt()->master_node_pt(m))
10495  {
10496  // This shouldn't happen!
10497  throw OomphLibError(
10498  "Dependent node has itself as a master!",
10499  "PRefineableQElement<3,INITIAL_NNODE_1D>::oc_hang_helper()",
10500  OOMPH_EXCEPTION_LOCATION);
10501  }
10502  if (dependent_node_pt[i]
10503  ->hanging_pt()
10504  ->master_node_pt(m)
10505  ->is_hanging())
10506  {
10507  // Check if node is master of master
10508  Node* new_nod_pt =
10509  dependent_node_pt[i]->hanging_pt()->master_node_pt(m);
10510  for (unsigned mm = 0; mm < new_nod_pt->hanging_pt()->nmaster();
10511  mm++)
10512  {
10513  if (dependent_node_pt[i] ==
10514  new_nod_pt->hanging_pt()->master_node_pt(mm))
10515  {
10516  std::cout << "++++++++++++++++++++++++++++++++++++++++"
10517  << std::endl;
10518  std::cout
10519  << " Dependent node: " << dependent_node_pt[i]
10520  << " = " << dependent_node_pt[i]->x(0) << " "
10521  << dependent_node_pt[i]->x(1) << " "
10522  << dependent_node_pt[i]->x(2) << " " << std::endl;
10523  std::cout
10524  << " Master node: "
10525  << dependent_node_pt[i]->hanging_pt()->master_node_pt(m)
10526  << " = "
10527  << dependent_node_pt[i]->hanging_pt()->master_node_pt(m)->x(
10528  0)
10529  << " "
10530  << dependent_node_pt[i]->hanging_pt()->master_node_pt(m)->x(
10531  1)
10532  << " "
10533  << dependent_node_pt[i]->hanging_pt()->master_node_pt(m)->x(
10534  2)
10535  << " " << std::endl;
10536  std::cout << "Master's master node: "
10537  << dependent_node_pt[i]
10538  ->hanging_pt()
10539  ->master_node_pt(m)
10540  ->hanging_pt()
10541  ->master_node_pt(mm)
10542  << " = "
10543  << dependent_node_pt[i]
10544  ->hanging_pt()
10545  ->master_node_pt(m)
10546  ->hanging_pt()
10547  ->master_node_pt(mm)
10548  ->x(0)
10549  << " "
10550  << dependent_node_pt[i]
10551  ->hanging_pt()
10552  ->master_node_pt(m)
10553  ->hanging_pt()
10554  ->master_node_pt(mm)
10555  ->x(1)
10556  << " "
10557  << dependent_node_pt[i]
10558  ->hanging_pt()
10559  ->master_node_pt(m)
10560  ->hanging_pt()
10561  ->master_node_pt(mm)
10562  ->x(2)
10563  << " " << std::endl;
10564 
10565 
10566  // Print out hanging scheme
10567  std::cout << "Hanging node: " << dependent_node_pt[i]->x(0)
10568  << " " << dependent_node_pt[i]->x(1) << " "
10569  << dependent_node_pt[i]->x(2) << " " << std::endl;
10570  for (unsigned m_tmp = 0;
10571  m_tmp < dependent_node_pt[i]->hanging_pt()->nmaster();
10572  m_tmp++)
10573  {
10574  std::cout
10575  << " m = " << m_tmp << ": "
10576  << dependent_node_pt[i]
10577  ->hanging_pt()
10578  ->master_node_pt(m_tmp)
10579  ->x(0)
10580  << " "
10581  << dependent_node_pt[i]
10582  ->hanging_pt()
10583  ->master_node_pt(m_tmp)
10584  ->x(1)
10585  << " "
10586  << dependent_node_pt[i]
10587  ->hanging_pt()
10588  ->master_node_pt(m_tmp)
10589  ->x(2)
10590  << " "
10591  << "w = "
10592  << dependent_node_pt[i]->hanging_pt()->master_weight(
10593  m_tmp)
10594  << " " << std::endl;
10595  }
10596 
10597  // Print out hanging scheme
10598  std::cout << "Master node " << m
10599  << " of Hanging node: " << new_nod_pt->x(0) << " "
10600  << new_nod_pt->x(1) << " " << new_nod_pt->x(2)
10601  << " " << std::endl;
10602  for (unsigned mm_tmp = 0;
10603  mm_tmp < new_nod_pt->hanging_pt()->nmaster();
10604  mm_tmp++)
10605  {
10606  std::cout
10607  << " mm = " << mm_tmp << ": "
10608  << new_nod_pt->hanging_pt()->master_node_pt(mm_tmp)->x(0)
10609  << " "
10610  << new_nod_pt->hanging_pt()->master_node_pt(mm_tmp)->x(1)
10611  << " "
10612  << new_nod_pt->hanging_pt()->master_node_pt(mm_tmp)->x(2)
10613  << " "
10614  << "w = "
10615  << new_nod_pt->hanging_pt()->master_weight(mm_tmp) << " "
10616  << std::endl;
10617  }
10618 
10619  // This shouldn't happen!
10620  throw OomphLibError(
10621  "Dependent node has itself as a master of a master!",
10622  "PRefineableQElement<3,INITIAL_NNODE_1D>::oc_hang_helper()",
10623  OOMPH_EXCEPTION_LOCATION);
10624  }
10625  }
10626  }
10627  }
10628  }
10629  else
10630  {
10631  // Check that this node is shared with the master element if it
10632  // isn't hanging
10633  bool is_master = false;
10634  for (unsigned n = 0; n < n_master_nodes; n++)
10635  {
10636  if (dependent_node_pt[i] == master_node_pt[n])
10637  {
10638  // Node is a master
10639  is_master = true;
10640  break;
10641  }
10642  }
10643 
10644  if (!is_master)
10645  {
10646  /// / Throw error
10647  // std::ostringstream error_string;
10648  // error_string
10649  // << "This node in the dependent element is neither" << std::endl
10650  // << "hanging or shared with a master element." << std::endl;
10651  //
10652  // throw OomphLibError(
10653  // error_string.str(),
10654  // "PRefineableQElement<3,INITIAL_NNODE_1D>::quad_hang_helper()",
10655  // OOMPH_EXCEPTION_LOCATION);
10656  }
10657  }
10658  }
10659 #endif
10660 
10661  // Finally, Loop over all dependent nodes and fine-tune their positions
10662  //-----------------------------------------------------------------
10663  // Here we simply set the node's positions to be consistent
10664  // with the hanging scheme. This is not strictly necessary
10665  // because it is done in the mesh adaptation before the node
10666  // becomes non-hanging later on. We make no attempt to ensure
10667  // (strong) continuity in the position across the mortar.
10668  for (unsigned i = 0; i < n_dependent_nodes; i++)
10669  {
10670  // Only fine-tune hanging nodes
10671  if (dependent_node_pt[i]->is_hanging())
10672  {
10673  // If we are doing the position, then
10674  if (value_id == -1)
10675  {
10676  // Get the local coordinate of this dependent node
10677  Vector<double> s_local(3);
10678  this->local_coordinate_of_node(dependent_node_number[i], s_local);
10679 
10680  // Get the position from interpolation in this element via
10681  // the hanging scheme
10682  Vector<double> x_in_neighb(3);
10683  this->interpolated_x(s_local, x_in_neighb);
10684 
10685  // Fine adjust the coordinates (macro map will pick up boundary
10686  // accurately but will lead to different element edges)
10687  dependent_node_pt[i]->x(0) = x_in_neighb[0];
10688  dependent_node_pt[i]->x(1) = x_in_neighb[1];
10689  dependent_node_pt[i]->x(2) = x_in_neighb[2];
10690  }
10691  }
10692  }
10693  } // End of case where this interface is to be mortared
10694  }
10695 
10696  //===================================================================
10697  // Build required templates
10698  //===================================================================
10699  template class PRefineableQElement<1, 2>;
10700  template class PRefineableQElement<1, 3>;
10701  template class PRefineableQElement<1, 4>;
10702 
10703  template class PRefineableQElement<2, 2>;
10704  template class PRefineableQElement<2, 3>;
10705  template class PRefineableQElement<2, 4>;
10706 
10707  template class PRefineableQElement<3, 2>;
10708  template class PRefineableQElement<3, 3>;
10709  template class PRefineableQElement<3, 4>;
10710 
10711 } // namespace oomph
e
Definition: cfortran.h:571
static char t char * s
Definition: cfortran.h:568
cstr elem_len * i
Definition: cfortran.h:603
char t
Definition: cfortran.h:568
////////////////////////////////////////////////////////////////////
void setup_algebraic_node_update(Node *&node_pt, const Vector< double > &s_father, FiniteElement *father_el_pt) const
Set up node update info for (newly created) algebraic node: I.e. work out its node update information...
BinaryTree class: Recursively defined, generalised binary tree.
Definition: binary_tree.h:92
A Class for the derivatives of shape functions The class design is essentially the same as Shape,...
Definition: shape.h:278
void pin(const unsigned &i)
Pin the i-th stored variable.
Definition: nodes.h:385
TimeStepper *& time_stepper_pt()
Return the pointer to the timestepper.
Definition: nodes.h:238
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:271
unsigned nvalue() const
Return number of values stored in data object (incl pinned ones).
Definition: nodes.h:483
A general Finite Element class.
Definition: elements.h:1317
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2179
virtual Node * get_node_at_local_coordinate(const Vector< double > &s) const
If there is a node at this local coordinate, return the pointer to the node.
Definition: elements.cc:3912
static const double Node_location_tolerance
Default value for the tolerance to be used when locating nodes via local coordinates.
Definition: elements.h:1378
virtual double interpolated_x(const Vector< double > &s, const unsigned &i) const
Return FE interpolated coordinate x[i] at local coordinate s.
Definition: elements.cc:3992
unsigned nnode() const
Return the number of nodes.
Definition: elements.h:2214
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
MacroElement * macro_elem_pt()
Access function to pointer to macro element.
Definition: elements.h:1882
Class for multidimensional Gauss Lobatto Legendre integration rules empty - just establishes template...
Definition: integral.h:1309
A Generalised Element class.
Definition: elements.h:73
Class that contains data for hanging nodes.
Definition: nodes.h:742
double const & master_weight(const unsigned &i) const
Return weight for dofs on i-th master node.
Definition: nodes.h:808
Node *const & master_node_pt(const unsigned &i) const
Return a pointer to the i-th master node.
Definition: nodes.h:791
unsigned nmaster() const
Return the number of master nodes.
Definition: nodes.h:785
void set_master_node_pt(const unsigned &i, Node *const &master_node_pt, const double &weight)
Set the pointer to the i-th master node and its weight.
Definition: nodes.cc:1474
////////////////////////////////////////////////////////////////////
Vector< GeomObject * > & geom_object_pt()
Vector of (pointers to) geometric objects involved in node update function.
virtual void set_node_update_info(const Vector< GeomObject * > &geom_object_pt)=0
Set node update information: Pass the vector of (pointers to) the geometric objects that affect the n...
////////////////////////////////////////////////////////////////////
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
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition: nodes.h:1060
HangInfo *const & hanging_pt() const
Return pointer to hanging node data (this refers to the geometric hanging node status) (const version...
Definition: nodes.h:1228
unsigned ndim() const
Return (Eulerian) spatial dimension of the node.
Definition: nodes.h:1054
virtual void set_coordinates_on_boundary(const unsigned &b, const unsigned &k, const Vector< double > &boundary_zeta)
Set the vector of the k-th generalised boundary coordinates on mesh boundary b. Broken virtual interf...
Definition: nodes.cc:2394
virtual void make_periodic(Node *const &node_pt)
Make the node periodic by copying the values from node_pt. Note that the coordinates will always rema...
Definition: nodes.cc:2257
unsigned nposition_type() const
Number of coordinate types needed in the mapping between local and global coordinates.
Definition: nodes.h:1016
OcTree class: Recursively defined, generalised octree.
Definition: octree.h:114
static Vector< int > faces_of_common_edge(const int &edge)
Function that, given an edge, returns the two faces on which it.
Definition: octree.cc:268
OcTree * gteq_face_neighbour(const int &direction, Vector< unsigned > &translate_s, Vector< double > &s_sw, Vector< double > &s_ne, int &face, int &diff_level, bool &in_neighbouring_tree) const
Find (pointer to) ‘greater-or-equal-sized face neighbour’ in given direction (L/R/U/D/F/B)....
Definition: octree.cc:3373
OcTree * gteq_true_edge_neighbour(const int &direction, const unsigned &i_root_edge_neighbour, unsigned &nroot_edge_neighbour, Vector< unsigned > &translate_s, Vector< double > &s_lo, Vector< double > &s_hi, int &edge, int &diff_level) const
Find (pointer to) ‘greater-or-equal-sized true edge neighbour’ in the given direction (LB,...
Definition: octree.cc:3618
Class that returns the shape functions associated with legendre.
Definition: shape.h:1234
static double nodal_position(const unsigned &n)
Definition: shape.h:1250
static void calculate_nodal_positions()
Static function used to populate the stored positions.
Definition: shape.h:1241
An OomphLibError object which should be thrown when an run-time error is encountered....
An OomphLibWarning object which should be created as a temporary object to issue a warning....
/////////////////////////////////////////////////////////////////// /////////////////////////////////...
unsigned & p_order()
Access function to P_order.
p-refineable version of RefineableQElement<1,INITIAL_NNODE_1D>. Generic class definitions
Node * get_node_at_local_coordinate(const Vector< double > &s) const
Return the node at the specified local coordinate.
p-refineable version of RefineableQElement<2,INITIAL_NNODE_1D>.
Node * get_node_at_local_coordinate(const Vector< double > &s) const
Return the node at the specified local coordinate.
p-refineable version of RefineableQElement<3,INITIAL_NNODE_1D>.
Node * get_node_at_local_coordinate(const Vector< double > &s) const
Return the node at the specified local coordinate.
A class that is used to template the p-refineable Q elements by dimension. It's really nothing more t...
Definition: Qelements.h:2274
double & s_macro_ll(const unsigned &i)
Access fct to the i-th coordinate of the element's "lower left" vertex in the associated MacroElement...
Definition: Qelements.h:186
double & s_macro_ur(const unsigned &i)
Access fct to the i-th coordinate of the element's "upper right" vertex in the associated MacroElemen...
Definition: Qelements.h:202
QuadTree class: Recursively defined, generalised quadtree.
Definition: quadtree.h:104
QuadTree * gteq_edge_neighbour(const int &direction, Vector< unsigned > &translate_s, Vector< double > &s_lo, Vector< double > &s_hi, int &edge, int &diff_level, bool &in_neighbouring_tree) const
Return pointer to greater or equal-sized edge neighbour in specified direction; also provide info reg...
Definition: quadtree.cc:413
virtual bool nodes_built()
Return true if all the nodes have been built, false if not.
virtual unsigned ncont_interpolated_values() const =0
Number of continuously interpolated values. Note: We assume that they are located at the beginning of...
virtual unsigned ninterpolating_node_1d(const int &value_id)
Return the number of nodes in a one_d direction that are used to interpolate the value_id-th unknown....
virtual unsigned ninterpolating_node(const int &value_id)
Return the number of nodes that are used to interpolate the value_id-th unknown. Default is to assume...
virtual void interpolating_basis(const Vector< double > &s, Shape &psi, const int &value_id) const
Return the basis functions that are used to interpolate the value_id-th unknown. By default assume is...
virtual Node * interpolating_node_pt(const unsigned &n, const int &value_id)
In mixed elements, different sets of nodes are used to interpolate different unknowns....
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...
Refineable version of QElement<2,NNODE_1D>.
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)
Refineable version of QElement<3,NNODE_1D>.
void interpolated_zeta_on_face(const unsigned &boundary, const int &face, const Vector< double > &s, Vector< double > &zeta)
Return the value of the intrinsic boundary coordinate interpolated along the face.
void get_bcs(int bound, Vector< int > &bound_cons) const
Determine Vector of boundary conditions along the element's boundary (or vertex) bound (S/W/N/E/SW/SE...
void get_boundaries(const int &edge, std::set< unsigned > &boundaries) const
Given an element edge/vertex, return a Vector which contains all the (mesh-)boundary numbers that thi...
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 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...
Refineable version of Solid brick 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 shape functions. In simple cases, the shape functions have only one index that can be tho...
Definition: shape.h:76
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
bool is_neighbour_periodic(const int &direction)
Return whether the neighbour in the particular direction is periodic.
Definition: tree.h:364
A generalised tree base class that abstracts the common functionality between the quad- and octrees u...
Definition: tree.h:74
RefineableElement * object_pt() const
Return the pointer to the object (RefineableElement) represented by the tree.
Definition: tree.h:88
unsigned nsons() const
Return number of sons (zero if it's a leaf node)
Definition: tree.h:129
int son_type() const
Return son type.
Definition: tree.h:214
static const int OMEGA
Default value for an unassigned neighbour.
Definition: tree.h:262
Tree * son_pt(const int &son_index) const
Return pointer to the son for a given index. Note that to aid code readability specific enums have be...
Definition: tree.h:103
TreeRoot *& root_pt()
Return pointer to root of the tree.
Definition: tree.h:141
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
void shape(const double &s, double *Psi)
Definition for 1D Lagrange shape functions. The value of all the shape functions at the local coordin...
Definition: shape.h:564
double dlegendre(const unsigned &p, const double &x)
Calculates first derivative of Legendre polynomial of degree p at x using three term recursive formul...
Definition: orthpoly.h:121
double ddlegendre(const unsigned &p, const double &x)
Calculates second derivative of Legendre polynomial of degree p at x using three term recursive formu...
Definition: orthpoly.h:144
void gll_nodes(const unsigned &Nnode, Vector< double > &x)
Calculates the Gauss Lobatto Legendre abscissas for degree p = NNode-1.
Definition: orthpoly.cc:33
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
OomphInfo oomph_info
Single (global) instantiation of the OomphInfo object – this is used throughout the library as a "rep...