Qelements.h
Go to the documentation of this file.
1 //LIC// ====================================================================
2 //LIC// This file forms part of oomph-lib, the object-oriented,
3 //LIC// multi-physics finite-element library, available
4 //LIC// at http://www.oomph-lib.org.
5 //LIC//
6 //LIC// Version 1.0; svn revision $LastChangedRevision$
7 //LIC//
8 //LIC// $LastChangedDate$
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 //Header functions for classes that define Qelements
31 //Include guards to prevent multiple inclusion of the header
32 #ifndef OOMPH_QELEMENT_HEADER
33 #define OOMPH_QELEMENT_HEADER
34 
35 // Config header generated by autoconfig
36 #ifdef HAVE_CONFIG_H
37  #include <oomph-lib-config.h>
38 #endif
39 
40 
41 #ifdef OOMPH_HAS_MPI
42 #include "mpi.h"
43 #endif
44 
45 //oomph-lib headers
46 #include "Vector.h"
47 #include "shape.h"
48 #include "integral.h"
49 #include "timesteppers.h"
50 #include "elements.h"
51 #include "macro_element.h"
52 
54 
55 
56 
57 namespace oomph
58 {
59 
60 
61 //////////////////////////////////////////////////////////////////////
62 //////////////////////////////////////////////////////////////////////
63 //////////////////////////////////////////////////////////////////////
64 
65 //========================================================================
66 /// Empty base class for Qelements (created so that
67 /// we can use dynamic_cast<>() to figure out if a an element
68 /// is a Qelement (from a purely geometric point of view).
69 //========================================================================
70  class QElementGeometricBase : public virtual FiniteElement
71 {
72 
73  public:
74 
75  /// Empty default constructor
77 
78  /// Broken copy constructor
80  {
81  BrokenCopy::broken_copy("QElementGeometricBase");
82  }
83 
84  /// Broken assignment operator
85 //Commented out broken assignment operator because this can lead to a conflict warning
86 //when used in the virtual inheritence hierarchy. Essentially the compiler doesn't
87 //realise that two separate implementations of the broken function are the same and so,
88 //quite rightly, it shouts.
89  /*void operator=(const QElementGeometricBase&)
90  {
91  BrokenCopy::broken_assign("QElementGeometricBase");
92  }*/
93 
94 
95 };
96 
97 
98 //////////////////////////////////////////////////////////////////////
99 //////////////////////////////////////////////////////////////////////
100 //////////////////////////////////////////////////////////////////////
101 
102 
103 //========================================================================
104 /// Base class for Qelements
105 //========================================================================
106 class QElementBase : public virtual QElementGeometricBase
107 {
108  public:
109 
110  /// Constructor: Initialise pointers to macro element reference coords
111  QElementBase() : S_macro_ll_pt(0), S_macro_ur_pt(0)
112  {}
113 
114  /// Broken copy constructor
116  {
117  BrokenCopy::broken_copy("QElementBase");
118  }
119 
120  /// Broken assignment operator
121  /*void operator=(const QElementBase&)
122  {
123  BrokenCopy::broken_assign("QElementBase");
124  }*/
125 
126  /// Destructor: Kill storage for macro element reference coords
127  virtual ~QElementBase()
128  {
129  // Can be deleted blindly as they were nulled initially
130  delete S_macro_ll_pt;
131  S_macro_ll_pt=0;
132  delete S_macro_ur_pt;
133  S_macro_ur_pt=0;
134  }
135 
136  ///Check whether the local coordinate are valid or not
138  {
139  unsigned ncoord = dim();
140  for(unsigned i=0;i<ncoord;i++)
141  {
142  // We're outside
143  if((s[i] - s_max() > 0.0) ||
144  (s_min() - s[i] > 0.0))
145  {
146  return false;
147  }
148  }
149  return true;
150  }
151 
152  /// \short Adjust local coordinates so that they're located inside
153  /// the element
155  {
156  unsigned ncoord = dim();
157  for(unsigned i=0;i<ncoord;i++)
158  {
159  // Adjust to move it onto the boundary
160  if (s[i] > s_max() ) s[i] = s_max();
161  if (s[i] < s_min() ) s[i] = s_min();
162  }
163  }
164 
165 
166  /// \short Set pointer to macro element also sets up storage for the
167  /// reference coordinates and initialises them
169  {
170  // Get the spatial dimension (= number of local and macro element coords)
171  unsigned n_dim=dim();
172 
173  // Create storage if none has been allocated
174  if(S_macro_ll_pt==0)
175  {
176  S_macro_ll_pt=new Vector<double>(n_dim);
177  }
178  //Otherwise resize the allocated storage
179  else
180  {
181  S_macro_ll_pt->resize(n_dim);
182  }
183 
184  //Create storage if none has been allocated
185  if(S_macro_ur_pt==0)
186  {
187  S_macro_ur_pt=new Vector<double>(n_dim);
188  }
189  //Otherwise resize the allocated storage
190  else
191  {
192  S_macro_ur_pt->resize(n_dim);
193  }
194 
195  // Initialise the vertex coordinates in the macro element
196  // Default: The element is unrefined and hence its vertices are those
197  // of the macro element itself
198  for (unsigned i=0;i<n_dim;i++)
199  {
200  s_macro_ll(i)=-1.0;
201  s_macro_ur(i)= 1.0;
202  }
203 
204  /// Call the corresponding function in the FiniteElement base class
205  FiniteElement::set_macro_elem_pt(macro_elem_pt);
206  }
207 
208 
209  /// \short Access fct to the i-th coordinate of the element's
210  /// "lower left" vertex in the associated MacroElement
211  double& s_macro_ll(const unsigned& i)
212  {
213 #ifdef PARANOID
214  if (S_macro_ll_pt==0)
215  {
216  throw OomphLibError("S_macro_ll_pt has not been set\n",
217  OOMPH_CURRENT_FUNCTION,
218  OOMPH_EXCEPTION_LOCATION);
219  }
220 #endif
221  return (*S_macro_ll_pt)[i];
222  }
223 
224 
225 
226  /// \short Access fct to the i-th coordinate of the element's
227  /// "upper right" vertex in the associated MacroElement
228  double& s_macro_ur(const unsigned& i)
229  {
230 #ifdef PARANOID
231  if (S_macro_ur_pt==0)
232  {
233  throw OomphLibError("S_macro_ur_pt has not been set\n",
234  OOMPH_CURRENT_FUNCTION,
235  OOMPH_EXCEPTION_LOCATION);
236  }
237 #endif
238  return (*S_macro_ur_pt)[i];
239  }
240 
241 
242 
243  /// \short Access fct to the i-th coordinate of the element's
244  /// "lower left" vertex in the associated MacroElement. (const version)
245  double s_macro_ll(const unsigned& i) const
246  {
247 #ifdef PARANOID
248  if (S_macro_ll_pt==0)
249  {
250  throw OomphLibError("S_macro_ll_pt has not been set\n",
251  OOMPH_CURRENT_FUNCTION,
252  OOMPH_EXCEPTION_LOCATION);
253  }
254 #endif
255  return (*S_macro_ll_pt)[i];
256  }
257 
258 
259 
260  /// \short Access fct to the i-th coordinate of the element's
261  /// "upper right" vertex in the associated MacroElement. (const version)
262  double s_macro_ur(const unsigned& i) const
263  {
264 #ifdef PARANOID
265  if (S_macro_ur_pt==0)
266  {
267  throw OomphLibError("S_macro_ur_pt has not been set\n",
268  OOMPH_CURRENT_FUNCTION,
269  OOMPH_EXCEPTION_LOCATION);
270  }
271 #endif
272  return (*S_macro_ur_pt)[i];
273  }
274 
275  /// \short Global coordinates as function of local coordinates.
276  /// using the macro element representation
278  Vector<double> &x) const
279  {
280  //Check that there is a macro element
281  if(Macro_elem_pt==0)
282  {
283  throw OomphLibError(
284  "Macro Element pointer not set in this element\n",
285  OOMPH_CURRENT_FUNCTION,
286  OOMPH_EXCEPTION_LOCATION);
287  }
288 
289  //Use macro element representation
290  unsigned el_dim = dim();
291  Vector<double> s_macro(el_dim);
292  for(unsigned i=0;i<el_dim;i++)
293  {
294  s_macro[i]=s_macro_ll(i)+0.5*(s[i]+1.0)*(s_macro_ur(i)-s_macro_ll(i));
295  }
296  Macro_elem_pt->macro_map(s_macro,x);
297  }
298 
299  /// \short Global coordinates as function of local coordinates
300  /// at previous time "level" t (t=0: present; t>0: previous)
301  /// using the macro element representation
302  void get_x_from_macro_element(const unsigned& t, const Vector<double>& s,
303  Vector<double>& x)
304  {
305  //Check that there is a macro element
306  if(Macro_elem_pt==0)
307  {
308  throw OomphLibError(
309  "Macro Element pointer not set in this element\n",
310  OOMPH_CURRENT_FUNCTION,
311  OOMPH_EXCEPTION_LOCATION);
312  }
313 
314  //Use the macro element representation
315  unsigned el_dim = dim();
316  Vector<double> s_macro(el_dim);
317  for(unsigned i=0;i<el_dim;i++)
318  {
319  s_macro[i]=s_macro_ll(i)+0.5*(s[i]+1.0)*(s_macro_ur(i)-s_macro_ll(i));
320  }
321  Macro_elem_pt->macro_map(t,s_macro,x);
322  }
323 
324  /// Return number of nodes on one face of the element. Always
325  /// nnode_1d^(el_dim - 1).
326  unsigned nnode_on_face() const
327  {
328  // c++ doesn't have pow(int, int) so we have to use all these casts...
329  return static_cast<unsigned>(std::pow(static_cast<double>(nnode_1d()),
330  static_cast<double>(dim()-1)));
331  }
332 
333  /// It's a Q element!
335  {
336  return ElementGeometry::Q;
337  }
338 
339  private:
340 
341  /// Pointer to vector of lower left vertex coords. in macro element
343 
344  /// Pointer to vector of upper right vertex coords. in macro element
346 
347 };
348 
349 
350 //////////////////////////////////////////////////////////////////////////
351 //////////////////////////////////////////////////////////////////////////
352 //////////////////////////////////////////////////////////////////////////
353 
354 
355 
356 //========================================================================
357 /// Base class for Solid Qelements
358 //========================================================================
359 class QSolidElementBase : public virtual QElementBase,
360  public virtual SolidFiniteElement
361 {
362  public:
363 
364  /// Constructor: Empty
366 
367  /// Broken copy constructor
369  {
370  BrokenCopy::broken_copy("QSolidElementBase");
371  }
372 
373  /// Broken assignment operator
374  /*void operator=(const QSolidElementBase&)
375  {
376  BrokenCopy::broken_assign("QSolidElementBase");
377  }*/
378 
379  /// \short Set pointer to MacroElement -- overloads generic version
380  /// in RefineableQElement<2> and uses the MacroElement
381  /// also as the default for the "undeformed" configuration.
382  /// This assignment can/must be overwritten with
383  /// set_undeformed_macro_elem_pt(...) if the deformation of
384  /// the solid body is driven by a deformation of the
385  /// "current" Domain/MacroElement representation of it's boundary.
387  {
388  // Call the general Q version which sets up the storage
389  // for the reference coordinates
390  QElementBase::set_macro_elem_pt(macro_elem_pt);
391  // Store pointer to macro element that represents the exact
392  // undeformed geomtry
393  set_undeformed_macro_elem_pt(macro_elem_pt);
394  }
395 
396  /// \short Set pointers to "current" and "undeformed" MacroElements.
398  MacroElement* undeformed_macro_elem_pt)
399  {
400  // Call the general Q version which sets up the storage
401  // for the reference coordinates
402  QElementBase::set_macro_elem_pt(macro_elem_pt);
403  // Store pointer to macro element that represents the exact
404  // undeformed geomtry
405  set_undeformed_macro_elem_pt(undeformed_macro_elem_pt);
406  }
407 
408  /// \short Eulerian and Lagrangian coordinates as function of the
409  /// local coordinates: The Eulerian position is returned in
410  /// FE-interpolated form (\c x_fe) and then in the form obtained
411  /// from the "current" MacroElement representation (if it exists -- if not,
412  /// \c x is the same as \c x_fe). This allows the Domain/MacroElement-
413  /// based representation to be used to apply displacement boundary
414  /// conditions exactly. Ditto for the Lagrangian coordinates returned
415  /// in xi_fe and xi.
417  Vector<double>& x_fe,
418  Vector<double>& x,
419  Vector<double>& xi_fe,
420  Vector<double>& xi) const
421  {
422  // Lagrangian coordinate: Directly from
423  // underlying FE representation
424  unsigned n_xi = xi_fe.size();
425  for(unsigned i=0;i<n_xi;i++) {xi_fe[i] = interpolated_xi(s,i);}
426 
427  // Lagrangian coordinate from FE representation again
428  if(Undeformed_macro_elem_pt==0)
429  {
430  unsigned n_xi = xi.size();
431  for(unsigned i=0;i<n_xi;i++) {xi[i] = xi_fe[i];}
432  }
433  // ...or refer to the "undeformed" MacroElement if it exists.
434  else
435  {
436  unsigned el_dim = dim();
437  Vector<double> s_macro(el_dim);
438  for(unsigned i=0;i<el_dim;i++)
439  {
440  s_macro[i]=s_macro_ll(i)+0.5*(s[i]+1.0)*(s_macro_ur(i)-s_macro_ll(i));
441  }
442  Undeformed_macro_elem_pt->macro_map(s_macro,xi);
443  }
444 
445 
446  // Eulerian coordinate directly from underlying FE representation
447  unsigned n_x=x_fe.size();
448  for(unsigned i=0;i<n_x;i++) {x_fe[i] = interpolated_x(s,i);}
449 
450  // Eulerian coordinate from FE representation again:
451  if(Macro_elem_pt==0)
452  {
453  for(unsigned i=0;i<n_x;i++) {x[i] = x_fe[i];}
454  }
455  // or refer to the "current" MacroElement if it exists.
456  else
457  {
458  unsigned el_dim = dim();
459  Vector<double> s_macro(el_dim);
460  for(unsigned i=0;i<el_dim;i++)
461  {
462  s_macro[i]=s_macro_ll(i)+0.5*(s[i]+1.0)*(s_macro_ur(i)-s_macro_ll(i));
463  }
464  Macro_elem_pt->macro_map(s_macro,x);
465  }
466  }
467 
468 };
469 
470 
471 
472 
473 //////////////////////////////////////////////////////////////////////////
474 //////////////////////////////////////////////////////////////////////////
475 //////////////////////////////////////////////////////////////////////////
476 
477 
478 
479 //=======================================================================
480 /// General QElement class
481 ///
482 /// Empty, just establishes the template parameters
483 //=======================================================================
484 template<unsigned DIM, unsigned NNODE_1D>
485  class QElement
486 {
487 };
488 
489 //=======================================================================
490 /// Base class for all line elements
491 //=======================================================================
492 class LineElementBase : public virtual QElementBase
493 {
494  public:
495 
496  /// Constructor. Empty
498 
499  /// \short Number of vertex nodes in the element
500  virtual unsigned nvertex_node() const=0;
501 
502  /// \short Pointer to the j-th vertex node in the element
503  virtual Node* vertex_node_pt(const unsigned& j) const=0;
504 
505 };
506 
507 //=======================================================================
508 /// General QElement class specialised to one spatial dimension
509 //=======================================================================
510 template<unsigned NNODE_1D>
511 class QElement<1,NNODE_1D> : public virtual LineElementBase
512 {
513  private:
514 
515  /// \short Default integration rule: Gaussian integration of same 'order'
516  /// as the element
517  //This is sort of optimal, because it means that the integration is exact
518  //for the shape functions. Can overwrite this in specific element defintion.
520 
521 public:
522 
523  /// Constructor
525  {
526  //There are NNODE_1D nodes in this element
527  this->set_n_node(NNODE_1D);
528  //Set the dimensions of the element and the nodes, by default, both 1D
529  this->set_dimension(1);
530  //Assign pointer to default (full) integration_scheme
531  this->set_integration_scheme(&Default_integration_scheme);
532  }
533 
534  /// Broken copy constructor
536  {
537  BrokenCopy::broken_copy("QElement");
538  }
539 
540  /// Broken assignment operator
541  /*void operator=(const QElement&)
542  {
543  BrokenCopy::broken_assign("QElement");
544  }*/
545 
546  /// Calculate the geometric shape functions at local coordinate s
547  void shape(const Vector<double> &s, Shape &psi) const;
548 
549  /// \short Compute the geometric shape functions and
550  /// derivatives w.r.t. local coordinates at local coordinate s
551  void dshape_local(const Vector<double> &s, Shape &psi, DShape &dpsids)
552  const;
553 
554  /// \short Compute the geometric shape functions, derivatives and
555  /// second derivatives w.r.t. local coordinates at local coordinate s
556  /// d2psids(i,0) = \f$ d^2 \psi_j / d s^2 \f$
557  void d2shape_local(const Vector<double> &s, Shape &psi, DShape &dpsids,
558  DShape &d2psids) const;
559 
560  /// \short Overload the template-free interface for the calculation of
561  /// inverse jacobian matrix. This is a one-dimensional element, so
562  /// use the 1D version.
564  DenseMatrix<double> &inverse_jacobian) const
565  {return FiniteElement::invert_jacobian<1>(jacobian,inverse_jacobian);}
566 
567  /// Min. value of local coordinate
568  double s_min() const {return -1.0;}
569 
570  /// Max. value of local coordinate
571  double s_max() const {return 1.0;}
572 
573  /// \short Number of vertex nodes in the element
574  unsigned nvertex_node() const
575  {return 2;}
576 
577  /// \short Pointer to the j-th vertex node in the element
578  Node* vertex_node_pt(const unsigned& j) const
579  {
580  unsigned n_node_1d=nnode_1d();
581  Node* nod_pt;
582  switch(j)
583  {
584  case 0:
585  nod_pt=node_pt(0);
586  break;
587  case 1:
588  nod_pt=node_pt(n_node_1d-1);
589  break;
590  default:
591  std::ostringstream error_message;
592  error_message << "Vertex node number is " << j <<
593  " but must be from 0 to 1\n";
594 
595  throw OomphLibError(error_message.str(),
596  OOMPH_CURRENT_FUNCTION,
597  OOMPH_EXCEPTION_LOCATION);
598  }
599  return nod_pt;
600  }
601 
602  /// Get local coordinates of node j in the element; vector sets its own size
603  void local_coordinate_of_node(const unsigned& j, Vector<double>& s) const
604  {
605  s.resize(1);
606  s[0]=this->s_min()+double(j)/double(NNODE_1D-1)*
607  (this->s_max()-this->s_min());
608  }
609 
610 
611  /// Get the local fraction of node j in the element
612  void local_fraction_of_node(const unsigned &j,
613  Vector<double> &s_fraction)
614  {
615  s_fraction.resize(1);
616  s_fraction[0] = double(j)/double(NNODE_1D-1);
617  }
618 
619 
620  /// This function returns the local fraction of all nodes at the n-th
621  /// position in a one dimensional expansion along the i-th local coordinate
623  const unsigned &n1d,const unsigned &i)
624  {
625  //It's just the value of the node divided by the number of 1-D nodes
626  return double(n1d)/double(NNODE_1D-1);
627  }
628 
629  /// Get the node at the specified local coordinate
631 
632  /// Number of nodes along each element edge
633  unsigned nnode_1d() const {return NNODE_1D;}
634 
635  /// \short Return the number of actual plot points for paraview
636  /// plot with parameter nplot.
637  unsigned nplot_points_paraview(const unsigned& nplot) const
638  {
639  return nplot;
640  }
641 
642  /// \short Return the number of local sub-elements for paraview plot with
643  /// parameter nplot.
644  unsigned nsub_elements_paraview(const unsigned& nplot) const
645  {
646  return (nplot-1);
647  }
648 
649  /// \short Fill in the offset information for paraview plot.
650  /// Needs to be implemented for each new geometric element type; see
651  /// http://www.vtk.org/VTK/img/file-formats.pdf
652  void write_paraview_output_offset_information(std::ofstream& file_out,
653  const unsigned& nplot,
654  unsigned& counter) const
655  {
656  // Number of local elements we want to plot over
657  unsigned plot=nsub_elements_paraview(nplot);
658 
659  // loops over the i-th local element in parent element
660  for(unsigned i=0;i<plot;i++)
661  {
662  file_out << i+counter << " "
663  << i+1+counter
664  << std::endl;
665  }
666  counter+=nplot_points_paraview(nplot);
667  }
668 
669  /// \short Return the paraview element type.
670  /// Needs to be implemented for each new geometric element type; see
671  /// http://www.vtk.org/VTK/img/file-formats.pdf
672  /// Use type "VTK_LINE" (== 3) for 2D quad elements
673  void write_paraview_type(std::ofstream& file_out,
674  const unsigned& nplot) const
675  {
676  unsigned local_loop=nsub_elements_paraview(nplot);
677  for(unsigned i=0;i<local_loop;i++)
678  {
679  file_out << "3" << std::endl;
680  }
681  }
682 
683  /// \short Return the offsets for the paraview sub-elements. Needs
684  /// to be implemented for each new geometric element type; see
685  /// http://www.vtk.org/VTK/img/file-formats.pdf
686  void write_paraview_offsets(std::ofstream& file_out,
687  const unsigned& nplot,
688  unsigned& offset_sum) const
689  {
690  // Loop over all local elements and add its offset to the overall offset_sum
691  unsigned local_loop=nsub_elements_paraview(nplot);
692  for(unsigned i=0;i<local_loop;i++)
693  {
694  offset_sum+=2;
695  file_out << offset_sum << std::endl;
696  }
697  }
698 
699  /// Output
700  void output(std::ostream &outfile);
701 
702  /// Output at n_plot points
703  void output(std::ostream &outfile, const unsigned &n_plot);
704 
705  /// C-style output
706  void output(FILE* file_pt);
707 
708  /// C_style output at n_plot points
709  void output(FILE* file_pt, const unsigned &n_plot);
710 
711 
712  /// \short Get cector of local coordinates of plot point i (when plotting
713  /// nplot points in each "coordinate direction).
715  const unsigned& i,
716  const unsigned& nplot,
717  Vector<double>& s,
718  const bool& use_equally_spaced_interior_sample_points=false) const
719  {
720  if (nplot>1)
721  {
722  s[0]=-1.0+2.0*double(i)/double(nplot-1);
723  if (use_equally_spaced_interior_sample_points)
724  {
725  double range=2.0;
726  double dx_new=range/double(nplot);
727  double range_new=double(nplot-1)*dx_new;
728  s[0]=-1.0+0.5*dx_new+range_new*(1.0+s[0])/range;
729  }
730  }
731  else
732  {
733  s[0]=0.0;
734  }
735  }
736 
737  /// \short Return string for tecplot zone header (when plotting
738  /// nplot points in each "coordinate direction)
739  std::string tecplot_zone_string(const unsigned& nplot) const
740  {
741  std::ostringstream header;
742  header << "ZONE I=" << nplot << "\n";
743  return header.str();
744  }
745 
746  /// \short Return total number of plot points (when plotting
747  /// nplot points in each "coordinate direction)
748  unsigned nplot_points(const unsigned& nplot) const
749  {
750  unsigned DIM=1;
751  unsigned np=1;
752  for (unsigned i=0;i<DIM;i++) {np*=nplot;}
753  return np;
754  }
755 
756  /// Get the number of the ith node on face face_index in the bulk node
757  /// vector.
758  unsigned get_bulk_node_number(const int& face_index,
759  const unsigned& i) const
760  {
762 
763  if(face_index == -1) {return 0;}
764  else if(face_index == +1) {return nnode_1d() - 1;}
765  else
766  {
767  std::string err = "Face index should be in {-1, +1}.";
768  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
769  OOMPH_CURRENT_FUNCTION);
770  }
771  }
772 
773  /// Get the sign of the outer unit normal on the face given by face_index.
774  int face_outer_unit_normal_sign(const int& face_index) const
775  {
776 #ifdef PARANOID
777  if(std::abs(face_index) != 1)
778  {
779  std::string err = "Face index should be in {-1, +1}.";
780  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
781  OOMPH_CURRENT_FUNCTION);
782  }
783 #endif
784  return face_index;
785  }
786 
787  /// Get a pointer to the function mapping face coordinates to bulk coordinates
789  (const int& face_index) const
790  {
791  if(face_index == 1) {return &QElement1FaceToBulkCoordinates::face1;}
792  else if(face_index == -1) {return &QElement1FaceToBulkCoordinates::face0;}
793  else
794  {
795  std::string err = "Face index should be in {-1, +1}.";
796  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
797  OOMPH_CURRENT_FUNCTION);
798  }
799  }
800 
801  /// Get a pointer to the derivative of the mapping from face to bulk
802  /// coordinates.
804  (const int& face_index) const
805  {
806  if(face_index == 1) {return &QElement1BulkCoordinateDerivatives::faces0;}
807  else if (face_index == -1) {return &QElement1BulkCoordinateDerivatives::faces0;}
808  else
809  {
810  std::string err = "Face index should be in {-1, +1}.";
811  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
812  OOMPH_CURRENT_FUNCTION);
813  }
814  }
815 
816 };
817 
818 //=======================================================================
819 /// Base class for all quad elements
820 //=======================================================================
821 class QuadElementBase : public virtual QElementBase
822 {
823  public:
824 
825  /// Constructor. Empty
827 
828  /// \short Number of vertex nodes in the element
829  virtual unsigned nvertex_node() const=0;
830 
831  /// \short Pointer to the j-th vertex node in the element
832  virtual Node* vertex_node_pt(const unsigned& j) const=0;
833 
834 };
835 
836 //=======================================================================
837 /// General QElement class specialised to two spatial dimensions
838 //=======================================================================
839 template<unsigned NNODE_1D>
840 class QElement<2,NNODE_1D> : public virtual QuadElementBase
841 {
842  private:
843 
844  /// \short Default integration rule: Gaussian integration of same 'order'
845  /// as the element
846  //N.B. This is sort of optimal, because it means that the integration is exact
847  //for the shape functions. Can overwrite this in specific element defintion
849 
850 public:
851 
852  ///Constructor
854  {
855  //There are NNODE_1D*NNODE_1D nodes in this element
856  this->set_n_node(NNODE_1D*NNODE_1D);
857  //Set the dimensions of the element and the nodes, by default, both 2D
858  set_dimension(2);
859  //Assign default (full) spatial integration scheme
860  set_integration_scheme(&Default_integration_scheme);
861  }
862 
863  /// Broken copy constructor
865  {
866  BrokenCopy::broken_copy("QElement");
867  }
868 
869  /// Broken assignment operator
870  /*void operator=(const QElement&)
871  {
872  BrokenCopy::broken_assign("QElement");
873  }*/
874 
875  /// Calculate the geometric shape functions at local coordinate s
876  void shape(const Vector<double> &s, Shape &psi) const;
877 
878  /// \short Compute the geometric shape functions and
879  /// derivatives w.r.t. local coordinates at local coordinate s
880  void dshape_local(const Vector<double> &s, Shape &psi, DShape &dpsids)
881  const;
882 
883  /// \short Compute the geometric shape functions, derivatives and
884  /// second derivatives w.r.t. local coordinates at local coordinate s
885  /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
886  /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
887  /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
888  void d2shape_local(const Vector<double> &s, Shape &psi, DShape &dpsids,
889  DShape &d2psids) const;
890 
891  /// \short Overload the template-free interface for the calculation of
892  /// inverse jacobian matrix. This is a two-dimensional element, so use
893  /// the two-d version.
895  DenseMatrix<double> &inverse_jacobian) const
896  {return FiniteElement::invert_jacobian<2>(jacobian,inverse_jacobian);}
897 
898  /// Min. value of local coordinate
899  double s_min() const {return -1.0;}
900 
901  /// Max. value of local coordinate
902  double s_max() const {return 1.0;}
903 
904 
905  /// \short Number of vertex nodes in the element
906  unsigned nvertex_node() const
907  {return 4;}
908 
909  /// \short Pointer to the j-th vertex node in the element
910  Node* vertex_node_pt(const unsigned& j) const
911  {
912  unsigned n_node_1d=nnode_1d();
913  Node* nod_pt;
914  switch(j)
915  {
916  case 0:
917  nod_pt=node_pt(0);
918  break;
919  case 1:
920  nod_pt=node_pt(n_node_1d-1);
921  break;
922  case 2:
923  nod_pt=node_pt(n_node_1d*(n_node_1d-1));
924  break;
925  case 3:
926  nod_pt=node_pt(n_node_1d*n_node_1d-1);
927  break;
928  default:
929  std::ostringstream error_message;
930  error_message << "Vertex node number is " << j <<
931  " but must be from 0 to 3\n";
932 
933  throw OomphLibError(error_message.str(),
934  OOMPH_CURRENT_FUNCTION,
935  OOMPH_EXCEPTION_LOCATION);
936  }
937  return nod_pt;
938  }
939 
940 
941  /// Get local coordinates of node j in the element; vector sets its own size
942  void local_coordinate_of_node(const unsigned& j, Vector<double>& s) const
943  {
944  s.resize(2);
945  unsigned j0=j%NNODE_1D;
946  unsigned j1=j/NNODE_1D;
947  const double S_min = this->s_min();
948  const double S_range = this->s_max() - S_min;
949  s[0]=S_min+double(j0)/double(NNODE_1D-1)*S_range;
950  s[1]=S_min+double(j1)/double(NNODE_1D-1)*S_range;
951  }
952 
953  /// Get the local fraction of node j in the element
954  void local_fraction_of_node(const unsigned &j,
955  Vector<double> &s_fraction)
956  {
957  s_fraction.resize(2);
958  unsigned j0 = j%NNODE_1D;
959  unsigned j1 = j/NNODE_1D;
960  s_fraction[0] = double(j0)/double(NNODE_1D-1);
961  s_fraction[1] = double(j1)/double(NNODE_1D-1);
962  }
963 
964  /// This function returns the local fraction of ant nodes in the n-th positoin
965  /// in a one dimensional expansion along the i-th local coordinate
966  inline double local_one_d_fraction_of_node(const unsigned &n1d,
967  const unsigned &i)
968  {
969  //It's just the value of the node divided by the number of 1-D nodes
970  return double(n1d)/double(NNODE_1D-1);
971  }
972 
973  /// Get the node at the specified local coordinate
975 
976  /// Number of nodes along each element edge
977  unsigned nnode_1d() const {return NNODE_1D;}
978 
979  /// \short Return the number of actual plot points for paraview
980  /// plot with parameter nplot.
981  unsigned nplot_points_paraview(const unsigned& nplot) const
982  {
983  return nplot*nplot;
984  }
985 
986  /// \short Return the number of local sub-elements for paraview plot with
987  /// parameter nplot.
988  unsigned nsub_elements_paraview(const unsigned& nplot) const
989  {
990  return (nplot-1)*(nplot-1);
991  }
992 
993  /// \short Fill in the offset information for paraview plot.
994  /// Needs to be implemented for each new geometric element type; see
995  /// http://www.vtk.org/VTK/img/file-formats.pdf
996  void write_paraview_output_offset_information(std::ofstream& file_out,
997  const unsigned& nplot,
998  unsigned& counter) const
999  {
1000  // Number of local elements we want to plot over
1001  unsigned plot=nsub_elements_paraview(nplot);
1002 
1003  // loops over the i-th local element in parent element
1004  for(unsigned i=0;i<plot;i++)
1005  {
1006  unsigned d=(i-(i%(nplot-1)))/(nplot-1);
1007 
1008  file_out << i%(nplot-1)+d*nplot+counter << " "
1009  << i%(nplot-1)+1+d*nplot+counter << " "
1010  << i%(nplot-1)+1+(d+1)*nplot+counter << " "
1011  << i%(nplot-1)+(d+1)*nplot+counter
1012  << std::endl;
1013  }
1014  counter+=nplot_points_paraview(nplot);
1015  }
1016 
1017  /// \short Return the paraview element type.
1018  /// Needs to be implemented for each new geometric element type; see
1019  /// http://www.vtk.org/VTK/img/file-formats.pdf
1020  /// Use type "VTK_QUAD" (== 9) for 2D quad elements
1021  void write_paraview_type(std::ofstream& file_out,
1022  const unsigned& nplot) const
1023  {
1024  unsigned local_loop=nsub_elements_paraview(nplot);
1025  for(unsigned i=0;i<local_loop;i++)
1026  {
1027  file_out << "9" << std::endl;
1028  }
1029  }
1030 
1031  /// \short Return the offsets for the paraview sub-elements. Needs
1032  /// to be implemented for each new geometric element type; see
1033  /// http://www.vtk.org/VTK/img/file-formats.pdf
1034  void write_paraview_offsets(std::ofstream& file_out,
1035  const unsigned& nplot,
1036  unsigned& offset_sum) const
1037  {
1038  // Loop over all local elements and add its offset to the overall offset_sum
1039  unsigned local_loop=nsub_elements_paraview(nplot);
1040  for(unsigned i=0;i<local_loop;i++)
1041  {
1042  offset_sum+=4;
1043  file_out << offset_sum << std::endl;
1044  }
1045  }
1046 
1047  /// Output
1048  void output(std::ostream &outfile);
1049 
1050  /// Output at n_plot points
1051  void output(std::ostream &outfile, const unsigned &n_plot);
1052 
1053  /// C-style output
1054  void output(FILE* file_pt);
1055 
1056  /// C_style output at n_plot points
1057  void output(FILE* file_pt, const unsigned &n_plot);
1058 
1059 
1060  /// \short Get cector of local coordinates of plot point i (when plotting
1061  /// nplot points in each "coordinate direction).
1063  const unsigned& i,
1064  const unsigned& nplot,
1065  Vector<double>& s,
1066  const bool& use_equally_spaced_interior_sample_points=false) const
1067  {
1068  if (nplot>1)
1069  {
1070  unsigned i0=i%nplot;
1071  unsigned i1=(i-i0)/nplot;
1072 
1073  s[0]=-1.0+2.0*double(i0)/double(nplot-1);
1074  s[1]=-1.0+2.0*double(i1)/double(nplot-1);
1075  if (use_equally_spaced_interior_sample_points)
1076  {
1077  double range=2.0;
1078  double dx_new=range/double(nplot);
1079  double range_new=double(nplot-1)*dx_new;
1080  s[0]=-1.0+0.5*dx_new+range_new*(1.0+s[0])/range;
1081  s[1]=-1.0+0.5*dx_new+range_new*(1.0+s[1])/range;
1082  }
1083  }
1084  else
1085  {
1086  s[0]=0.0;
1087  s[1]=0.0;
1088  }
1089  }
1090 
1091  /// \short Return string for tecplot zone header (when plotting
1092  /// nplot points in each "coordinate direction)
1093  std::string tecplot_zone_string(const unsigned& nplot) const
1094  {
1095  std::ostringstream header;
1096  header << "ZONE I=" << nplot << ", J=" << nplot << "\n";
1097  return header.str();
1098  }
1099 
1100  /// Return total number of plot points (when plotting
1101  /// nplot points in each "coordinate direction)
1102  unsigned nplot_points(const unsigned& nplot) const
1103  {
1104  unsigned DIM=2;
1105  unsigned np=1;
1106  for (unsigned i=0;i<DIM;i++) {np*=nplot;}
1107  return np;
1108  };
1109 
1110  /// Get the number of the ith node on face face_index (in the bulk node
1111  /// vector).
1112  unsigned get_bulk_node_number(const int& face_index,
1113  const unsigned& i) const
1114  {
1116 
1117  const unsigned nn1d = nnode_1d();
1118 
1119  if(face_index == -1) {return i*nn1d;}
1120  else if(face_index == +1) {return nn1d*i + nn1d-1;}
1121  else if(face_index == -2) {return i;}
1122  else if(face_index == +2) {return nn1d*(nn1d-1) + i;}
1123  else
1124  {
1125  std::string err = "Face index should be in {-1, +1, -2, +2}.";
1126  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
1127  OOMPH_CURRENT_FUNCTION);
1128  }
1129  }
1130 
1131  /// Get the sign of the outer unit normal on the face given by face_index.
1132  int face_outer_unit_normal_sign(const int& face_index) const
1133  {
1134  if(face_index < 0) {return 1;}
1135  else if(face_index > 0) {return -1;}
1136  else
1137  {
1138  std::string err = "Face index should be one of {-1, +1, -2, +2}.";
1139  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
1140  OOMPH_CURRENT_FUNCTION);
1141  }
1142  }
1143 
1144  /// Get a pointer to the function mapping face coordinates to bulk coordinates
1146  (const int& face_index) const
1147  {
1148  if(face_index == 1) {return &QElement2FaceToBulkCoordinates::face2;}
1149  else if (face_index == -1) {return &QElement2FaceToBulkCoordinates::face0;}
1150  else if (face_index == -2) {return &QElement2FaceToBulkCoordinates::face1;}
1151  else if (face_index == 2) {return &QElement2FaceToBulkCoordinates::face3;}
1152  else
1153  {
1154  std::string err = "Face index should be in {-1, +1}.";
1155  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
1156  OOMPH_CURRENT_FUNCTION);
1157  }
1158  }
1159 
1160  /// Get a pointer to the derivative of the mapping from face to bulk
1161  /// coordinates.
1163  (const int& face_index) const
1164  {
1165  if(face_index == 1) {return &QElement2BulkCoordinateDerivatives::faces0;}
1166  else if (face_index == -1) {return &QElement2BulkCoordinateDerivatives::faces0;}
1167  else if (face_index == -2) {return &QElement2BulkCoordinateDerivatives::faces1;}
1168  else if (face_index == 2) {return &QElement2BulkCoordinateDerivatives::faces1;}
1169  else
1170  {
1171  std::string err = "Face index should be in {-1, +1}.";
1172  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
1173  OOMPH_CURRENT_FUNCTION);
1174  }
1175  }
1176 
1177 
1178 
1179 };
1180 
1181 //=======================================================================
1182 /// Base class for all brick elements
1183 //=======================================================================
1184 class BrickElementBase : public virtual QElementBase
1185 {
1186  public:
1187 
1188  /// Constructor. Empty
1190 
1191  /// \short Number of vertex nodes in the element
1192  virtual unsigned nvertex_node() const=0;
1193 
1194  /// \short Pointer to the j-th vertex node in the element
1195  virtual Node* vertex_node_pt(const unsigned& j) const=0;
1196 
1197 };
1198 
1199 //=======================================================================
1200 ///General QElement class specialised to three spatial dimensions
1201 //=======================================================================
1202 template<unsigned NNODE_1D>
1203 class QElement<3,NNODE_1D> : public virtual BrickElementBase
1204 {
1205  private:
1206 
1207  /// \short Default integration rule: Gaussian integration of same 'order'
1208  /// as the element
1209  //N.B. This is sort of optimal, because it means that the integration is exact
1210  //for the shape functions. Can overwrite this in specific element defintion
1212 
1213 public:
1214 
1215  /// Constructor
1217  {
1218  //There are NNODE_1D^3 nodes in this element
1219  this->set_n_node(NNODE_1D*NNODE_1D*NNODE_1D);
1220  //Set the dimensions of the element and the nodes, by default, both 3D
1221  set_dimension(3);
1222  //Assign default (full_ spatial integration_scheme
1223  set_integration_scheme(&Default_integration_scheme);
1224  }
1225 
1226 
1227  /// Broken copy constructor
1229  {
1230  BrokenCopy::broken_copy("QElement");
1231  }
1232 
1233  /// Broken assignment operator
1234  /*void operator=(const QElement&)
1235  {
1236  BrokenCopy::broken_assign("QElement");
1237  }*/
1238 
1239  /// Calculate the geometric shape functions at local coordinate s
1240  void shape(const Vector<double> &s, Shape &psi) const;
1241 
1242  /// \short Compute the geometric shape functions and
1243  /// derivatives w.r.t. local coordinates at local coordinate s
1244  void dshape_local(const Vector<double> &s, Shape &psi, DShape &dpsids)
1245  const;
1246 
1247  /// \short Compute the geometric shape functions, derivatives and
1248  /// second derivatives w.r.t. local coordinates at local coordinate s.
1249  /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
1250  /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
1251  /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_2^2 \f$
1252  /// d2psids(i,3) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
1253  /// d2psids(i,4) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_2 \f$
1254  /// d2psids(i,5) = \f$ \partial^2 \psi_j / \partial s_1 \partial s_2 \f$
1255  void d2shape_local(const Vector<double> &s, Shape &psi, DShape &dpsids,
1256  DShape &d2psids) const;
1257 
1258 
1259  /// \short Overload the template-free interface for the calculation of
1260  /// the inverse jacobian mapping. This is a three-dimensional element,
1261  /// so use the 3d version
1263  DenseMatrix<double> &inverse_jacobian) const
1264  {return FiniteElement::invert_jacobian<3>(jacobian,inverse_jacobian);}
1265 
1266  /// Min. value of local coordinate
1267  double s_min() const {return -1.0;}
1268 
1269  /// Max. value of local coordinate
1270  double s_max() const {return 1.0;}
1271 
1272  /// \short Number of vertex nodes in the element
1273  unsigned nvertex_node() const
1274  {return 8;}
1275 
1276  /// \short Pointer to the j-th vertex node in the element
1277  Node* vertex_node_pt(const unsigned& j) const
1278  {
1279  unsigned N=nnode_1d();
1280  Node* nod_pt;
1281  switch(j)
1282  {
1283  case 0:
1284  nod_pt=node_pt(0);
1285  break;
1286  case 1:
1287  nod_pt=node_pt(N-1);
1288  break;
1289  case 2:
1290  nod_pt=node_pt(N*(N-1));
1291  break;
1292  case 3:
1293  nod_pt=node_pt(N*N-1);
1294  break;
1295  case 4:
1296  nod_pt=node_pt(N*N*(N-1));
1297  break;
1298  case 5:
1299  nod_pt=node_pt(N*N*(N-1)+(N-1));
1300  break;
1301  case 6:
1302  nod_pt=node_pt(N*N*N-N);
1303  break;
1304  case 7:
1305  nod_pt=node_pt(N*N*N-1);
1306  break;
1307  default:
1308  std::ostringstream error_message;
1309  error_message << "Vertex node number is " << j <<
1310  " but must be from 0 to 7\n";
1311 
1312  throw OomphLibError(error_message.str(),
1313  OOMPH_CURRENT_FUNCTION,
1314  OOMPH_EXCEPTION_LOCATION);
1315  }
1316  return nod_pt;
1317  }
1318 
1319  /// Get local coordinates of node j in the element; vector sets its own size
1320  void local_coordinate_of_node(const unsigned& j, Vector<double>& s) const
1321  {
1322  s.resize(3);
1323  unsigned j0=j%NNODE_1D;
1324  unsigned j1=(j/NNODE_1D)%NNODE_1D;
1325  unsigned j2=j/(NNODE_1D*NNODE_1D);
1326  const double S_min = this->s_min();
1327  const double S_range = this->s_max() - S_min;
1328 
1329  s[0]=S_min+double(j0)/double(NNODE_1D-1)*S_range;
1330  s[1]=S_min+double(j1)/double(NNODE_1D-1)*S_range;
1331  s[2]=S_min+double(j2)/double(NNODE_1D-1)*S_range;
1332  }
1333 
1334  /// Get the local fraction of node j in the element
1335  void local_fraction_of_node(const unsigned &j,
1336  Vector<double> &s_fraction)
1337  {
1338  s_fraction.resize(3);
1339  unsigned j0 = j%NNODE_1D;
1340  unsigned j1=(j/NNODE_1D)%NNODE_1D;
1341  unsigned j2=j/(NNODE_1D*NNODE_1D);
1342  s_fraction[0]= double(j0)/double(NNODE_1D-1);
1343  s_fraction[1]= double(j1)/double(NNODE_1D-1);
1344  s_fraction[2]= double(j2)/double(NNODE_1D-1);
1345  }
1346 
1347  /// This function returns the local fraction of any nodes in the n-th positoin
1348  /// in a one dimensional expansion along the i-th local coordinate
1349  inline double local_one_d_fraction_of_node(const unsigned &n1d,
1350  const unsigned &i)
1351  {
1352  //It's just the value of the node divided by the number of 1-D nodes
1353  return double(n1d)/double(NNODE_1D-1);
1354  }
1355 
1356  /// Get the node at the specified local coordinate
1358 
1359  /// Number of nodes along each element edge
1360  unsigned nnode_1d() const {return NNODE_1D;}
1361 
1362  /// \short Return the number of actual plot points for paraview
1363  /// plot with parameter nplot.
1364  unsigned nplot_points_paraview(const unsigned& nplot) const
1365  {
1366  return nplot*nplot*nplot;
1367  }
1368 
1369  /// \short Return the number of local sub-elements for paraview plot with
1370  /// parameter nplot.
1371  unsigned nsub_elements_paraview(const unsigned& nplot) const
1372  {
1373  return (nplot-1)*(nplot-1)*(nplot-1);
1374  }
1375 
1376  /// \short Fill in the offset information for paraview plot.
1377  /// Needs to be implemented for each new geometric element type; see
1378  /// http://www.vtk.org/VTK/img/file-formats.pdf
1379  void write_paraview_output_offset_information(std::ofstream& file_out,
1380  const unsigned& nplot,
1381  unsigned& counter) const
1382  {
1383  // Number of local elements we want to plot over
1384  unsigned plot=nsub_elements_paraview(nplot);
1385 
1386  for(unsigned j=0;j<plot;j+=(nplot-1)*(nplot-1)+1)
1387  {
1388  // To keep track of how many cross-sections we've looped over
1389  unsigned r=((j-(j%((nplot-1)*(nplot-1))))/((nplot-1)*(nplot-1)));
1390 
1391  // loop over all the elemnets in this sublevel
1392  unsigned sub_plot=(nplot-1)*(nplot-1);
1393 
1394  // loops over the i-th local element in parent element
1395  for(unsigned i=0;i<sub_plot;i++)
1396  {
1397  unsigned d=((i-(i%(nplot-1)))/(nplot-1));
1398 
1399 
1400  // Lower level of rectangle
1401  file_out << i%(nplot-1)+d*nplot+r*nplot*nplot+counter << " "
1402  << i%(nplot-1)+1+d*nplot+r*nplot*nplot+counter << " "
1403  << i%(nplot-1)+1+(d+1)*nplot+r*nplot*nplot+counter << " "
1404  << i%(nplot-1)+(d+1)*nplot+r*nplot*nplot+counter << " "
1405 
1406  // Upper level of rectangle
1407  << i%(nplot-1)+d*nplot+(r+1)*nplot*nplot+counter << " "
1408  << i%(nplot-1)+1+d*nplot+(r+1)*nplot*nplot+counter << " "
1409  << i%(nplot-1)+1+(d+1)*nplot+(r+1)*nplot*nplot+counter << " "
1410  << i%(nplot-1)+(d+1)*nplot+(r+1)*nplot*nplot+counter
1411  << std::endl;
1412  }
1413  }
1414  counter+=nplot_points_paraview(nplot);
1415  }
1416 
1417  /// \short Return the paraview element type.
1418  /// Needs to be implemented for each new geometric element type; see
1419  /// http://www.vtk.org/VTK/img/file-formats.pdf
1420  /// Use type "VTK_HEXAHEDRON" (== 12) for 2D quad elements
1421  void write_paraview_type(std::ofstream& file_out,
1422  const unsigned& nplot) const
1423  {
1424  unsigned local_loop=nsub_elements_paraview(nplot);
1425  for(unsigned i=0;i<local_loop;i++)
1426  {
1427  file_out << "12" << std::endl;
1428  }
1429  }
1430 
1431  /// \short Return the offsets for the paraview sub-elements. Needs
1432  /// to be implemented for each new geometric element type; see
1433  /// http://www.vtk.org/VTK/img/file-formats.pdf
1434  void write_paraview_offsets(std::ofstream& file_out,
1435  const unsigned& nplot,
1436  unsigned& offset_sum) const
1437  {
1438  unsigned local_loop=nsub_elements_paraview(nplot);
1439  for(unsigned i=0;i<local_loop;i++)
1440  {
1441  offset_sum+=8;
1442  file_out << offset_sum << std::endl;
1443  }
1444  }
1445 
1446  /// Output
1447  void output(std::ostream &outfile);
1448 
1449  /// Output at n_plot points
1450  void output(std::ostream &outfile, const unsigned &n_plot);
1451 
1452  /// C-style output
1453  void output(FILE* file_pt);
1454 
1455  /// C_style output at n_plot points
1456  void output(FILE* file_pt, const unsigned &n_plot);
1457 
1458  /// \short Get cector of local coordinates of plot point i (when plotting
1459  /// nplot points in each "coordinate direction).
1461  const unsigned& i,
1462  const unsigned& nplot,
1463  Vector<double>& s,
1464  const bool& use_equally_spaced_interior_sample_points=false) const
1465  {
1466  if (nplot>1)
1467  {
1468  unsigned i01=i%(nplot*nplot);
1469  unsigned i0=i01%nplot;
1470  unsigned i1=(i01-i0)/nplot;
1471  unsigned i2=(i-i01)/(nplot*nplot);
1472 
1473  s[0]=-1.0+2.0*double(i0)/double(nplot-1);
1474  s[1]=-1.0+2.0*double(i1)/double(nplot-1);
1475  s[2]=-1.0+2.0*double(i2)/double(nplot-1);
1476  if (use_equally_spaced_interior_sample_points)
1477  {
1478  double range=2.0;
1479  double dx_new=range/double(nplot);
1480  double range_new=double(nplot-1)*dx_new;
1481  s[0]=-1.0+0.5*dx_new+range_new*(1.0+s[0])/range;
1482  s[1]=-1.0+0.5*dx_new+range_new*(1.0+s[1])/range;
1483  s[2]=-1.0+0.5*dx_new+range_new*(1.0+s[2])/range;
1484  }
1485  }
1486  else
1487  {
1488  s[0]=0.0;
1489  s[1]=0.0;
1490  s[2]=0.0;
1491  }
1492  }
1493 
1494  /// \short Return string for tecplot zone header (when plotting
1495  /// nplot points in each "coordinate direction)
1496  std::string tecplot_zone_string(const unsigned& nplot) const
1497  {
1498  std::ostringstream header;
1499  header << "ZONE I=" << nplot << ", J=" << nplot << ", K="
1500  << nplot << "\n";
1501  return header.str();
1502  }
1503 
1504  /// Return total number of plot points (when plotting
1505  /// nplot points in each "coordinate direction)
1506  unsigned nplot_points(const unsigned& nplot) const
1507  {
1508  unsigned DIM=3;
1509  unsigned np=1;
1510  for (unsigned i=0;i<DIM;i++) {np*=nplot;}
1511  return np;
1512  };
1513 
1514  /// Get the number of the ith node on face face_index in the bulk node
1515  /// vector.
1516  unsigned get_bulk_node_number(const int& face_index,
1517  const unsigned& i) const
1518  {
1520 
1521  const unsigned nn1d = nnode_1d();
1522 
1523  if(face_index == -1) {return i*nn1d;}
1524  else if(face_index == +1) {return i*nn1d + (nn1d-1);}
1525  else if(face_index == -2) {return i%nn1d + (i/nn1d)*nn1d*nn1d;}
1526  else if(face_index == +2) {return i%nn1d + (i/nn1d)*nn1d*nn1d + (nn1d*(nn1d-1));}
1527  else if(face_index == -3) {return i;}
1528  else if(face_index == +3) {return i+(nn1d*nn1d)*(nn1d-1);}
1529  else
1530  {
1531  std::string err = "Face index should be in {-1, +1, -2, +2, -3, +3}.";
1532  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
1533  OOMPH_CURRENT_FUNCTION);
1534  }
1535  }
1536 
1537  /// Get the sign of the outer unit normal on the face given by face_index.
1538  int face_outer_unit_normal_sign(const int& face_index) const
1539  {
1540  if(face_index == -3) {return -1;}
1541  else if(face_index == +3) {return 1;}
1542  else if(face_index == -2) {return 1;}
1543  else if(face_index == 2) {return -1;}
1544  else if(face_index == -1) {return -1;}
1545  else if(face_index == 1) {return 1;}
1546  else
1547  {
1548  std::string err = "Face index should be in {-1, +1, -2, +2, -3, +3}.";
1549  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
1550  OOMPH_CURRENT_FUNCTION);
1551  }
1552  }
1553 
1554  /// Get a pointer to the function mapping face coordinates to bulk coordinates
1556  (const int& face_index) const
1557  {
1558  if(face_index == 1) {return &QElement3FaceToBulkCoordinates::face3;}
1559  else if (face_index == -1) {return &QElement3FaceToBulkCoordinates::face0;}
1560  else if (face_index == -2) {return &QElement3FaceToBulkCoordinates::face1;}
1561  else if (face_index == 2) {return &QElement3FaceToBulkCoordinates::face4;}
1562  else if (face_index == -3) {return &QElement3FaceToBulkCoordinates::face2;}
1563  else if (face_index == 3) {return &QElement3FaceToBulkCoordinates::face5;}
1564  else
1565  {
1566  std::string err = "Face index should be in {-1, +1}.";
1567  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
1568  OOMPH_CURRENT_FUNCTION);
1569  }
1570  }
1571 
1572  /// Get a pointer to the derivative of the mapping from face to bulk
1573  /// coordinates.
1575  (const int& face_index) const
1576  {
1577  if(face_index == 1) {return &QElement3BulkCoordinateDerivatives::faces0;}
1578  else if (face_index == -1) {return &QElement3BulkCoordinateDerivatives::faces0;}
1579  else if (face_index == -2) {return &QElement3BulkCoordinateDerivatives::faces1;}
1580  else if (face_index == 2) {return &QElement3BulkCoordinateDerivatives::faces1;}
1581  else if (face_index == -3) {return &QElement3BulkCoordinateDerivatives::faces2;}
1582  else if (face_index == 3) {return &QElement3BulkCoordinateDerivatives::faces2;}
1583  else
1584  {
1585  std::string err = "Face index should be in {-1, +1}.";
1586  throw OomphLibError(err, OOMPH_EXCEPTION_LOCATION,
1587  OOMPH_CURRENT_FUNCTION);
1588  }
1589  }
1590 
1591 };
1592 
1593 //=======================================================================
1594 /// SolidQElement elements are quadrilateral elements whose
1595 /// derivatives also include those based upon the lagrangian
1596 /// positions of the nodes.
1597 /// They are the basis for solid mechanics elements
1598 //=======================================================================
1599 template <unsigned DIM, unsigned NNODE_1D>
1601 {};
1602 
1603 
1604 //=======================================================================
1605 ///SolidQElement elements, specialised to one spatial dimension
1606 //=======================================================================
1607 template <unsigned NNODE_1D>
1608 class SolidQElement<1,NNODE_1D> : public virtual QElement<1,NNODE_1D>,
1609  public virtual QSolidElementBase
1610 {
1611  public:
1612 
1613  /// Constructor
1615  {
1616  //Set the Lagrangian dimension of the element
1617  set_lagrangian_dimension(1);
1618  }
1619 
1620  /// Broken copy constructor
1622  {
1623  BrokenCopy::broken_copy("SolidQElement");
1624  }
1625 
1626  /// Broken assignment operator
1627  /*void operator=(const SolidQElement&)
1628  {
1629  BrokenCopy::broken_assign("SolidQElement");
1630  }*/
1631 
1632 ///Overload the output function
1633  void output(std::ostream &outfile) {FiniteElement::output(outfile);}
1634 
1635  /// Output at n_plot points
1636  inline void output(std::ostream &outfile, const unsigned &n_plot);
1637 
1638  /// C-style output
1639  void output(FILE* file_pt) {FiniteElement::output(file_pt);}
1640 
1641  /// C_style output at n_plot points
1642  inline void output(FILE* file_pt, const unsigned &n_plot);
1643 
1644  /// \short Build the lower-dimensional FaceElement (an element of type
1645  /// SolidQElement<0,NNODE_1D>).
1646  /// The face index takes one of two values corresponding
1647  /// to the two possible faces:
1648  /// -1 (Left) s[0] = -1.0
1649  /// +1 (Right) s[0] = 1.0
1650  inline void build_face_element(const int &face_index,
1651  FaceElement* face_element_pt);
1652 
1653 
1654 };
1655 
1656 //For the dumb Intel 9.0 compiler, these need to live in here
1657 
1658 ///////////////////////////////////////////////////////////////////////////
1659 ///////////////////////////////////////////////////////////////////////////
1660 // SolidQElements
1661 ///////////////////////////////////////////////////////////////////////////
1662 ///////////////////////////////////////////////////////////////////////////
1663 
1664 ///////////////////////////////////////////////////////////////////////////
1665 // 1D SolidQElements
1666 ///////////////////////////////////////////////////////////////////////////
1667 
1668 
1669 //=======================================================================
1670 /// The output function for n_plot points in each coordinate direction
1671 /// for the 1D element
1672 //=======================================================================
1673 template <unsigned NNODE_1D>
1674 void SolidQElement<1,NNODE_1D>::output(std::ostream &outfile,
1675  const unsigned &n_plot)
1676 {
1677  //Local variables
1678  Vector<double> s(1);
1679 
1680  //Tecplot header info
1681  outfile << "ZONE I=" << n_plot << std::endl;
1682 
1683  //Find the dimension of the nodes
1684  unsigned n_dim = this->nodal_dimension();
1685 
1686  //Find the Lagrangian dimension of the first node
1687  unsigned n_lagr = static_cast<SolidNode*>(node_pt(0))->nlagrangian();
1688 
1689  //Loop over element nodes
1690  for(unsigned l=0;l<n_plot;l++)
1691  {
1692  s[0] = -1.0 + l*2.0/(n_plot-1);
1693 
1694  //Output the Eulerian coordinates
1695  for(unsigned i=0;i<n_dim;i++)
1696  {
1697  outfile << QElement<1,NNODE_1D>::interpolated_x(s,i) << " " ;
1698  }
1699  //Output the Lagranian coordinates
1700  for(unsigned i=0;i<n_lagr;i++)
1701  {
1702  outfile << SolidQElement<1,NNODE_1D>::interpolated_xi(s,i) << " " ;
1703  }
1704  outfile << std::endl;
1705  }
1706  outfile << std::endl;
1707 }
1708 
1709 //=======================================================================
1710 /// C-style output function for n_plot points in each coordinate direction
1711 /// for the 1D element
1712 //=======================================================================
1713 template <unsigned NNODE_1D>
1715  const unsigned &n_plot)
1716 {
1717  //Local variables
1718  Vector<double> s(1);
1719 
1720  //Tecplot header info
1721  fprintf(file_pt,"ZONE I=%i\n",n_plot);
1722 
1723  //Find the dimension of the nodes
1724  unsigned n_dim = this->nodal_dimension();
1725 
1726  //Find the Lagrangian dimension of the first node
1727  unsigned n_lagr = static_cast<SolidNode*>(node_pt(0))->nlagrangian();
1728 
1729  //Loop over element nodes
1730  for(unsigned l=0;l<n_plot;l++)
1731  {
1732  s[0] = -1.0 + l*2.0/(n_plot-1);
1733 
1734  //Output the Eulerian coordinates
1735  for(unsigned i=0;i<n_dim;i++)
1736  {
1737  fprintf(file_pt,"%g ",QElement<1,NNODE_1D>::interpolated_x(s,i));
1738  }
1739  //Output the Lagranian coordinates
1740  for(unsigned i=0;i<n_lagr;i++)
1741  {
1742  fprintf(file_pt,"%g ",SolidQElement<1,NNODE_1D>::interpolated_xi(s,i));
1743  }
1744  fprintf(file_pt,"\n");
1745  }
1746  fprintf(file_pt,"\n");
1747 
1748 }
1749 
1750 
1751 //===========================================================
1752 /// Function to setup geometrical information for lower-dimensional
1753 /// FaceElements (which are of type SolidQElement<0,1>).
1754 //===========================================================
1755 template<unsigned NNODE_1D>
1757 build_face_element(const int &face_index,
1758  FaceElement *face_element_pt)
1759 {
1760  //Build the standard non-solid FaceElement
1761  QElement<1,NNODE_1D>::build_face_element(face_index,face_element_pt);
1762 
1763  //Set the Lagrangian dimension from the first node of the present element
1764  dynamic_cast<SolidFiniteElement*>(face_element_pt)->
1765  set_lagrangian_dimension(static_cast<SolidNode*>(node_pt(0))->nlagrangian());
1766 }
1767 
1768 
1769 
1770 //=======================================================================
1771 /// SolidQElement elements, specialised to two spatial dimensions
1772 //=======================================================================
1773 template <unsigned NNODE_1D>
1774 class SolidQElement<2,NNODE_1D> : public virtual QElement<2,NNODE_1D>,
1775  public virtual QSolidElementBase
1776 {
1777  public:
1778 
1779  /// Constructor
1780  SolidQElement() : QElementBase(), QElement<2,NNODE_1D>(),
1782  {
1783  //Set the Lagrangian dimension of the element
1784  set_lagrangian_dimension(2);
1785  }
1786 
1787  /// Broken copy constructor
1789  {
1790  BrokenCopy::broken_copy("SolidQElement");
1791  }
1792 
1793  /// Broken assignment operator
1794  /*void operator=(const SolidQElement&)
1795  {
1796  BrokenCopy::broken_assign("SolidQElement");
1797  }*/
1798 
1799  /// Overload the output function
1800  void output(std::ostream &outfile) {FiniteElement::output(outfile);}
1801 
1802  /// Output at n_plot^2 points
1803  inline void output(std::ostream &outfile, const unsigned &n_plot);
1804 
1805  /// C-style output
1806  void output(FILE* file_pt){FiniteElement::output(file_pt);}
1807 
1808  /// C_style output at n_plot points
1809  inline void output(FILE* file_pt, const unsigned &n_plot);
1810 
1811 
1812  /// \short Build the lower-dimensional FaceElement (an element of type
1813  /// SolidQElement<1,NNODE_1D>).The face index takes one of four values
1814  /// corresponding to the four possible faces:
1815  /// -1 (West) s[0] = -1.0
1816  /// +1 (East) s[0] = 1.0
1817  /// -2 (South) s[1] = -1.0
1818  /// +2 (North) s[1] = 1.0
1819  inline void build_face_element(const int &face_index,
1820  FaceElement* face_element_pt);
1821 
1822 };
1823 
1824 
1825 
1826 
1827 
1828 ///////////////////////////////////////////////////////////////////////////
1829 // 2D SolidQElements
1830 ///////////////////////////////////////////////////////////////////////////
1831 
1832 //===========================================================
1833 /// The output function for any number of points per element
1834 //===========================================================
1835 template <unsigned NNODE_1D>
1836 void SolidQElement<2,NNODE_1D>::output(std::ostream &outfile,
1837  const unsigned &n_plot)
1838 {
1839  //Local variables
1840  Vector<double> s(2);
1841 
1842  //Tecplot header info
1843  outfile << "ZONE I=" << n_plot << ", J=" << n_plot << std::endl;
1844 
1845  //Find the dimension of the nodes
1846  unsigned n_dim = this->nodal_dimension();
1847 
1848  //Find the Lagrangian dimension of the first node
1849  unsigned n_lagr = static_cast<SolidNode*>(node_pt(0))->nlagrangian();
1850 
1851  //Loop over plot points
1852  for(unsigned l2=0;l2<n_plot;l2++)
1853  {
1854  s[1] = -1.0 + l2*2.0/(n_plot-1);
1855  for(unsigned l1=0;l1<n_plot;l1++)
1856  {
1857  s[0] = -1.0 + l1*2.0/(n_plot-1);
1858 
1859  //Output the Eulerian coordinates
1860  for(unsigned i=0;i<n_dim;i++)
1861  {
1862  outfile << QElement<2,NNODE_1D>::interpolated_x(s,i) << " " ;
1863  }
1864  //Output the Lagranian coordinates
1865  for(unsigned i=0;i<n_lagr;i++)
1866  {
1867  outfile << SolidQElement<2,NNODE_1D>::interpolated_xi(s,i) << " " ;
1868  }
1869  outfile << std::endl;
1870  }
1871  }
1872  outfile << std::endl;
1873 }
1874 
1875 
1876 
1877 
1878 //====================================================================
1879 /// C-style output function for any number of points per element
1880 //====================================================================
1881 template <unsigned NNODE_1D>
1883  const unsigned &n_plot)
1884 {
1885  //Local variables
1886  Vector<double> s(2);
1887 
1888  //Tecplot header info
1889  fprintf(file_pt,"ZONE I=%i, J=%i\n",n_plot,n_plot);
1890 
1891  //Find the dimension of the nodes
1892  unsigned n_dim = this->nodal_dimension();
1893 
1894  //Find the Lagrangian dimension of the first node
1895  unsigned n_lagr = static_cast<SolidNode*>(node_pt(0))->nlagrangian();
1896 
1897  //Loop over plot points
1898  for(unsigned l2=0;l2<n_plot;l2++)
1899  {
1900  s[1] = -1.0 + l2*2.0/(n_plot-1);
1901  for(unsigned l1=0;l1<n_plot;l1++)
1902  {
1903  s[0] = -1.0 + l1*2.0/(n_plot-1);
1904 
1905  //Output the Eulerian coordinates
1906  for(unsigned i=0;i<n_dim;i++)
1907  {
1908  fprintf(file_pt,"%g ",QElement<2,NNODE_1D>::interpolated_x(s,i));
1909  }
1910  //Output the Lagranian coordinates
1911  for(unsigned i=0;i<n_lagr;i++)
1912  {
1913  fprintf(file_pt,"%g ",SolidQElement<2,NNODE_1D>::interpolated_xi(s,i));
1914  }
1915  fprintf(file_pt,"\n");
1916  }
1917  }
1918  fprintf(file_pt,"\n");
1919 }
1920 
1921 
1922 //===========================================================
1923 /// Function to setup geometrical information for lower-dimensional
1924 /// FaceElements (which are of type SolidQElement<1,NNODE_1D>).
1925 //===========================================================
1926 template<unsigned NNODE_1D>
1928 build_face_element(const int &face_index, FaceElement *face_element_pt)
1929 {
1930  //Build the standard non-solid FaceElement
1931  QElement<2,NNODE_1D>::build_face_element(face_index,face_element_pt);
1932 
1933  //Set the Lagrangian dimension from the first node of the present element
1934  dynamic_cast<SolidFiniteElement*>(face_element_pt)->
1935  set_lagrangian_dimension(static_cast<SolidNode*>(node_pt(0))->nlagrangian());
1936 }
1937 
1938 
1939 
1940 //=======================================================================
1941 /// SolidQElement elements, specialised to three spatial dimensions
1942 //=======================================================================
1943 template <unsigned NNODE_1D>
1944 class SolidQElement<3,NNODE_1D> : public virtual QElement<3,NNODE_1D>,
1945  public virtual QSolidElementBase
1946 {
1947 
1948  public:
1949 
1950  /// Constructor
1951  SolidQElement() : QElementBase(), QElement<3,NNODE_1D>(),
1953  {
1954  //Set the Lagrangian dimension of the element
1955  set_lagrangian_dimension(3);
1956  }
1957 
1958  /// Broken copy constructor
1960  {
1961  BrokenCopy::broken_copy("SolidQElement");
1962  }
1963 
1964  /// Broken assignment operator
1965  /*void operator=(const SolidQElement&)
1966  {
1967  BrokenCopy::broken_assign("SolidQElement");
1968  }*/
1969 
1970  /// Overload the output function
1971  void output(std::ostream &outfile) {FiniteElement::output(outfile);}
1972 
1973  /// Output at n_plot^2 points
1974  inline void output(std::ostream &outfile, const unsigned &n_plot);
1975 
1976  /// C-style output
1977  void output(FILE* file_pt){FiniteElement::output(file_pt);}
1978 
1979  /// C_style output at n_plot points
1980  inline void output(FILE* file_pt, const unsigned &n_plot);
1981 
1982 
1983  /// \short Build the lower-dimensional FaceElement (an element of type
1984  /// SolidQElement<2,NNODE_1D>). The face index takes of one
1985  /// six values corresponding
1986  /// to the six possible faces:
1987  /// -1 (Left) s[0] = -1.0
1988  /// +1 (Right) s[0] = 1.0
1989  /// -2 (Down) s[1] = -1.0
1990  /// +2 (Up) s[1] = 1.0
1991  /// -3 (Back) s[2] = -1.0
1992  /// +3 (Front) s[2] = 1.0
1993  inline void build_face_element(const int &face_index,
1994  FaceElement* face_element_pt);
1995 
1996 };
1997 
1998 
1999 
2000 
2001 
2002 ///////////////////////////////////////////////////////////////////////////
2003 // 3D SolidQElements
2004 ///////////////////////////////////////////////////////////////////////////
2005 
2006 //===========================================================
2007 /// The output function for any number of points per element
2008 //===========================================================
2009 template <unsigned NNODE_1D>
2010 void SolidQElement<3,NNODE_1D>::output(std::ostream &outfile,
2011  const unsigned &n_plot)
2012 {
2013  //Local variables
2014  Vector<double> s(3);
2015 
2016  //Tecplot header info
2017  outfile << "ZONE I=" << n_plot << ", J=" << n_plot
2018  << ", K=" << n_plot << std::endl;
2019 
2020  //Find the dimension of the nodes
2021  unsigned n_dim = this->nodal_dimension();
2022 
2023  //Find the Lagrangian dimension of the first node
2024  unsigned n_lagr = static_cast<SolidNode*>(node_pt(0))->nlagrangian();
2025 
2026  //Loop over plot points
2027  for(unsigned l3=0;l3<n_plot;l3++)
2028  {
2029  s[2] = -1.0 + l3*2.0/(n_plot-1);
2030  for(unsigned l2=0;l2<n_plot;l2++)
2031  {
2032  s[1] = -1.0 + l2*2.0/(n_plot-1);
2033  for(unsigned l1=0;l1<n_plot;l1++)
2034  {
2035  s[0] = -1.0 + l1*2.0/(n_plot-1);
2036 
2037  //Output the Eulerian coordinates
2038  for(unsigned i=0;i<n_dim;i++)
2039  {
2040  outfile << QElement<3,NNODE_1D>::interpolated_x(s,i) << " " ;
2041  }
2042  //Output the Lagranian coordinates
2043  for(unsigned i=0;i<n_lagr;i++)
2044  {
2045  outfile << SolidQElement<3,NNODE_1D>::interpolated_xi(s,i) << " " ;
2046  }
2047  outfile << std::endl;
2048  }
2049  }
2050  }
2051  outfile << std::endl;
2052 }
2053 
2054 
2055 //====================================================================
2056 /// C-style output function for any number of points per element
2057 //====================================================================
2058 template <unsigned NNODE_1D>
2060  const unsigned &n_plot)
2061 {
2062  //Local variables
2063  Vector<double> s(3);
2064 
2065  //Tecplot header info
2066  fprintf(file_pt,"ZONE I=%i, J=%i, K=%i\n",n_plot,n_plot,n_plot);
2067 
2068  //Find the dimension of the nodes
2069  unsigned n_dim = this->nodal_dimension();
2070 
2071  //Find the Lagrangian dimension of the first node
2072  unsigned n_lagr = static_cast<SolidNode*>(node_pt(0))->nlagrangian();
2073 
2074  //Loop over plot points
2075  for(unsigned l3=0;l3<n_plot;l3++)
2076  {
2077  s[2] = -1.0 + l3*2.0/(n_plot-1);
2078  for(unsigned l2=0;l2<n_plot;l2++)
2079  {
2080  s[1] = -1.0 + l2*2.0/(n_plot-1);
2081  for(unsigned l1=0;l1<n_plot;l1++)
2082  {
2083  s[0] = -1.0 + l1*2.0/(n_plot-1);
2084 
2085  //Output the Eulerian coordinates
2086  for(unsigned i=0;i<n_dim;i++)
2087  {
2088  fprintf(file_pt,"%g ",QElement<3,NNODE_1D>::interpolated_x(s,i));
2089  }
2090  //Output the Lagranian coordinates
2091  for(unsigned i=0;i<n_lagr;i++)
2092  {
2093  fprintf(file_pt,"%g ",
2095  }
2096  fprintf(file_pt,"\n");
2097  }
2098  }
2099  }
2100  fprintf(file_pt,"\n");
2101 }
2102 
2103 
2104 //===========================================================
2105 /// Function to setup geometrical information for lower-dimensional
2106 /// FaceElements (which are of type SolidQElement<1,NNODE_1D>).
2107 //===========================================================
2108 template<unsigned NNODE_1D>
2110  build_face_element(const int &face_index,
2111  FaceElement *face_element_pt)
2112 {
2113  //Build the standard non-solid FaceElement
2114  QElement<3,NNODE_1D>::build_face_element(face_index,face_element_pt);
2115 
2116  //Set the Lagrangian dimension from the first node of the present element
2117  dynamic_cast<SolidFiniteElement*>(face_element_pt)->
2118  set_lagrangian_dimension(static_cast<SolidNode*>(node_pt(0))->nlagrangian());
2119 }
2120 
2121 
2122 //==============================================================
2123 /// A class that is used to template the refineable Q elements
2124 /// by dimension. It's really nothing more than a policy class
2125 //=============================================================
2126 template<unsigned DIM>
2128 {
2129  public:
2130 
2131  /// Empty constuctor
2133 };
2134 
2135 //==============================================================
2136 /// A class that is used to template the p-refineable Q elements
2137 /// by dimension. It's really nothing more than a policy class.
2138 /// The default template parameter ensures that these elements
2139 /// inherit from the QElement of the correct type if they start
2140 /// with a p-order higher than linear (e.g. Navier-Stokes Elements).
2141 //=============================================================
2142 template<unsigned DIM, unsigned INITIAL_NNODE_1D=2>
2144 {
2145  public:
2146 
2147  /// Empty constuctor
2149 };
2150 
2151 //==============================================================
2152 /// A class that is used to template the solid refineable Q elements
2153 /// by dimension. It's really nothing more than a policy class
2154 //=============================================================
2155 template<unsigned DIM>
2157 {
2158  public:
2159 
2160  /// Empty constuctor
2162 };
2163 
2164 
2165 }
2166 
2167 #endif
2168 
2169 
2170 
2171 
2172 
2173 
void face1(const Vector< double > &s, Vector< double > &s_bulk)
The translation scheme for the south face (s1 = -1.0)
Node * vertex_node_pt(const unsigned &j) const
Pointer to the j-th vertex node in the element.
Definition: Qelements.h:910
void get_s_plot(const unsigned &i, const unsigned &nplot, Vector< double > &s, const bool &use_equally_spaced_interior_sample_points=false) const
Get cector of local coordinates of plot point i (when plotting nplot points in each "coordinate direc...
Definition: Qelements.h:714
double local_one_d_fraction_of_node(const unsigned &n1d, const unsigned &i)
Definition: Qelements.h:1349
Base class for all line elements.
Definition: Qelements.h:492
void broken_copy(const std::string &class_name)
Issue error message and terminate execution.
SolidQElement(const SolidQElement &)
Broken copy constructor.
Definition: Qelements.h:1788
void write_paraview_output_offset_information(std::ofstream &file_out, const unsigned &nplot, unsigned &counter) const
Fill in the offset information for paraview plot. Needs to be implemented for each new geometric elem...
Definition: Qelements.h:996
unsigned get_bulk_node_number(const int &face_index, const unsigned &i) const
Definition: Qelements.h:1516
unsigned nvertex_node() const
Number of vertex nodes in the element.
Definition: Qelements.h:574
unsigned nplot_points_paraview(const unsigned &nplot) const
Return the number of actual plot points for paraview plot with parameter nplot.
Definition: Qelements.h:1364
void write_paraview_offsets(std::ofstream &file_out, const unsigned &nplot, unsigned &offset_sum) const
Return the offsets for the paraview sub-elements. Needs to be implemented for each new geometric elem...
Definition: Qelements.h:1434
virtual void d2shape_local(const Vector< double > &s, Shape &psi, DShape &dpsids, DShape &d2psids) const
Function to compute the geometric shape functions and also first and second derivatives w...
Definition: elements.h:1955
unsigned nplot_points_paraview(const unsigned &nplot) const
Return the number of actual plot points for paraview plot with parameter nplot.
Definition: Qelements.h:637
void write_paraview_type(std::ofstream &file_out, const unsigned &nplot) const
Return the paraview element type. Needs to be implemented for each new geometric element type; see ht...
Definition: Qelements.h:1021
virtual void output(std::ostream &outfile)
Output the element data — typically the values at the nodes in a format suitable for post-processing...
Definition: elements.h:2884
int face_outer_unit_normal_sign(const int &face_index) const
Get the sign of the outer unit normal on the face given by face_index.
Definition: Qelements.h:1132
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Get local coordinates of node j in the element; vector sets its own size.
Definition: Qelements.h:942
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:3806
void write_paraview_offsets(std::ofstream &file_out, const unsigned &nplot, unsigned &offset_sum) const
Return the offsets for the paraview sub-elements. Needs to be implemented for each new geometric elem...
Definition: Qelements.h:1034
QElementBase()
Constructor: Initialise pointers to macro element reference coords.
Definition: Qelements.h:111
QSolidElementBase()
Constructor: Empty.
Definition: Qelements.h:365
void face0(const Vector< double > &s, Vector< double > &s_bulk)
The translation scheme for the face s0 = -1.0.
void face1(const Vector< double > &s, Vector< double > &s_bulk)
The translation scheme for the face s0 = 1.0.
ElementGeometry::ElementGeometry element_geometry() const
It&#39;s a Q element!
Definition: Qelements.h:334
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Get local coordinates of node j in the element; vector sets its own size.
Definition: Qelements.h:603
virtual unsigned nplot_points_paraview(const unsigned &nplot) const
Return the number of actual plot points for paraview plot with parameter nplot. Broken virtual; can b...
Definition: elements.h:2712
void output(FILE *file_pt)
C-style output.
Definition: Qelements.h:1639
std::string tecplot_zone_string(const unsigned &nplot) const
Return string for tecplot zone header (when plotting nplot points in each "coordinate direction) ...
Definition: Qelements.h:1093
void(* CoordinateMappingFctPt)(const Vector< double > &s, Vector< double > &s_bulk)
Typedef for the function that translates the face coordinate to the coordinate in the bulk element...
Definition: elements.h:1245
cstr elem_len * i
Definition: cfortran.h:607
void local_fraction_of_node(const unsigned &j, Vector< double > &s_fraction)
Get the local fraction of node j in the element.
Definition: Qelements.h:954
void face2(const Vector< double > &s, Vector< double > &s_bulk)
The translation scheme for the east face (s0 = 1.0)
double s_max() const
Max. value of local coordinate.
Definition: Qelements.h:902
SolidQElement(const SolidQElement &)
Broken copy constructor.
Definition: Qelements.h:1959
virtual void set_integration_scheme(Integral *const &integral_pt)
Set the spatial integration scheme.
Definition: elements.cc:3150
unsigned nvertex_node() const
Number of vertex nodes in the element.
Definition: Qelements.h:1273
Base class for all brick elements.
Definition: Qelements.h:1184
Vector< double > * S_macro_ll_pt
Pointer to vector of lower left vertex coords. in macro element.
Definition: Qelements.h:342
unsigned get_bulk_node_number(const int &face_index, const unsigned &i) const
Definition: Qelements.h:1112
void face2(const Vector< double > &s, Vector< double > &s_bulk)
The translation scheme for the back face (s2 = -1.0)
void faces0(const Vector< double > &s, DenseMatrix< double > &dsbulk_dsface, unsigned &interior_direction)
Function for the east and west faces, along which s0 is fixed.
double s_max() const
Max. value of local coordinate.
Definition: Qelements.h:1270
void faces1(const Vector< double > &s, DenseMatrix< double > &dsbulk_dsface, unsigned &interior_direction)
Function for the up and down faces, along which s1 is fixed.
Vector< double > * S_macro_ur_pt
Pointer to vector of upper right vertex coords. in macro element.
Definition: Qelements.h:345
unsigned get_bulk_node_number(const int &face_index, const unsigned &i) const
Definition: Qelements.h:758
void face4(const Vector< double > &s, Vector< double > &s_bulk)
The translation scheme for the up face (s1 = 1.0)
void move_local_coord_back_into_element(Vector< double > &s) const
Adjust local coordinates so that they&#39;re located inside the element.
Definition: Qelements.h:154
A general Finite Element class.
Definition: elements.h:1274
PRefineableQElement()
Empty constuctor.
Definition: Qelements.h:2148
void write_paraview_output_offset_information(std::ofstream &file_out, const unsigned &nplot, unsigned &counter) const
Fill in the offset information for paraview plot. Needs to be implemented for each new geometric elem...
Definition: Qelements.h:652
virtual void set_macro_elem_pt(MacroElement *macro_elem_pt)
Set pointer to macro element also sets up storage for the reference coordinates and initialises them...
Definition: Qelements.h:168
char t
Definition: cfortran.h:572
unsigned nvertex_node() const
Number of vertex nodes in the element.
Definition: Qelements.h:906
void output(FILE *file_pt)
C-style output.
Definition: Qelements.h:1977
unsigned nnode_1d() const
Number of nodes along each element edge.
Definition: Qelements.h:633
Base class for Solid Qelements.
Definition: Qelements.h:359
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:852
unsigned nnode_1d() const
Number of nodes along each element edge.
Definition: Qelements.h:977
virtual void set_macro_elem_pt(MacroElement *macro_elem_pt, MacroElement *undeformed_macro_elem_pt)
Set pointers to "current" and "undeformed" MacroElements.
Definition: Qelements.h:397
void(* BulkCoordinateDerivativesFctPt)(const Vector< double > &s, DenseMatrix< double > &ds_bulk_dsface, unsigned &interior_direction)
Typedef for the function that returns the partial derivative of the local coordinates in the bulk ele...
Definition: elements.h:1253
QuadElementBase()
Constructor. Empty.
Definition: Qelements.h:826
void set_n_node(const unsigned &n)
Set the number of nodes in the element to n, by resizing the storage for pointers to the Node objects...
Definition: elements.h:1361
bool local_coord_is_valid(const Vector< double > &s)
Check whether the local coordinate are valid or not.
Definition: Qelements.h:137
void set_dimension(const unsigned &dim)
Set the dimension of the element and initially set the dimension of the nodes to be the same as the d...
Definition: elements.h:1344
unsigned nplot_points(const unsigned &nplot) const
Definition: Qelements.h:1506
virtual double s_min() const
Min value of local coordinate.
Definition: elements.h:2643
double invert_jacobian_mapping(const DenseMatrix< double > &jacobian, DenseMatrix< double > &inverse_jacobian) const
Overload the template-free interface for the calculation of inverse jacobian matrix. This is a one-dimensional element, so use the 1D version.
Definition: Qelements.h:563
Base class for Qelements.
Definition: Qelements.h:106
virtual void set_macro_elem_pt(MacroElement *macro_elem_pt)
Broken assignment operator.
Definition: Qelements.h:386
double invert_jacobian_mapping(const DenseMatrix< double > &jacobian, DenseMatrix< double > &inverse_jacobian) const
Overload the template-free interface for the calculation of the inverse jacobian mapping. This is a three-dimensional element, so use the 3d version.
Definition: Qelements.h:1262
virtual void set_macro_elem_pt(MacroElement *macro_elem_pt)
Set pointer to macro element – can be overloaded in derived elements to perform additional tasks...
Definition: elements.h:1833
Base class for all quad elements.
Definition: Qelements.h:821
double & s_macro_ur(const unsigned &i)
Access fct to the i-th coordinate of the element&#39;s "upper right" vertex in the associated MacroElemen...
Definition: Qelements.h:228
unsigned nlagrangian() const
Access function to # of Lagrangian coordinates.
Definition: geom_objects.h:182
QElement(const QElement &)
Broken copy constructor.
Definition: Qelements.h:864
unsigned nodal_dimension() const
Return the required Eulerian dimension of the nodes in this element.
Definition: elements.h:2370
void faces1(const Vector< double > &s, DenseMatrix< double > &dsbulk_dsface, unsigned &interior_direction)
Function for the north and south faces, along which s1 is fixed.
unsigned nplot_points_paraview(const unsigned &nplot) const
Return the number of actual plot points for paraview plot with parameter nplot.
Definition: Qelements.h:981
double s_macro_ur(const unsigned &i) const
Access fct to the i-th coordinate of the element&#39;s "upper right" vertex in the associated MacroElemen...
Definition: Qelements.h:262
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:3881
static Gauss< 2, NNODE_1D > Default_integration_scheme
Default integration rule: Gaussian integration of same &#39;order&#39; as the element.
Definition: Qelements.h:848
QElementGeometricBase()
Empty default constructor.
Definition: Qelements.h:76
unsigned nnode_on_face() const
Definition: Qelements.h:326
void write_paraview_type(std::ofstream &file_out, const unsigned &nplot) const
Return the paraview element type. Needs to be implemented for each new geometric element type; see ht...
Definition: Qelements.h:1421
BrickElementBase()
Constructor. Empty.
Definition: Qelements.h:1189
double local_one_d_fraction_of_node(const unsigned &n1d, const unsigned &i)
Definition: Qelements.h:622
virtual BulkCoordinateDerivativesFctPt bulk_coordinate_derivatives_fct_pt(const int &face_index) const
Definition: elements.h:3196
void faces0(const Vector< double > &s, DenseMatrix< double > &dsbulk_dsface, unsigned &interior_direction)
Function for the back and front faces, along which s0 is fixed.
std::string tecplot_zone_string(const unsigned &nplot) const
Return string for tecplot zone header (when plotting nplot points in each "coordinate direction) ...
Definition: Qelements.h:1496
virtual unsigned nsub_elements_paraview(const unsigned &nplot) const
Return the number of local sub-elements for paraview plot with parameter nplot. Broken virtual; can b...
Definition: elements.h:2726
virtual unsigned nvertex_node() const
Definition: elements.h:2374
static char t char * s
Definition: cfortran.h:572
void get_x_from_macro_element(const unsigned &t, const Vector< double > &s, Vector< double > &x)
Global coordinates as function of local coordinates at previous time "level" t (t=0: present; t>0: pr...
Definition: Qelements.h:302
double local_one_d_fraction_of_node(const unsigned &n1d, const unsigned &i)
Definition: Qelements.h:966
double s_min() const
Min. value of local coordinate.
Definition: Qelements.h:1267
void macro_map(const Vector< double > &s, Vector< double > &r)
The mapping from local to global coordinates at the current time : r(s)
Node * vertex_node_pt(const unsigned &j) const
Pointer to the j-th vertex node in the element.
Definition: Qelements.h:1277
unsigned nsub_elements_paraview(const unsigned &nplot) const
Return the number of local sub-elements for paraview plot with parameter nplot.
Definition: Qelements.h:1371
virtual void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Function to compute the geometric shape functions and derivatives w.r.t. local coordinates at local c...
Definition: elements.h:1922
virtual ~QElementBase()
Broken assignment operator.
Definition: Qelements.h:127
int face_outer_unit_normal_sign(const int &face_index) const
Get the sign of the outer unit normal on the face given by face_index.
Definition: Qelements.h:774
virtual CoordinateMappingFctPt face_to_bulk_coordinate_fct_pt(const int &face_index) const
Get a pointer to the function mapping face coordinates to bulk coordinates.
Definition: elements.h:3186
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Get local coordinates of node j in the element; vector sets its own size.
Definition: Qelements.h:1320
void face_node_number_error_check(const unsigned &i) const
Range check for face node numbers.
Definition: elements.h:3172
unsigned nplot_points(const unsigned &nplot) const
Return total number of plot points (when plotting nplot points in each "coordinate direction) ...
Definition: Qelements.h:748
virtual double s_max() const
Max. value of local coordinate.
Definition: elements.h:2654
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2109
SolidQElement(const SolidQElement &)
Broken copy constructor.
Definition: Qelements.h:1621
void output(std::ostream &outfile)
Output with default number of plot points.
MacroElement * macro_elem_pt()
Access function to pointer to macro element.
Definition: elements.h:1837
unsigned nsub_elements_paraview(const unsigned &nplot) const
Return the number of local sub-elements for paraview plot with parameter nplot.
Definition: Qelements.h:644
void faces0(const Vector< double > &s, DenseMatrix< double > &dsbulk_dsface, unsigned &interior_direction)
Function for both faces – the bulk coordinate is fixed on both.
void faces2(const Vector< double > &s, DenseMatrix< double > &dsbulk_dsface, unsigned &interior_direction)
Function for the left and right faces, along which s2 is fixed.
void local_fraction_of_node(const unsigned &j, Vector< double > &s_fraction)
Get the local fraction of node j in the element.
Definition: Qelements.h:1335
static Gauss< 3, NNODE_1D > Default_integration_scheme
Default integration rule: Gaussian integration of same &#39;order&#39; as the element.
Definition: Qelements.h:1211
void face3(const Vector< double > &s, Vector< double > &s_bulk)
The translation scheme for the right face (s0 = 1.0)
unsigned nplot_points(const unsigned &nplot) const
Definition: Qelements.h:1102
unsigned dim() const
Return the spatial dimension of the element, i.e. the number of local coordinates required to paramet...
Definition: elements.h:2482
double & s_macro_ll(const unsigned &i)
Access fct to the i-th coordinate of the element&#39;s "lower left" vertex in the associated MacroElement...
Definition: Qelements.h:211
A Class for nodes that deform elastically (i.e. position is an unknown in the problem). The idea is that the Eulerian positions are stored in a Data object and the Lagrangian coordinates are stored in addition. The pointer that addresses the Eulerian positions is set to the pointer to Value in the Data object. Hence, SolidNode uses knowledge of the internal structure of Data and must be a friend of the Data class. In order to allow a mesh to deform via an elastic-style equation in deforming-domain problems, the positions are stored separately from the values, so that elastic problems may be combined with any other type of problem.
Definition: nodes.h:1569
LineElementBase()
Constructor. Empty.
Definition: Qelements.h:497
void face0(const Vector< double > &s, Vector< double > &s_bulk)
The translation scheme for the west face (s0 = -1.0)
virtual unsigned nnode_1d() const
Return the number of nodes along one edge of the element Default is to return zero — must be overloa...
Definition: elements.h:2151
void get_x_from_macro_element(const Vector< double > &s, Vector< double > &x) const
Global coordinates as function of local coordinates. using the macro element representation.
Definition: Qelements.h:277
RefineableSolidQElement()
Empty constuctor.
Definition: Qelements.h:2161
double invert_jacobian_mapping(const DenseMatrix< double > &jacobian, DenseMatrix< double > &inverse_jacobian) const
Overload the template-free interface for the calculation of inverse jacobian matrix. This is a two-dimensional element, so use the two-d version.
Definition: Qelements.h:894
void output(std::ostream &outfile)
Broken assignment operator.
Definition: Qelements.h:1971
QSolidElementBase(const QSolidElementBase &)
Broken copy constructor.
Definition: Qelements.h:368
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn&#39;t been defined.
void get_x_and_xi(const Vector< double > &s, Vector< double > &x_fe, Vector< double > &x, Vector< double > &xi_fe, Vector< double > &xi) const
Eulerian and Lagrangian coordinates as function of the local coordinates: The Eulerian position is re...
Definition: Qelements.h:416
void write_paraview_offsets(std::ofstream &file_out, const unsigned &nplot, unsigned &offset_sum) const
Return the offsets for the paraview sub-elements. Needs to be implemented for each new geometric elem...
Definition: Qelements.h:686
void face1(const Vector< double > &s, Vector< double > &s_bulk)
The translation scheme for the down face (s1 = -1.0)
void write_paraview_type(std::ofstream &file_out, const unsigned &nplot) const
Return the paraview element type. Needs to be implemented for each new geometric element type; see ht...
Definition: Qelements.h:673
double s_min() const
Min. value of local coordinate.
Definition: Qelements.h:899
void get_s_plot(const unsigned &i, const unsigned &nplot, Vector< double > &s, const bool &use_equally_spaced_interior_sample_points=false) const
Get cector of local coordinates of plot point i (when plotting nplot points in each "coordinate direc...
Definition: Qelements.h:1460
QElement(const QElement &)
Broken copy constructor.
Definition: Qelements.h:1228
void get_s_plot(const unsigned &i, const unsigned &nplot, Vector< double > &s, const bool &use_equally_spaced_interior_sample_points=false) const
Get cector of local coordinates of plot point i (when plotting nplot points in each "coordinate direc...
Definition: Qelements.h:1062
void local_fraction_of_node(const unsigned &j, Vector< double > &s_fraction)
Get the local fraction of node j in the element.
Definition: Qelements.h:612
virtual Node * vertex_node_pt(const unsigned &j) const
Pointer to the j-th vertex node in the element. Broken virtual function in "pure" finite elements...
Definition: elements.h:2383
void face0(const Vector< double > &s, Vector< double > &s_bulk)
The translation scheme for the left face (s0 = -1.0)
virtual void build_face_element(const int &face_index, FaceElement *face_element_pt)
Function for building a lower dimensional FaceElement on the specified face of the FiniteElement...
Definition: elements.cc:5002
Node * vertex_node_pt(const unsigned &j) const
Pointer to the j-th vertex node in the element.
Definition: Qelements.h:578
void output(std::ostream &outfile)
Broken assignment operator.
Definition: Qelements.h:1800
void face5(const Vector< double > &s, Vector< double > &s_bulk)
The translation scheme for the front face (s2 = 1.0)
QElementGeometricBase(const QElementGeometricBase &)
Broken copy constructor.
Definition: Qelements.h:79
static Gauss< 1, NNODE_1D > Default_integration_scheme
Default integration rule: Gaussian integration of same &#39;order&#39; as the element.
Definition: Qelements.h:519
double s_max() const
Max. value of local coordinate.
Definition: Qelements.h:571
double s_min() const
Min. value of local coordinate.
Definition: Qelements.h:568
std::string tecplot_zone_string(const unsigned &nplot) const
Return string for tecplot zone header (when plotting nplot points in each "coordinate direction) ...
Definition: Qelements.h:739
QElementBase(const QElementBase &)
Broken copy constructor.
Definition: Qelements.h:115
void output(std::ostream &outfile)
Broken assignment operator.
Definition: Qelements.h:1633
void face3(const Vector< double > &s, Vector< double > &s_bulk)
The translation scheme for the north face (s1 = 1.0)
void write_paraview_output_offset_information(std::ofstream &file_out, const unsigned &nplot, unsigned &counter) const
Fill in the offset information for paraview plot. Needs to be implemented for each new geometric elem...
Definition: Qelements.h:1379
RefineableQElement()
Empty constuctor.
Definition: Qelements.h:2132
unsigned nnode_1d() const
Number of nodes along each element edge.
Definition: Qelements.h:1360
SolidFiniteElement class.
Definition: elements.h:3361
virtual void shape(const Vector< double > &s, Shape &psi) const =0
Calculate the geometric shape functions at local coordinate s. This function must be overloaded for e...
void output(FILE *file_pt)
C-style output.
Definition: Qelements.h:1806
double s_macro_ll(const unsigned &i) const
Access fct to the i-th coordinate of the element&#39;s "lower left" vertex in the associated MacroElement...
Definition: Qelements.h:245
MacroElement * Macro_elem_pt
Pointer to the element&#39;s macro element (NULL by default)
Definition: elements.h:1647
unsigned nsub_elements_paraview(const unsigned &nplot) const
Return the number of local sub-elements for paraview plot with parameter nplot.
Definition: Qelements.h:988
int face_outer_unit_normal_sign(const int &face_index) const
Get the sign of the outer unit normal on the face given by face_index.
Definition: Qelements.h:1538
QElement(const QElement &)
Broken copy constructor.
Definition: Qelements.h:535