Telements.h
Go to the documentation of this file.
1// LIC// ====================================================================
2// LIC// This file forms part of oomph-lib, the object-oriented,
3// LIC// multi-physics finite-element library, available
4// LIC// at http://www.oomph-lib.org.
5// LIC//
6// LIC// Copyright (C) 2006-2022 Matthias Heil and Andrew Hazel
7// LIC//
8// LIC// This library is free software; you can redistribute it and/or
9// LIC// modify it under the terms of the GNU Lesser General Public
10// LIC// License as published by the Free Software Foundation; either
11// LIC// version 2.1 of the License, or (at your option) any later version.
12// LIC//
13// LIC// This library is distributed in the hope that it will be useful,
14// LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// LIC// Lesser General Public License for more details.
17// LIC//
18// LIC// You should have received a copy of the GNU Lesser General Public
19// LIC// License along with this library; if not, write to the Free Software
20// LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21// LIC// 02110-1301 USA.
22// LIC//
23// LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24// LIC//
25// LIC//====================================================================
26// Header functions for classes that define Telements
27#ifndef OOMPH_TELEMENT_HEADER
28#define OOMPH_TELEMENT_HEADER
29
30// Config header generated by autoconfig
31#ifdef HAVE_CONFIG_H
32#include <oomph-lib-config.h>
33#endif
34
35#ifdef OOMPH_HAS_MPI
36#include "mpi.h"
37#endif
38
39// oomph-lib headers
40#include "Vector.h"
41#include "shape.h"
42#include "integral.h"
43#include "elements.h"
44
45namespace oomph
46{
47 /// ////////////////////////////////////////////////////////////////////////
48 /// ////////////////////////////////////////////////////////////////////////
49 /// ////////////////////////////////////////////////////////////////////////
50
51
52 //===================================================
53 /// Triangular Face class
54 //===================================================
55 class TFace
56 {
57 public:
58 /// Constructor: Pass in the three vertex nodes
60 {
61 if ((node1_pt == node2_pt) || (node2_pt == node3_pt) ||
62 (node1_pt == node3_pt))
63 {
64#ifdef PARANOID
65 std::ostringstream error_stream;
66 error_stream << "TFace cannot have two identical vertex nodes\n";
67 throw OomphLibError(
68 error_stream.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
69#endif
70 }
71
72 // Sort lexicographically based on pointer address of nodes
73 std::set<Node*> nodes;
74 nodes.insert(node1_pt);
75 nodes.insert(node2_pt);
76 nodes.insert(node3_pt);
77 std::set<Node*>::iterator it = nodes.begin();
78 Node1_pt = (*it);
79 it++;
80 Node2_pt = (*it);
81 it++;
82 Node3_pt = (*it);
83 it++;
84 }
85
86
87 /// Access to the first vertex node
88 Node* node1_pt() const
89 {
90 return Node1_pt;
91 }
92
93 /// Access to the second vertex node
94 Node* node2_pt() const
95 {
96 return Node2_pt;
97 }
98
99 /// Access to the third vertex node
100 Node* node3_pt() const
101 {
102 return Node3_pt;
103 }
104
105 /// Comparison operator
106 bool operator==(const TFace& other) const
107 {
108 if ((Node1_pt == other.node1_pt()) && (Node2_pt == other.node2_pt()) &&
109 (Node3_pt == other.node3_pt()))
110 {
111 return true;
112 }
113 else
114 {
115 return false;
116 }
117 }
118
119
120 /// Less-than operator
121 bool operator<(const TFace& other) const
122 {
123 if (Node1_pt < other.node1_pt())
124 {
125 return true;
126 }
127 else if (Node1_pt == other.node1_pt())
128 {
129 if (Node2_pt < other.node2_pt())
130 {
131 return true;
132 }
133 else if (Node2_pt == other.node2_pt())
134 {
135 if (Node3_pt < other.node3_pt())
136 {
137 return true;
138 }
139 else
140 {
141 return false;
142 }
143 }
144 else
145 {
146 return false;
147 }
148 }
149 else
150 {
151 return false;
152 }
153 }
154
155
156 /// Test whether the face lies on a boundary. Relatively simple
157 /// test, based on all vertices lying on (some) boundary.
158 bool is_on_boundary() const
159 {
162 }
163
164
165 /// Test whether the face is a boundary face, i.e. does it
166 /// connnect three boundary nodes?
167 bool is_boundary_face() const
168 {
169 return ((dynamic_cast<BoundaryNodeBase*>(Node1_pt) != 0) &&
170 (dynamic_cast<BoundaryNodeBase*>(Node2_pt) != 0) &&
171 (dynamic_cast<BoundaryNodeBase*>(Node3_pt) != 0));
172 }
173
174 /// Access to pointer to set of mesh boundaries that this
175 /// face occupies; NULL if the node is not on any boundary.
176 /// Construct via set intersection of the boundary sets for the
177 /// associated vertex nodes
178 void get_boundaries_pt(std::set<unsigned>*& boundaries_pt)
179 {
180 std::set<unsigned> set1;
181 std::set<unsigned>* set1_pt = &set1;
182 Node1_pt->get_boundaries_pt(set1_pt);
183 std::set<unsigned> set2;
184 std::set<unsigned>* set2_pt = &set2;
185 Node2_pt->get_boundaries_pt(set2_pt);
186 std::set<unsigned> set3;
187 std::set<unsigned>* set3_pt = &set3;
188 Node3_pt->get_boundaries_pt(set3_pt);
189 std::set<unsigned> aux_set;
190 set_intersection((*set1_pt).begin(),
191 (*set1_pt).end(),
192 (*set2_pt).begin(),
193 (*set2_pt).end(),
194 inserter(aux_set, aux_set.begin()));
195 set_intersection(aux_set.begin(),
196 aux_set.end(),
197 (*set3_pt).begin(),
198 (*set3_pt).end(),
199 inserter((*boundaries_pt), (*boundaries_pt).begin()));
200 }
201
202
203 private:
204 /// First vertex node
206
207 /// Second vertex node
209
210 /// Third vertex node
212 };
213
214
215 /// ////////////////////////////////////////////////////////////////////
216 /// ////////////////////////////////////////////////////////////////////
217 /// ////////////////////////////////////////////////////////////////////
218
219
220 //========================================================================
221 /// A class for those member functions that must be fully specialised
222 /// for the Telements. The fact that member functions of partially
223 /// specialised classes cannot necessarily be fully specialised
224 /// means that we must either fully specialise every class, or use this
225 /// base class to fully specialize only those functions that are required.
226 //========================================================================
227 template<unsigned DIM, unsigned NNODE_1D>
229 {
230 };
231
232 /// //////////////////////////////////////////////////////////////////////
233 /// TElementShape inline functions:
234 /// //////////////////////////////////////////////////////////////////////
235 template<>
236 class TElementShape<1, 2>
237 {
238 public:
239 //=======================================================================
240 /// Return local coordinates of node j
241 //=======================================================================
242 void local_coordinate_of_node(const unsigned& j, Vector<double>& s) const
243 {
244 s.resize(1);
245 switch (j)
246 {
247 case 0:
248 s[0] = 0.0;
249 break;
250
251 case 1:
252 s[0] = 1.0;
253 break;
254
255 default:
256 std::ostringstream error_message;
257 error_message
258 << "Element only has two nodes; called with node number " << j
259 << std::endl;
260
261 throw OomphLibError(error_message.str(),
262 OOMPH_CURRENT_FUNCTION,
263 OOMPH_EXCEPTION_LOCATION);
264 }
265 }
266
267
268 //=======================================================================
269 /// Shape function for specific TElement<1,2>
270 //=======================================================================
271 void shape(const Vector<double>& s, Shape& psi) const
272 {
273 psi[0] = 1.0 - s[0];
274 psi[1] = s[0];
275 }
276
277
278 //=======================================================================
279 /// Derivatives of shape functions for specific TElement<2,2>
280 //=======================================================================
281 void dshape_local(const Vector<double>& s, Shape& psi, DShape& dpsids) const
282 {
283 this->shape(s, psi);
284
285 // Derivatives
286 dpsids(0, 0) = -1.0;
287 dpsids(1, 0) = 1.0;
288 }
289
290
291 //=======================================================================
292 /// Second derivatives of shape functions for specific TElement<1,2>:
293 /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
294 //=======================================================================
296 Shape& psi,
297 DShape& dpsids,
298 DShape& d2psids) const
299 {
300 this->dshape_local(s, psi, dpsids);
301
302 d2psids(0, 0) = 0.0;
303 d2psids(1, 0) = 0.0;
304 }
305 };
306
307
308 template<>
309 class TElementShape<1, 3>
310 {
311 public:
312 //=======================================================================
313 /// Return local coordinates of node j
314 //=======================================================================
315 void local_coordinate_of_node(const unsigned& j, Vector<double>& s) const
316 {
317 s.resize(1);
318 switch (j)
319 {
320 case 0:
321 s[0] = 0.0;
322 break;
323
324 case 1:
325 s[0] = 0.5;
326 break;
327
328 case 2:
329 s[0] = 1.0;
330 break;
331
332 default:
333 std::ostringstream error_message;
334 error_message
335 << "Element only has three nodes; called with node number " << j
336 << std::endl;
337
338 throw OomphLibError(error_message.str(),
339 OOMPH_CURRENT_FUNCTION,
340 OOMPH_EXCEPTION_LOCATION);
341 }
342 }
343
344
345 //=======================================================================
346 /// Shape function for specific TElement<1,3>
347 //=======================================================================
348 void shape(const Vector<double>& s, Shape& psi) const
349 {
350 psi[0] = 2.0 * (s[0] - 1.0) * (s[0] - 0.5);
351 psi[1] = 4.0 * (1.0 - s[0]) * s[0];
352 psi[2] = 2.0 * (s[0] - 0.5) * s[0];
353 }
354
355
356 //=======================================================================
357 /// Derivatives of shape functions for specific TElement<1,3>
358 //=======================================================================
359 void dshape_local(const Vector<double>& s, Shape& psi, DShape& dpsids) const
360 {
361 // ALH: Don't know why object qualifier is needed
362 this->shape(s, psi);
363
364 dpsids(0, 0) = 4.0 * s[0] - 3.0;
365 dpsids(1, 0) = 4.0 - 8.0 * s[0];
366 dpsids(2, 0) = 4.0 * s[0] - 1.0;
367 }
368
369
370 //=======================================================================
371 /// Second derivatives of shape functions for specific TElement<1,3>:
372 /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
373 //=======================================================================
375 Shape& psi,
376 DShape& dpsids,
377 DShape& d2psids) const
378 {
379 // ALH: Don't know why object qualifier is needed
380 this->dshape_local(s, psi, dpsids);
381
382 d2psids(0, 0) = 4.0;
383 d2psids(1, 0) = -8.0;
384 d2psids(2, 0) = 4.0;
385 }
386 };
387
388 template<>
389 class TElementShape<1, 4>
390 {
391 public:
392 //=======================================================================
393 /// Return local coordinates of node j
394 //=======================================================================
395 void local_coordinate_of_node(const unsigned& j, Vector<double>& s) const
396 {
397 s.resize(1);
398 switch (j)
399 {
400 case 0:
401 s[0] = 0.0;
402 break;
403
404 case 1:
405 s[0] = (1.0 / 3.0);
406 break;
407
408 case 2:
409 s[0] = (2.0 / 3.0);
410 break;
411
412 case 3:
413 s[0] = 1.0;
414 break;
415
416 default:
417 std::ostringstream error_message;
418 error_message
419 << "Element only has four nodes; called with node number " << j
420 << std::endl;
421
422 throw OomphLibError(error_message.str(),
423 OOMPH_CURRENT_FUNCTION,
424 OOMPH_EXCEPTION_LOCATION);
425 }
426 }
427
428
429 //=======================================================================
430 /// Shape function for specific TElement<1,4>
431 //=======================================================================
432 void shape(const Vector<double>& s, Shape& psi) const
433 {
434 psi[0] = 0.5 * (1.0 - s[0]) * (3.0 * s[0] - 2.0) * (3.0 * s[0] - 1.0);
435 psi[1] = -4.5 * s[0] * (1.0 - s[0]) * (3.0 * s[0] - 2.0);
436 psi[2] = 4.5 * s[0] * (1.0 - s[0]) * (3.0 * s[0] - 1.0);
437 psi[3] = 0.5 * s[0] * (3.0 * s[0] - 2.0) * (3.0 * s[0] - 1.0);
438 }
439
440 //=======================================================================
441 /// Derivatives of shape functions for specific TElement<1,4>
442 //=======================================================================
443 void dshape_local(const Vector<double>& s, Shape& psi, DShape& dpsids) const
444 {
445 // ALH: Don't know why object qualifier is needed
446 this->shape(s, psi);
447
448 dpsids(0, 0) = -13.5 * s[0] * s[0] + 18.0 * s[0] - 5.5;
449 dpsids(1, 0) = 40.5 * s[0] * s[0] - 45.0 * s[0] + 9.0;
450 dpsids(2, 0) = -40.5 * s[0] * s[0] + 36.0 * s[0] - 4.5;
451 dpsids(3, 0) = 13.5 * s[0] * s[0] - 9.0 * s[0] + 1.0;
452 }
453
454 //=======================================================================
455 /// Second derivatives of shape functions for specific TElement<2,4>:
456 /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
457 //=======================================================================
459 Shape& psi,
460 DShape& dpsids,
461 DShape& d2psids) const
462 {
463 throw OomphLibError(
464 "Not checked yet", OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
465
466 // ALH: Don't know why object qualifier is needed
467 this->dshape_local(s, psi, dpsids);
468
469 d2psids(0, 0) = 0.0;
470 d2psids(1, 0) = 0.0;
471 d2psids(2, 0) = 0.0;
472 d2psids(3, 0) = 0.0;
473 }
474 };
475
476
477 template<>
478 class TElementShape<2, 2>
479 {
480 public:
481 //=======================================================================
482 /// Return local coordinates of node j
483 //=======================================================================
484 void local_coordinate_of_node(const unsigned& j, Vector<double>& s) const
485 {
486 s.resize(2);
487
488 switch (j)
489 {
490 case 0:
491 s[0] = 1.0;
492 s[1] = 0.0;
493 break;
494
495 case 1:
496 s[0] = 0.0;
497 s[1] = 1.0;
498 break;
499
500 case 2:
501 s[0] = 0.0;
502 s[1] = 0.0;
503 break;
504
505 default:
506 std::ostringstream error_message;
507 error_message
508 << "Element only has three nodes; called with node number " << j
509 << std::endl;
510
511 throw OomphLibError(error_message.str(),
512 OOMPH_CURRENT_FUNCTION,
513 OOMPH_EXCEPTION_LOCATION);
514 }
515 }
516
517
518 //=======================================================================
519 /// Shape function for specific TElement<2,2>
520 //=======================================================================
521 void shape(const Vector<double>& s, Shape& psi) const
522 {
523 psi[0] = s[0];
524 psi[1] = s[1];
525 psi[2] = 1.0 - s[0] - s[1];
526 }
527
528
529 //=======================================================================
530 /// Derivatives of shape functions for specific TElement<2,2>
531 //=======================================================================
532 void dshape_local(const Vector<double>& s, Shape& psi, DShape& dpsids) const
533 {
534 this->shape(s, psi);
535
536 // Derivatives
537 dpsids(0, 0) = 1.0;
538 dpsids(0, 1) = 0.0;
539 dpsids(1, 0) = 0.0;
540 dpsids(1, 1) = 1.0;
541 dpsids(2, 0) = -1.0;
542 dpsids(2, 1) = -1.0;
543 }
544
545
546 //=======================================================================
547 /// Second derivatives of shape functions for specific TElement<2,2>:
548 /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
549 /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
550 /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
551 //=======================================================================
553 Shape& psi,
554 DShape& dpsids,
555 DShape& d2psids) const
556 {
557 this->dshape_local(s, psi, dpsids);
558
559 for (unsigned i = 0; i < 3; i++)
560 {
561 d2psids(i, 0) = 0.0;
562 d2psids(i, 1) = 0.0;
563 d2psids(i, 2) = 0.0;
564 }
565 }
566 };
567
568 template<>
569 class TElementShape<2, 3>
570 {
571 public:
572 //=======================================================================
573 /// Return local coordinates of node j
574 //=======================================================================
575 void local_coordinate_of_node(const unsigned& j, Vector<double>& s) const
576 {
577 s.resize(2);
578
579 switch (j)
580 {
581 case 0:
582 s[0] = 1.0;
583 s[1] = 0.0;
584 break;
585
586 case 1:
587 s[0] = 0.0;
588 s[1] = 1.0;
589 break;
590
591 case 2:
592 s[0] = 0.0;
593 s[1] = 0.0;
594 break;
595
596 case 3:
597 s[0] = 0.5;
598 s[1] = 0.5;
599 break;
600
601 case 4:
602 s[0] = 0.0;
603 s[1] = 0.5;
604 break;
605
606 case 5:
607 s[0] = 0.5;
608 s[1] = 0.0;
609 break;
610
611 default:
612 std::ostringstream error_message;
613 error_message
614 << "Element only has six nodes; called with node number " << j
615 << std::endl;
616
617 throw OomphLibError(error_message.str(),
618 OOMPH_CURRENT_FUNCTION,
619 OOMPH_EXCEPTION_LOCATION);
620 }
621 }
622
623
624 //=======================================================================
625 /// Shape function for specific TElement<2,3>
626 //=======================================================================
627 void shape(const Vector<double>& s, Shape& psi) const
628 {
629 // Reconstruct the third area coordinate
630 double s_2 = 1.0 - s[0] - s[1];
631
632 // note that s[2] needs replacing by s_2 everywhere since only
633 // two independent variables s[0],s[1] and s_2 is expressed in terms of
634 // those later.
635 psi[0] = 2.0 * s[0] * (s[0] - 0.5);
636 psi[1] = 2.0 * s[1] * (s[1] - 0.5);
637 psi[2] = 2.0 * s_2 * (s_2 - 0.5);
638 psi[3] = 4.0 * s[0] * s[1];
639 psi[4] = 4.0 * s[1] * s_2;
640 psi[5] = 4.0 * s_2 * s[0];
641 }
642
643
644 //=======================================================================
645 /// Derivatives of shape functions for specific TElement<2,3>
646 //=======================================================================
647 void dshape_local(const Vector<double>& s, Shape& psi, DShape& dpsids) const
648 {
649 // ALH: Don't know why object qualifier is needed
650 this->shape(s, psi);
651
652 dpsids(0, 0) = 4.0 * s[0] - 1.0;
653 dpsids(0, 1) = 0.0;
654 dpsids(1, 0) = 0.0;
655 dpsids(1, 1) = 4.0 * s[1] - 1.0;
656 dpsids(2, 0) = 2.0 * (2.0 * s[0] - 1.5 + 2.0 * s[1]);
657 dpsids(2, 1) = 2.0 * (2.0 * s[0] - 1.5 + 2.0 * s[1]);
658 dpsids(3, 0) = 4.0 * s[1];
659 dpsids(3, 1) = 4.0 * s[0];
660 dpsids(4, 0) = -4.0 * s[1];
661 dpsids(4, 1) = 4.0 * (1.0 - s[0] - 2.0 * s[1]);
662 dpsids(5, 0) = 4.0 * (1.0 - 2.0 * s[0] - s[1]);
663 dpsids(5, 1) = -4.0 * s[0];
664 }
665
666
667 //=======================================================================
668 /// Second derivatives of shape functions for specific TElement<2,3>:
669 /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
670 /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
671 /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
672 //=======================================================================
674 Shape& psi,
675 DShape& dpsids,
676 DShape& d2psids) const
677 {
678 // ALH: Don't know why object qualifier is needed
679 this->dshape_local(s, psi, dpsids);
680
681 d2psids(0, 0) = 4.0;
682 d2psids(0, 1) = 0.0;
683 d2psids(0, 2) = 0.0;
684
685 d2psids(1, 0) = 0.0;
686 d2psids(1, 1) = 4.0;
687 d2psids(1, 2) = 0.0;
688
689 d2psids(2, 0) = 4.0;
690 d2psids(2, 1) = 4.0;
691 d2psids(2, 2) = 4.0;
692
693 d2psids(3, 0) = 0.0;
694 d2psids(3, 1) = 0.0;
695 d2psids(3, 2) = 4.0;
696
697 d2psids(4, 0) = 0.0;
698 d2psids(4, 1) = -8.0;
699 d2psids(4, 2) = -4.0;
700
701 d2psids(5, 0) = -8.0;
702 d2psids(5, 1) = 0.0;
703 d2psids(5, 2) = -4.0;
704 }
705 };
706
707 template<>
708 class TElementShape<2, 4>
709 {
710 public:
711 //=======================================================================
712 /// Return local coordinates of node j
713 //=======================================================================
714 void local_coordinate_of_node(const unsigned& j, Vector<double>& s) const
715 {
716 s.resize(2);
717
718 switch (j)
719 {
720 case 0:
721 s[0] = 1.0;
722 s[1] = 0.0;
723 break;
724
725 case 1:
726 s[0] = 0.0;
727 s[1] = 1.0;
728 break;
729
730 case 2:
731 s[0] = 0.0;
732 s[1] = 0.0;
733 break;
734
735 case 3:
736 s[0] = 2.0 / 3.0;
737 s[1] = 1.0 / 3.0;
738 break;
739
740 case 4:
741 s[0] = 1.0 / 3.0;
742 s[1] = 2.0 / 3.0;
743 break;
744
745 case 5:
746 s[0] = 0.0;
747 s[1] = 2.0 / 3.0;
748 break;
749
750 case 6:
751 s[0] = 0.0;
752 s[1] = 1.0 / 3.0;
753 break;
754
755 case 8:
756 s[0] = 2.0 / 3.0;
757 s[1] = 0.0;
758 break;
759
760 case 7:
761 s[0] = 1.0 / 3.0;
762 s[1] = 0.0;
763 break;
764
765 case 9:
766 s[0] = 1.0 / 3.0;
767 s[1] = 1.0 / 3.0;
768 break;
769
770 default:
771 std::ostringstream error_message;
772 error_message
773 << "Element only has ten nodes; called with node number " << j
774 << std::endl;
775
776 throw OomphLibError(error_message.str(),
777 OOMPH_CURRENT_FUNCTION,
778 OOMPH_EXCEPTION_LOCATION);
779 }
780 }
781
782
783 //=======================================================================
784 /// Shape function for specific TElement<2,4>
785 //=======================================================================
786 void shape(const Vector<double>& s, Shape& psi) const
787 {
788 psi[0] = 0.5 * s[0] * (3.0 * s[0] - 2.0) * (3.0 * s[0] - 1.0);
789 psi[1] = 0.5 * s[1] * (3.0 * s[1] - 2.0) * (3.0 * s[1] - 1.0);
790 psi[2] = 0.5 * (1.0 - s[0] - s[1]) * (1.0 - 3.0 * s[0] - 3.0 * s[1]) *
791 (2.0 - 3.0 * s[0] - 3.0 * s[1]);
792 psi[3] = 4.5 * s[0] * s[1] * (3.0 * s[0] - 1.0);
793 psi[4] = 4.5 * s[0] * s[1] * (3.0 * s[1] - 1.0);
794 psi[5] = 4.5 * s[1] * (1.0 - s[0] - s[1]) * (3.0 * s[1] - 1.0);
795 psi[6] =
796 4.5 * s[1] * (1.0 - s[0] - s[1]) * (3.0 * (1.0 - s[0] - s[1]) - 1.0);
797 psi[7] = 4.5 * s[0] * (1.0 - s[0] - s[1]) * (2.0 - 3 * s[0] - 3 * s[1]);
798 psi[8] = 4.5 * s[0] * (1.0 - s[0] - s[1]) * (3.0 * s[0] - 1.0);
799 psi[9] = 27.0 * s[0] * s[1] * (1.0 - s[0] - s[1]);
800 }
801
802 //=======================================================================
803 /// Derivatives of shape functions for specific TElement<2,4>
804 //=======================================================================
805 void dshape_local(const Vector<double>& s, Shape& psi, DShape& dpsids) const
806 {
807 // ALH: Don't know why object qualifier is needed
808 this->shape(s, psi);
809
810 dpsids(0, 0) = 13.5 * s[0] * s[0] - 9.0 * s[0] + 1.0;
811 dpsids(0, 1) = 0.0;
812 dpsids(1, 0) = 0.0;
813 dpsids(1, 1) = 13.5 * s[1] * s[1] - 9.0 * s[1] + 1.0;
814 dpsids(2, 0) = 0.5 * (36.0 * s[0] + 36.0 * s[1] - 27.0 * s[0] * s[0] -
815 27.0 * s[1] * s[1] - 54.0 * s[0] * s[1] - 11.0);
816 dpsids(2, 1) = 0.5 * (36.0 * s[0] + 36.0 * s[1] - 27.0 * s[0] * s[0] -
817 27.0 * s[1] * s[1] - 54.0 * s[0] * s[1] - 11.0);
818 dpsids(3, 0) = 27.0 * s[0] * s[1] - 4.5 * s[1];
819 dpsids(3, 1) = 4.5 * s[0] * (3.0 * s[0] - 1.0);
820 dpsids(4, 0) = 4.5 * s[1] * (3.0 * s[1] - 1.0);
821 dpsids(4, 1) = 27.0 * s[0] * s[1] - 4.5 * s[0];
822 dpsids(5, 0) = 4.5 * (s[1] - 3.0 * s[1] * s[1]);
823 dpsids(5, 1) =
824 4.5 * (s[0] - 6.0 * s[0] * s[1] - 9.0 * s[1] * s[1] + 8 * s[1] - 1.0);
825 dpsids(6, 0) = 4.5 * (6.0 * s[0] * s[1] - 5.0 * s[1] + 6.0 * s[1] * s[1]);
826 dpsids(6, 1) =
827 4.5 * (2.0 - 5.0 * s[0] + 3.0 * s[0] * s[0] + 12.0 * s[0] * s[1] -
828 10.0 * s[1] + 9.0 * s[1] * s[1]);
829 dpsids(7, 0) =
830 4.5 * (2.0 - 10.0 * s[0] + 9.0 * s[0] * s[0] + 12.0 * s[0] * s[1] -
831 5.0 * s[1] + 3.0 * s[1] * s[1]);
832 dpsids(7, 1) = 4.5 * (6.0 * s[0] * s[0] - 5.0 * s[0] + 6.0 * s[0] * s[1]);
833 dpsids(8, 0) =
834 4.5 * (s[1] - 6.0 * s[0] * s[1] - 9.0 * s[0] * s[0] + 8 * s[0] - 1.0);
835 dpsids(8, 1) = 4.5 * (s[0] - 3.0 * s[0] * s[0]);
836 dpsids(9, 0) = 27.0 * s[1] - 54.0 * s[0] * s[1] - 27.0 * s[1] * s[1];
837 dpsids(9, 1) = 27.0 * s[0] - 54.0 * s[0] * s[1] - 27.0 * s[0] * s[0];
838 }
839
840 //=======================================================================
841 /// Second derivatives of shape functions for specific TElement<2,4>:
842 /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
843 /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
844 /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
845 //=======================================================================
847 Shape& psi,
848 DShape& dpsids,
849 DShape& d2psids) const
850 {
851 throw OomphLibError(
852 "Not checked yet", OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
853
854 // ALH: Don't know why object qualifier is needed
855 this->dshape_local(s, psi, dpsids);
856
857 d2psids(0, 0) = 9.0 * (3.0 * s[0] - 1.0);
858 d2psids(0, 1) = 0.0;
859 d2psids(0, 2) = 0.0;
860 d2psids(1, 0) = 0.0;
861 d2psids(1, 1) = 0.0;
862 d2psids(1, 2) = 9.0 * (3.0 * s[1] - 1.0);
863 d2psids(2, 0) = 9.0 * (2.0 - 3.0 * s[0] - 3.0 * s[1]);
864 d2psids(2, 1) = 9.0 * (2.0 - 3.0 * s[0] - 3.0 * s[1]);
865 d2psids(2, 2) = 9.0 * (2.0 - 3.0 * s[0] - 3.0 * s[1]);
866 d2psids(3, 0) = 27.0 * s[1];
867 d2psids(3, 1) = 0.0;
868 d2psids(3, 2) = 27.0 * s[0] - 4.5;
869 d2psids(4, 0) = 0.0;
870 d2psids(4, 1) = 27.0 * s[0];
871 d2psids(4, 2) = 27.0 * s[1] - 4.5;
872 d2psids(5, 0) = 0.0;
873 d2psids(5, 1) = 9.0 * (4.0 - 3.0 * s[0] - 9.0 * s[1]);
874 d2psids(5, 2) = 4.5 * (1.0 - 6.0 * s[1]);
875 d2psids(6, 0) = 27.0 * s[1];
876 d2psids(6, 1) = 9.0 * (6.0 * s[0] + 9.0 * s[1] - 5.0);
877 d2psids(6, 2) = 4.5 * (6.0 * s[0] + 12.0 * s[1] - 5.0);
878 d2psids(8, 0) = 9.0 * (4.0 - 9.0 * s[0] - 3.0 * s[1]);
879 d2psids(8, 1) = 0.0;
880 d2psids(8, 2) = 4.5 * (1.0 - 6.0 * s[0]);
881 d2psids(7, 0) = 9.0 * (9.0 * s[0] + 6.0 * s[1] - 5.0);
882 d2psids(7, 1) = 27.0 * s[0];
883 d2psids(7, 2) = 4.5 * (12.0 * s[0] + 6.0 * s[1] - 5.0);
884 d2psids(9, 0) = -54.0 * s[1];
885 d2psids(9, 1) = -54.0 * s[0];
886 d2psids(9, 2) = 27.0 - 54.0 * s[0] - 54.0 * s[1];
887 }
888 };
889
890
891 //========================================================================
892 /// A class for those member functions that must be fully specialised
893 /// for Telements that are enriched by bubbble functions.
894 /// The fact that member functions of partially
895 /// specialised classes cannot necessarily be fully specialised
896 /// means that we must either fully specialise every class, or use this
897 /// base class to fully specialize only those functions that are required.
898 //========================================================================
899 template<unsigned DIM, unsigned NNODE_1D>
901 {
902 };
903
904
905 /// ////////////////////////////////////////////////////////////////////
906 /// Specific Enriched TElementShape inline functions
907 /// ///////////////////////////////////////////////////////////////////
908
909 //===============================================================
910 /// Standard quadratic shape functions enriched by the addition
911 /// of a cubic bubble, which consists of adding a single node
912 /// at the centroid
913 //=============================================================
914 template<>
916 {
917 public:
918 //=====================================================================
919 /// Return the number of nodes required for enrichement
920 //====================================================================
922 {
923 return 1;
924 }
925
926 //=======================================================================
927 /// Return local coordinates of node j
928 //=======================================================================
929 void local_coordinate_of_node(const unsigned& j, Vector<double>& s) const
930 {
931 s.resize(2);
932
933 switch (j)
934 {
935 case 0:
936 s[0] = 1.0;
937 s[1] = 0.0;
938 break;
939
940 case 1:
941 s[0] = 0.0;
942 s[1] = 1.0;
943 break;
944
945 case 2:
946 s[0] = 0.0;
947 s[1] = 0.0;
948 break;
949
950 case 3:
951 s[0] = 0.5;
952 s[1] = 0.5;
953 break;
954
955 case 4:
956 s[0] = 0.0;
957 s[1] = 0.5;
958 break;
959
960 case 5:
961 s[0] = 0.5;
962 s[1] = 0.0;
963 break;
964
965 // Add the centroid as the enriched node
966 case 6:
967 s[0] = 1.0 / 3.0;
968 s[1] = 1.0 / 3.0;
969 break;
970
971 default:
972 std::ostringstream error_message;
973 error_message
974 << "Element only has seven nodes; called with node number " << j
975 << std::endl;
976
977 throw OomphLibError(error_message.str(),
978 OOMPH_CURRENT_FUNCTION,
979 OOMPH_EXCEPTION_LOCATION);
980 }
981 }
982
983
984 //=======================================================================
985 /// Shape function for specific TBubbleEnrichedElement<2,3>
986 //=======================================================================
987 void shape(const Vector<double>& s, Shape& psi) const
988 {
989 // Reconstruct the third area coordinate
990 const double s_2 = 1.0 - s[0] - s[1];
991
992 // Calculate the enrichment function
993 const double cubic_bubble = s[0] * s[1] * s_2;
994 // The appropriate amount of the cubic bubble function is
995 // added/subtracted to each original quadratic shape function to ensure
996 // that it is zero at the centroid (1/3,1/3).
997
998 // note that s[2] needs replacing by s_2 everywhere since only
999 // two independent variables s[0],s[1] and s_2 is expressed in terms of
1000 // those later.
1001 psi[0] = 2.0 * s[0] * (s[0] - 0.5) + 3.0 * cubic_bubble;
1002 psi[1] = 2.0 * s[1] * (s[1] - 0.5) + 3.0 * cubic_bubble;
1003 psi[2] = 2.0 * s_2 * (s_2 - 0.5) + 3.0 * cubic_bubble;
1004 psi[3] = 4.0 * s[0] * s[1] - 12.0 * cubic_bubble;
1005 psi[4] = 4.0 * s[1] * s_2 - 12.0 * cubic_bubble;
1006 psi[5] = 4.0 * s_2 * s[0] - 12.0 * cubic_bubble;
1007 // The bubble function scaled to have magnitude one at (1/3,1/3)
1008 psi[6] = 27.0 * cubic_bubble;
1009 }
1010
1011
1012 //=======================================================================
1013 /// Derivatives of shape functions for specific TBubbleElement<2,3>
1014 //=======================================================================
1015 void dshape_local(const Vector<double>& s, Shape& psi, DShape& dpsids) const
1016 {
1017 // ALH: Don't know why object qualifier is needed
1018 this->shape(s, psi);
1019
1020 // Calculate derivatives of bubble functions
1021 const double d_bubble_ds0 = s[1] * (1.0 - s[1] - 2.0 * s[0]);
1022 const double d_bubble_ds1 = s[0] * (1.0 - s[0] - 2.0 * s[1]);
1023
1024 // Add the appropriate derivatives to the shape functions
1025 dpsids(0, 0) = 4.0 * s[0] - 1.0 + 3.0 * d_bubble_ds0;
1026 dpsids(0, 1) = 0.0 + 3.0 * d_bubble_ds1;
1027 dpsids(1, 0) = 0.0 + 3.0 * d_bubble_ds0;
1028 dpsids(1, 1) = 4.0 * s[1] - 1.0 + 3.0 * d_bubble_ds1;
1029 dpsids(2, 0) = 2.0 * (2.0 * s[0] - 1.5 + 2.0 * s[1]) + 3.0 * d_bubble_ds0;
1030 dpsids(2, 1) = 2.0 * (2.0 * s[0] - 1.5 + 2.0 * s[1]) + 3.0 * d_bubble_ds1;
1031 dpsids(3, 0) = 4.0 * s[1] - 12.0 * d_bubble_ds0;
1032 dpsids(3, 1) = 4.0 * s[0] - 12.0 * d_bubble_ds1;
1033 dpsids(4, 0) = -4.0 * s[1] - 12.0 * d_bubble_ds0;
1034 dpsids(4, 1) = 4.0 * (1.0 - s[0] - 2.0 * s[1]) - 12.0 * d_bubble_ds1;
1035 dpsids(5, 0) = 4.0 * (1.0 - 2.0 * s[0] - s[1]) - 12.0 * d_bubble_ds0;
1036 dpsids(5, 1) = -4.0 * s[0] - 12.0 * d_bubble_ds1;
1037 dpsids(6, 0) = 27.0 * d_bubble_ds0;
1038 dpsids(6, 1) = 27.0 * d_bubble_ds1;
1039 }
1040
1041
1042 //=======================================================================
1043 /// Second derivatives of shape functions for specific
1044 /// TBubbleElement<2,3>:
1045 /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
1046 /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
1047 /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
1048 //=======================================================================
1050 Shape& psi,
1051 DShape& dpsids,
1052 DShape& d2psids) const
1053 {
1054 // ALH: Don't know why object qualifier is needed
1055 this->dshape_local(s, psi, dpsids);
1056
1057 // Calculate derivatives of bubble functions
1058 const double d2_bubble_ds0 = -2.0 * s[1];
1059 const double d2_bubble_ds1 = -2.0 * s[0];
1060 const double d2_bubble_ds2 = 1.0 - 2.0 * s[0] - 2.0 * s[1];
1061
1062 d2psids(0, 0) = 4.0 + 3.0 * d2_bubble_ds0;
1063 d2psids(0, 1) = 0.0 + 3.0 * d2_bubble_ds1;
1064 d2psids(0, 2) = 0.0 + 3.0 * d2_bubble_ds2;
1065
1066 d2psids(1, 0) = 0.0 + 3.0 * d2_bubble_ds0;
1067 d2psids(1, 1) = 4.0 + 3.0 * d2_bubble_ds1;
1068 d2psids(1, 2) = 0.0 + 3.0 * d2_bubble_ds2;
1069
1070 d2psids(2, 0) = 4.0 + 3.0 * d2_bubble_ds0;
1071 d2psids(2, 1) = 4.0 + 3.0 * d2_bubble_ds1;
1072 d2psids(2, 2) = 4.0 + 3.0 * d2_bubble_ds2;
1073
1074 d2psids(3, 0) = 0.0 - 12.0 * d2_bubble_ds0;
1075 d2psids(3, 1) = 0.0 - 12.0 * d2_bubble_ds1;
1076 d2psids(3, 2) = 4.0 - 12.0 * d2_bubble_ds2;
1077
1078 d2psids(4, 0) = 0.0 - 12.0 * d2_bubble_ds0;
1079 d2psids(4, 1) = -8.0 - 12.0 * d2_bubble_ds1;
1080 d2psids(4, 2) = -4.0 - 12.0 * d2_bubble_ds2;
1081
1082 d2psids(5, 0) = -8.0 - 12.0 * d2_bubble_ds0;
1083 d2psids(5, 1) = 0.0 - 12.0 * d2_bubble_ds1;
1084 d2psids(5, 2) = -4.0 - 12.0 * d2_bubble_ds2;
1085
1086 d2psids(6, 0) = 27.0 * d2_bubble_ds0;
1087 d2psids(6, 1) = 27.0 * d2_bubble_ds1;
1088 d2psids(6, 2) = 27.0 * d2_bubble_ds2;
1089 }
1090 };
1091
1092 /// ///////////////////////////////////////////////////////////////////
1093 /// ///////////////////////////////////////////////////////////////////
1094 /// ///////////////////////////////////////////////////////////////////
1095
1096 //========================================================================
1097 /// Empty base class for Telements (created so that
1098 /// we can use dynamic_cast<>() to figure out if a an element
1099 /// is a Telement (from a purely geometric point of view).
1100 //========================================================================
1102 {
1103 public:
1104 /// Empty default constructor
1106
1107 /// Broken copy constructor
1109
1110 /// Broken assignment operator
1111 // Commented out broken assignment operator because this can lead to a
1112 // conflict warning when used in the virtual inheritence hierarchy.
1113 // Essentially the compiler doesn't realise that two separate
1114 // implementations of the broken function are the same and so, quite
1115 // rightly, it shouts.
1116 /*void operator=(const TElementGeometricBase&) = delete;*/
1117 };
1118
1119
1120 /// ///////////////////////////////////////////////////////////////////
1121 /// ///////////////////////////////////////////////////////////////////
1122 /// ///////////////////////////////////////////////////////////////////
1123
1124 //========================================================================
1125 /// Empty base class for Telements (created so that
1126 /// we can use dynamic_cast<>() to figure out if a an element
1127 /// is a Telement).
1128 //========================================================================
1130 {
1131 public:
1132 /// Empty default constructor
1134
1135 /// Broken copy constructor
1136 TElementBase(const TElementBase&) = delete;
1137
1138 /// Broken assignment operator
1139 /*void operator=(const TElementBase&) = delete;*/
1140
1141 /// It's a T element!
1143 {
1144 return ElementGeometry::T;
1145 }
1146
1147 /// Check whether the local coordinates are valid or not
1149 {
1150 // Check coordinates
1151 unsigned ncoord = dim();
1152 double sum = 0.0;
1153 for (unsigned i = 0; i < ncoord; i++)
1154 {
1155 // Each local coordinate must be positive
1156 if (s[i] < 0.0)
1157 {
1158 return false;
1159 }
1160 sum += s[i];
1161 }
1162
1163 // Sum must be less than 1
1164 if (sum <= 1.0)
1165 {
1166 return true;
1167 }
1168
1169 // We're outside...
1170 return false;
1171 }
1172
1173 /// Adjust local coordinates so that they're located inside
1174 /// the element
1176 {
1177 // Check coordinates
1178 unsigned ncoord = dim();
1179 double sum = 0.0;
1180 for (unsigned i = 0; i < ncoord; i++)
1181 {
1182 // Each coordinate must be positive individually
1183 if (s[i] < 0.0) s[i] = 0.0;
1184 sum += s[i];
1185 }
1186
1187 // Sum must be less than 1
1188 double excess = sum - 1.0;
1189 if (excess > 0.0)
1190 {
1191 // Subtract excess equally from all coordinates
1192 double sub = excess / double(ncoord);
1193 for (unsigned i = 0; i < ncoord; i++)
1194 {
1195 s[i] -= sub;
1196 }
1197 }
1198 }
1199 };
1200
1201 //=======================================================================
1202 /// General TElement class
1203 ///
1204 /// Empty, just establishes the template parameters
1205 //=======================================================================
1206 template<unsigned DIM, unsigned NNODE_1D>
1208 {
1209 };
1210
1211
1212 //=======================================================================
1213 /// General TElement class specialised to one spatial dimensions
1214 /// Ordering of nodes is 0 at local coordinate s[0] = 0, 1 at local
1215 /// coordinate s[0] = 1 and then filling in the intermediate values
1216 /// from s[0]=0 to 1.
1217 //=======================================================================
1218 template<unsigned NNODE_1D>
1219 class TElement<1, NNODE_1D> : public virtual TElementBase,
1220 public TElementShape<1, NNODE_1D>
1221 {
1222 private:
1223 /// Default integration rule: Gaussian integration of same 'order' as
1224 /// the element
1225 // This is sort of optimal, because it means that the integration is exact
1226 // for the shape functions. Can overwrite this in specific element
1227 // defintion.
1229
1230 public:
1231 /// Constructor
1233 {
1234 // Number of nodes
1235 switch (NNODE_1D)
1236 {
1237 case 2:
1238 case 3:
1239 case 4:
1240 break;
1241
1242 default:
1243 std::string error_message =
1244 "One-dimensional TElements are currently only implemented for\n";
1245 error_message += "three and six nodes, i.e. NNODE_1D=2 , 3 , 4\n";
1246
1247 throw OomphLibError(
1248 error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1249 }
1250
1251 // Set the number of nodes
1252 unsigned n_node = NNODE_1D;
1253 this->set_n_node(n_node);
1254
1255 // Set the elemental and nodal dimension
1256 set_dimension(1);
1257
1258 // Assign default (full) spatial integration scheme
1259 set_integration_scheme(&Default_integration_scheme);
1260 }
1261
1262
1263 /// Broken copy constructor
1264 TElement(const TElement&) = delete;
1265
1266 /// Broken assignment operator
1267 /*void operator=(const TElement&) = delete;*/
1268
1269
1270 /// Destructor
1272
1273 /// Number of nodes along each element edge
1274 unsigned nnode_1d() const
1275 {
1276 return NNODE_1D;
1277 }
1278
1279
1280 /// Number of vertex nodes in the element: One more
1281 /// than spatial dimension
1282 unsigned nvertex_node() const
1283 {
1284 return 2;
1285 }
1286
1287 /// Pointer to the j-th vertex node in the element
1288 Node* vertex_node_pt(const unsigned& j) const
1289 {
1290 switch (j)
1291 {
1292 case 0:
1293
1294 return node_pt(0);
1295 break;
1296
1297 case 1:
1298
1299 return node_pt(NNODE_1D - 1);
1300 break;
1301
1302 default:
1303
1304 std::ostringstream error_message;
1305 error_message
1306 << "Element only has two vertex nodes; called with node number "
1307 << j << std::endl;
1308 throw OomphLibError(error_message.str(),
1309 OOMPH_CURRENT_FUNCTION,
1310 OOMPH_EXCEPTION_LOCATION);
1311 }
1312 }
1313
1314 /// Calculate the geometric shape functions at local coordinate s
1315 inline void shape(const Vector<double>& s, Shape& psi) const
1316 {
1318 }
1319
1320 /// Compute the geometric shape functions and
1321 /// derivatives w.r.t. local coordinates at local coordinate s
1322 inline void dshape_local(const Vector<double>& s,
1323 Shape& psi,
1324 DShape& dpsids) const
1325 {
1327 }
1328
1329 /// Compute the geometric shape functions, derivatives and
1330 /// second derivatives w.r.t local coordinates at local coordinate s
1331 /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
1332 /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
1333 /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
1334 inline void d2shape_local(const Vector<double>& s,
1335 Shape& psi,
1336 DShape& dpsids,
1337 DShape& d2psids) const
1338 {
1339 TElementShape<1, NNODE_1D>::d2shape_local(s, psi, dpsids, d2psids);
1340 }
1341
1342 /// Overload the template-free interface for the calculation of
1343 /// inverse jacobian matrix. This is a one dimensional element, so use
1344 /// the 1D version.
1346 DenseMatrix<double>& inverse_jacobian) const
1347 {
1348 return FiniteElement::invert_jacobian<1>(jacobian, inverse_jacobian);
1349 }
1350
1351 /// Min. value of local coordinate
1352 double s_min() const
1353 {
1354 return 0.0;
1355 }
1356
1357 /// Max. value of local coordinate
1358 double s_max() const
1359 {
1360 return 1.0;
1361 }
1362
1363 /// Return local coordinates of node j
1364 inline void local_coordinate_of_node(const unsigned& j,
1365 Vector<double>& s) const
1366 {
1368 }
1369
1370 /// Return the number of actual plot points for paraview
1371 /// plot with parameter nplot.
1372 unsigned nplot_points_paraview(const unsigned& nplot) const
1373 {
1374 return nplot;
1375 }
1376
1377 /// Return the number of local sub-elements for paraview plot with
1378 /// parameter nplot.
1379 unsigned nsub_elements_paraview(const unsigned& nplot) const
1380 {
1381 return (nplot - 1);
1382 }
1383
1384 /// Fill in the offset information for paraview plot.
1385 /// Needs to be implemented for each new geometric element type; see
1386 /// http://www.vtk.org/VTK/img/file-formats.pdf
1387 void write_paraview_output_offset_information(std::ofstream& file_out,
1388 const unsigned& nplot,
1389 unsigned& counter) const
1390 {
1391 // Number of local elements we want to plot over
1392 unsigned plot = nsub_elements_paraview(nplot);
1393
1394 // loops over the i-th local element in parent element
1395 for (unsigned i = 0; i < plot; i++)
1396 {
1397 file_out << i + counter << " " << i + 1 + counter << std::endl;
1398 }
1399 counter += nplot_points_paraview(nplot);
1400 }
1401
1402 /// Return the paraview element type.
1403 /// Needs to be implemented for each new geometric element type; see
1404 /// http://www.vtk.org/VTK/img/file-formats.pdf
1405 void write_paraview_type(std::ofstream& file_out,
1406 const unsigned& nplot) const
1407 {
1408 unsigned local_loop = nsub_elements_paraview(nplot);
1409 for (unsigned i = 0; i < local_loop; i++)
1410 {
1411 file_out << "3" << std::endl;
1412 }
1413 }
1414
1415 /// Return the offsets for the paraview sub-elements. Needs
1416 /// to be implemented for each new geometric element type; see
1417 /// http://www.vtk.org/VTK/img/file-formats.pdf
1418 void write_paraview_offsets(std::ofstream& file_out,
1419 const unsigned& nplot,
1420 unsigned& offset_sum) const
1421 {
1422 // Loop over all local elements and add its offset to the overall
1423 // offset_sum
1424 unsigned local_loop = nsub_elements_paraview(nplot);
1425 for (unsigned i = 0; i < local_loop; i++)
1426 {
1427 offset_sum += 2;
1428 file_out << offset_sum << std::endl;
1429 }
1430 }
1431
1432 /// Output
1433 void output(std::ostream& output);
1434
1435 /// Output at specified number of plot points
1436 void output(std::ostream& outfile, const unsigned& nplot);
1437
1438 /// C-style output
1439 void output(FILE* file_pt);
1440
1441 /// C_style output at n_plot points
1442 void output(FILE* file_pt, const unsigned& n_plot);
1443
1444 /// Get vector of local coordinates of plot point i (when plotting
1445 /// nplot points in each "coordinate direction").
1447 const unsigned& i,
1448 const unsigned& nplot,
1450 const bool& use_equally_spaced_interior_sample_points = false) const
1451 {
1452 if (nplot > 1)
1453 {
1454 s[0] = double(i) / double(nplot - 1);
1455
1456 if (use_equally_spaced_interior_sample_points)
1457 {
1458 double range = 1.0;
1459 double dx_new = range / double(nplot);
1460 double range_new = double(nplot - 1) * dx_new;
1461 s[0] = 0.5 * dx_new + range_new * s[0] / range;
1462 }
1463 }
1464 else
1465 {
1466 s[0] = 0.5;
1467 }
1468 }
1469
1470 /// Return string for tecplot zone header (when plotting
1471 /// nplot points in each "coordinate direction)
1472 std::string tecplot_zone_string(const unsigned& nplot) const
1473 {
1474 std::ostringstream header;
1475 header << "ZONE I=" << nplot << "\n";
1476 return header.str();
1477 }
1478
1479 /// Return total number of plot points (when plotting
1480 /// nplot points in each "coordinate direction)
1481 unsigned nplot_points(const unsigned& nplot) const
1482 {
1483 return nplot;
1484 }
1485
1486 /// Build the lower-dimensional FaceElement (an element of type
1487 /// PointElement). The face index takes two values
1488 /// corresponding to the two possible faces:
1489 /// -1 (Left) s[0] = -1.0
1490 /// +1 (Right) s[0] = 1.0
1491 void build_face_element(const int& face_index,
1492 FaceElement* face_element_pt);
1493 };
1494
1495
1496 //=======================================================================
1497 /// General TElement class specialised to two spatial dimensions
1498 /// Ordering of nodes as in Zienkiwizc sketches: vertex nodes
1499 /// 0 - 1 - 2 anticlockwise. Midside nodes filled in progressing
1500 /// along the consecutive edges. Central node(s) come(s) last.
1501 //=======================================================================
1502 template<unsigned NNODE_1D>
1503 class TElement<2, NNODE_1D> : public virtual TElementBase,
1504 public TElementShape<2, NNODE_1D>
1505 {
1506 private:
1507 /// Nodal translation scheme for use when generating face elements
1508 static const unsigned Node_on_face[3][NNODE_1D];
1509
1510 /// Default integration rule: Gaussian integration of same 'order' as
1511 /// the element
1512 // This is sort of optimal, because it means that the integration is exact
1513 // for the shape functions. Can overwrite this in specific element
1514 // defintion.
1516
1517
1518 public:
1519 /// Constructor
1521 {
1522 // Number of nodes
1523 switch (NNODE_1D)
1524 {
1525 case 2:
1526 case 3:
1527 case 4:
1528 break;
1529
1530 default:
1531 std::string error_message =
1532 "Triangles are currently only implemented for\n";
1533 error_message += "three and six nodes, i.e. NNODE_1D=2 , 3 , 4\n";
1534
1535 throw OomphLibError(
1536 error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1537 }
1538
1539 // Set the number of nodes
1540 unsigned n_node = (NNODE_1D * (NNODE_1D + 1)) / 2;
1541 this->set_n_node(n_node);
1542
1543 // Set the elemental and nodal dimension
1544 set_dimension(2);
1545
1546 // Assign default (full) spatial integration scheme
1547 set_integration_scheme(&Default_integration_scheme);
1548 }
1549
1550 /// Alternative constructor
1551 TElement(const bool& allow_high_order)
1552 {
1553 // Check if we are overriding the restriction on NNODE_1D
1554 if (!allow_high_order)
1555 {
1556 // Call the default constructor
1558 }
1559 else
1560 {
1561 // Set the number of nodes
1562 unsigned n_node = (NNODE_1D * (NNODE_1D + 1)) / 2;
1563 this->set_n_node(n_node);
1564
1565 // Set the elemental and nodal dimension
1566 set_dimension(2);
1567
1568 // Assign default (full) spatial integration scheme
1569 set_integration_scheme(&Default_integration_scheme);
1570 }
1571 }
1572
1573
1574 /// Broken copy constructor
1575 TElement(const TElement&) = delete;
1576
1577 /// Broken assignment operator
1578 /*void operator=(const TElement&) = delete;*/
1579
1580
1581 /// Destructor
1583
1584 /// Number of nodes along each element edge
1585 unsigned nnode_1d() const
1586 {
1587 return NNODE_1D;
1588 }
1589
1590 /// Number of vertex nodes in the element: One more
1591 /// than spatial dimension
1592 unsigned nvertex_node() const
1593 {
1594 return 3;
1595 }
1596
1597 /// Public access function for Node_on_face.
1598 unsigned get_bulk_node_number(const int& face_index,
1599 const unsigned& i) const
1600 {
1601 return Node_on_face[face_index][i];
1602 }
1603
1604 /// Pointer to the j-th vertex node in the element
1605 Node* vertex_node_pt(const unsigned& j) const
1606 {
1607 // Vertex nodes come first:
1608#ifdef PARANOID
1609 if (j > 2)
1610 {
1611 std::ostringstream error_message;
1612 error_message
1613 << "Element only has three vertex nodes; called with node number "
1614 << j << std::endl;
1615 throw OomphLibError(error_message.str(),
1616 OOMPH_CURRENT_FUNCTION,
1617 OOMPH_EXCEPTION_LOCATION);
1618 }
1619#endif
1620 return node_pt(j);
1621 }
1622
1623 /// Calculate the geometric shape functions at local coordinate s
1624 inline void shape(const Vector<double>& s, Shape& psi) const
1625 {
1627 }
1628
1629 /// Compute the geometric shape functions and
1630 /// derivatives w.r.t. local coordinates at local coordinate s
1631 inline void dshape_local(const Vector<double>& s,
1632 Shape& psi,
1633 DShape& dpsids) const
1634 {
1636 }
1637
1638 /// Compute the geometric shape functions, derivatives and
1639 /// second derivatives w.r.t local coordinates at local coordinate s
1640 /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
1641 /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
1642 /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
1643 inline void d2shape_local(const Vector<double>& s,
1644 Shape& psi,
1645 DShape& dpsids,
1646 DShape& d2psids) const
1647 {
1648 TElementShape<2, NNODE_1D>::d2shape_local(s, psi, dpsids, d2psids);
1649 }
1650
1651 /// Overload the template-free interface for the calculation of
1652 /// inverse jacobian matrix. This is a two dimensional element, so use
1653 /// the 2D version.
1655 DenseMatrix<double>& inverse_jacobian) const
1656 {
1657 return FiniteElement::invert_jacobian<2>(jacobian, inverse_jacobian);
1658 }
1659
1660 /// Min. value of local coordinate
1661 double s_min() const
1662 {
1663 return 0.0;
1664 }
1665
1666 /// Max. value of local coordinate
1667 double s_max() const
1668 {
1669 return 1.0;
1670 }
1671
1672 /// Return local coordinates of node j
1673 inline void local_coordinate_of_node(const unsigned& j,
1674 Vector<double>& s) const
1675 {
1677 }
1678
1679 /// Return the number of actual plot points for paraview
1680 /// plot with parameter nplot.
1681 unsigned nplot_points_paraview(const unsigned& nplot) const
1682 {
1683 unsigned node_sum = 0;
1684 for (unsigned i = 1; i <= nplot; i++)
1685 {
1686 node_sum += i;
1687 }
1688 return node_sum;
1689 }
1690
1691 /// Return the number of local sub-elements for paraview plot with
1692 /// parameter nplot.
1693 unsigned nsub_elements_paraview(const unsigned& nplot) const
1694 {
1695 unsigned local_sum = 0;
1696 for (unsigned i = 1; i < nplot; i++)
1697 {
1698 local_sum += 2 * (nplot - i - 1) + 1;
1699 }
1700 return local_sum;
1701 }
1702
1703 /// Fill in the offset information for paraview plot.
1704 /// Needs to be implemented for each new geometric element type; see
1705 /// http://www.vtk.org/VTK/img/file-formats.pdf
1706 void write_paraview_output_offset_information(std::ofstream& file_out,
1707 const unsigned& nplot,
1708 unsigned& counter) const
1709 {
1710 // Outputs list of connectivity of Paraview elements,
1711 // whilst remembering the overall ordering
1712
1713 unsigned node_count = 0;
1714 for (unsigned i = 0; i < nplot - 1; i++)
1715 {
1716 for (unsigned j = 0; j < nplot - i - 1; j++)
1717 {
1718 file_out << j + node_count + counter << " "
1719 << j + node_count + 1 + counter << " "
1720 << j + nplot + node_count - i + counter << std::endl;
1721
1722 if (j < nplot - i - 2)
1723 {
1724 file_out << j + node_count + 1 + counter << " "
1725 << j + nplot + node_count - i + 1 + counter << " "
1726 << j + nplot + node_count - i + counter << std::endl;
1727 }
1728 }
1729 node_count += (nplot - i);
1730 }
1731 counter += nplot_points_paraview(nplot);
1732 }
1733
1734 /// Return the paraview element type.
1735 /// Needs to be implemented for each new geometric element type; see
1736 /// http://www.vtk.org/VTK/img/file-formats.pdf
1737 void write_paraview_type(std::ofstream& file_out,
1738 const unsigned& nplot) const
1739 {
1740 unsigned local_loop = nsub_elements_paraview(nplot);
1741
1742 // Loop over all the local elements and print its paraview type
1743 for (unsigned i = 0; i < local_loop; i++)
1744 {
1745 file_out << "5" << std::endl;
1746 }
1747 }
1748
1749 /// Return the offsets for the paraview sub-elements. Needs
1750 /// to be implemented for each new geometric element type; see
1751 /// http://www.vtk.org/VTK/img/file-formats.pdf
1752 void write_paraview_offsets(std::ofstream& file_out,
1753 const unsigned& nplot,
1754 unsigned& offset_sum) const
1755 {
1756 unsigned local_loop = nsub_elements_paraview(nplot);
1757
1758 // Loop over all local elements and add its offset to the overall
1759 // offset_sum
1760 for (unsigned i = 0; i < local_loop; i++)
1761 {
1762 offset_sum += 3;
1763 file_out << offset_sum << std::endl;
1764 }
1765 }
1766
1767 /// Output
1768 void output(std::ostream& output);
1769
1770 /// Output at specified number of plot points
1771 void output(std::ostream& outfile, const unsigned& nplot);
1772
1773 /// C-style output
1774 void output(FILE* file_pt);
1775
1776 /// C_style output at n_plot points
1777 void output(FILE* file_pt, const unsigned& n_plot);
1778
1779 /// Get vector of local coordinates of plot point i (when plotting
1780 /// nplot points in each "coordinate direction").
1782 const unsigned& iplot,
1783 const unsigned& nplot,
1785 const bool& use_equally_spaced_interior_sample_points = false) const
1786 {
1787 if (nplot > 1)
1788 {
1789 unsigned np = 0, i, j;
1790 for (i = 0; i < nplot; ++i)
1791 {
1792 for (j = 0; j < nplot - i; ++j)
1793 {
1794 if (np == iplot)
1795 {
1796 s[0] = double(j) / double(nplot - 1);
1797 s[1] = double(i) / double(nplot - 1);
1798 if (use_equally_spaced_interior_sample_points)
1799 {
1800 double range = 1.0;
1801 double dx_new = range / (double(nplot) + 0.5);
1802 double range_new = double(nplot - 1) * dx_new;
1803 s[0] = 0.5 * dx_new + range_new * s[0] / range;
1804 s[1] = 0.5 * dx_new + range_new * s[1] / range;
1805 }
1806 return;
1807 }
1808 ++np;
1809 }
1810 }
1811 }
1812 else
1813 {
1814 s[0] = 1.0 / 3.0;
1815 s[1] = 1.0 / 3.0;
1816 }
1817 }
1818
1819 /// Return string for tecplot zone header (when plotting
1820 /// nplot points in each "coordinate direction)
1821 std::string tecplot_zone_string(const unsigned& nplot) const
1822 {
1823 std::ostringstream header;
1824 unsigned nel = 0;
1825 for (unsigned i = 1; i < nplot; i++)
1826 {
1827 nel += 2 * i - 1;
1828 }
1829 header << "ZONE N=" << nplot_points(nplot) << ", E=" << nel
1830 << ", F=FEPOINT, ET=TRIANGLE\n";
1831 return header.str();
1832 }
1833
1834 /// Add tecplot zone "footer" to output stream (when plotting
1835 /// nplot points in each "coordinate direction).
1836 /// Empty by default -- can be used, e.g., to add FE connectivity
1837 /// lists to elements that need it.
1838 void write_tecplot_zone_footer(std::ostream& outfile,
1839 const unsigned& nplot) const
1840 {
1841 // Output node lists for sub elements for Tecplot (node index
1842 // must start at 1)
1843 unsigned nod_count = 1;
1844 for (unsigned i = 0; i < nplot; i++)
1845 {
1846 for (unsigned j = 0; j < nplot - i; j++)
1847 {
1848 if (j < nplot - i - 1)
1849 {
1850 outfile << nod_count << " " << nod_count + 1 << " "
1851 << nod_count + nplot - i << std::endl;
1852 if (j < nplot - i - 2)
1853 {
1854 outfile << nod_count + 1 << " " << nod_count + nplot - i + 1
1855 << " " << nod_count + nplot - i << std::endl;
1856 }
1857 }
1858 ++nod_count;
1859 }
1860 }
1861 }
1862
1863 /// Add tecplot zone "footer" to C-style output. (when plotting
1864 /// nplot points in each "coordinate direction).
1865 /// Empty by default -- can be used, e.g., to add FE connectivity
1866 /// lists to elements that need it.
1867 void write_tecplot_zone_footer(FILE* file_pt, const unsigned& nplot) const
1868 {
1869 // Output node lists for sub elements for Tecplot (node index
1870 // must start at 1)
1871 unsigned nod_count = 1;
1872 for (unsigned i = 0; i < nplot; i++)
1873 {
1874 for (unsigned j = 0; j < nplot - i; j++)
1875 {
1876 if (j < nplot - i - 1)
1877 {
1878 fprintf(file_pt,
1879 "%i %i %i \n",
1880 nod_count,
1881 nod_count + 1,
1882 nod_count + nplot - i);
1883 if (j < nplot - i - 2)
1884 {
1885 fprintf(file_pt,
1886 "%i %i %i \n",
1887 nod_count + 1,
1888 nod_count + nplot - i + 1,
1889 nod_count + nplot - i);
1890 }
1891 }
1892 ++nod_count;
1893 }
1894 }
1895 }
1896
1897 /// Return total number of plot points (when plotting
1898 /// nplot points in each "coordinate direction)
1899 unsigned nplot_points(const unsigned& nplot) const
1900 {
1901 unsigned np = 0;
1902 for (unsigned i = 1; i <= nplot; i++)
1903 {
1904 np += i;
1905 }
1906 return np;
1907 }
1908
1909
1910 /// Build the lower-dimensional FaceElement (an element of type
1911 /// TElement<1,NNODE_1D>). The face index takes three possible values:
1912 /// 0 (Left) s[0] = 0.0
1913 /// 1 (Bottom) s[1] = 0.0
1914 /// 2 (Sloping face) s[0] = 1.0 - s[1]
1915 void build_face_element(const int& face_index,
1916 FaceElement* face_element_pt);
1917 };
1918
1919
1920 /// ////////////////////////////////////////////////////////////////////
1921 /// ////////////////////////////////////////////////////////////////////
1922 /// ////////////////////////////////////////////////////////////////////
1923
1924
1925 //=======================================================================
1926 /// Return local coordinates of node j
1927 //=======================================================================
1928 template<>
1929 class TElementShape<3, 2>
1930 {
1931 public:
1932 void local_coordinate_of_node(const unsigned& j, Vector<double>& s) const
1933 {
1934 s.resize(3);
1935
1936 switch (j)
1937 {
1938 case 0:
1939 s[0] = 1.0;
1940 s[1] = 0.0;
1941 s[2] = 0.0;
1942 break;
1943
1944 case 1:
1945 s[0] = 0.0;
1946 s[1] = 1.0;
1947 s[2] = 0.0;
1948 break;
1949
1950 case 2:
1951 s[0] = 0.0;
1952 s[1] = 0.0;
1953 s[2] = 1.0;
1954 break;
1955
1956 case 3:
1957 s[0] = 0.0;
1958 s[1] = 0.0;
1959 s[2] = 0.0;
1960 break;
1961
1962 default:
1963 std::ostringstream error_message;
1964 error_message
1965 << "Element only has four nodes; called with node number " << j
1966 << std::endl;
1967
1968 throw OomphLibError(error_message.str(),
1969 OOMPH_CURRENT_FUNCTION,
1970 OOMPH_EXCEPTION_LOCATION);
1971 }
1972 }
1973
1974
1975 //=======================================================================
1976 /// Shape function for specific TElement<3,2>
1977 //=======================================================================
1978 void shape(const Vector<double>& s, Shape& psi) const
1979 {
1980 psi[0] = s[0];
1981 psi[1] = s[1];
1982 psi[2] = s[2];
1983 psi[3] = 1.0 - s[0] - s[1] - s[2];
1984 }
1985
1986
1987 //=======================================================================
1988 /// Derivatives of shape functions for specific TElement<3,2>
1989 //=======================================================================
1990 void dshape_local(const Vector<double>& s, Shape& psi, DShape& dpsids) const
1991 {
1992 // ALH: Don't know why object qualifier is needed
1993 this->shape(s, psi);
1994
1995 // Derivatives
1996 dpsids(0, 0) = 1.0;
1997 dpsids(0, 1) = 0.0;
1998 dpsids(0, 2) = 0.0;
1999
2000 dpsids(1, 0) = 0.0;
2001 dpsids(1, 1) = 1.0;
2002 dpsids(1, 2) = 0.0;
2003
2004 dpsids(2, 0) = 0.0;
2005 dpsids(2, 1) = 0.0;
2006 dpsids(2, 2) = 1.0;
2007
2008 dpsids(3, 0) = -1.0;
2009 dpsids(3, 1) = -1.0;
2010 dpsids(3, 2) = -1.0;
2011 }
2012
2013
2014 //=======================================================================
2015 /// Second derivatives of shape functions for specific TElement<3,2>:
2016 /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
2017 /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
2018 /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_2^2 \f$
2019 /// d2psids(i,3) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
2020 /// d2psids(i,4) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_2 \f$
2021 /// d2psids(i,5) = \f$ \partial^2 \psi_j / \partial s_1 \partial s_2 \f$
2022 //=======================================================================
2024 Shape& psi,
2025 DShape& dpsids,
2026 DShape& d2psids) const
2027 {
2028 // ALH: Don't know why object qualifier is needed
2029 this->dshape_local(s, psi, dpsids);
2030
2031 for (unsigned i = 0; i < 4; i++)
2032 {
2033 d2psids(i, 0) = 0.0;
2034 d2psids(i, 1) = 0.0;
2035 d2psids(i, 2) = 0.0;
2036 d2psids(i, 3) = 0.0;
2037 d2psids(i, 4) = 0.0;
2038 d2psids(i, 5) = 0.0;
2039 }
2040 }
2041 };
2042
2043
2044 //=======================================================================
2045 /// Return local coordinates of node j
2046 //=======================================================================
2047 template<>
2048 class TElementShape<3, 3>
2049 {
2050 public:
2051 void local_coordinate_of_node(const unsigned& j, Vector<double>& s) const
2052 {
2053 s.resize(3);
2054
2055 switch (j)
2056 {
2057 case 0:
2058 s[0] = 1.0;
2059 s[1] = 0.0;
2060 s[2] = 0.0;
2061 break;
2062
2063 case 1:
2064 s[0] = 0.0;
2065 s[1] = 1.0;
2066 s[2] = 0.0;
2067 break;
2068
2069 case 2:
2070 s[0] = 0.0;
2071 s[1] = 0.0;
2072 s[2] = 1.0;
2073 break;
2074
2075 case 3:
2076 s[0] = 0.0;
2077 s[1] = 0.0;
2078 s[2] = 0.0;
2079 break;
2080
2081 case 4:
2082 s[0] = 0.5;
2083 s[1] = 0.5;
2084 s[2] = 0.0;
2085 break;
2086
2087 case 5:
2088 s[0] = 0.5;
2089 s[1] = 0.0;
2090 s[2] = 0.5;
2091 break;
2092
2093 case 6:
2094 s[0] = 0.5;
2095 s[1] = 0.0;
2096 s[2] = 0.0;
2097 break;
2098
2099 case 7:
2100 s[0] = 0.0;
2101 s[1] = 0.5;
2102 s[2] = 0.5;
2103 break;
2104
2105 case 8:
2106 s[0] = 0.0;
2107 s[1] = 0.0;
2108 s[2] = 0.5;
2109 break;
2110
2111 case 9:
2112 s[0] = 0.0;
2113 s[1] = 0.5;
2114 s[2] = 0.0;
2115 break;
2116
2117 default:
2118 std::ostringstream error_message;
2119 error_message
2120 << "Element only has ten nodes; called with node number " << j
2121 << std::endl;
2122
2123 throw OomphLibError(error_message.str(),
2124 OOMPH_CURRENT_FUNCTION,
2125 OOMPH_EXCEPTION_LOCATION);
2126 }
2127 }
2128
2129
2130 //=======================================================================
2131 /// Shape function for specific TElement<3,3>
2132 //=======================================================================
2133 void shape(const Vector<double>& s, Shape& psi) const
2134 {
2135 double s3 = 1.0 - s[0] - s[1] - s[2];
2136 psi[0] = (2.0 * s[0] - 1.0) * s[0];
2137 psi[1] = (2.0 * s[1] - 1.0) * s[1];
2138 psi[2] = (2.0 * s[2] - 1.0) * s[2];
2139 psi[3] = (2.0 * s3 - 1.0) * s3;
2140 psi[4] = 4.0 * s[0] * s[1];
2141 psi[5] = 4.0 * s[0] * s[2];
2142 psi[6] = 4.0 * s[0] * s3;
2143 psi[7] = 4.0 * s[1] * s[2];
2144 psi[8] = 4.0 * s[2] * s3;
2145 psi[9] = 4.0 * s[1] * s3;
2146 }
2147
2148
2149 //=======================================================================
2150 /// Derivatives of shape functions for specific TElement<3,3>
2151 //=======================================================================
2152 void dshape_local(const Vector<double>& s, Shape& psi, DShape& dpsids) const
2153 {
2154 // ALH: Don't know why object qualifier is needed
2155 this->shape(s, psi);
2156
2157 // Derivatives
2158 double s3 = 1.0 - s[0] - s[1] - s[2];
2159
2160 dpsids(0, 0) = 4.0 * s[0] - 1.0;
2161 dpsids(0, 1) = 0.0;
2162 dpsids(0, 2) = 0.0;
2163
2164 dpsids(1, 0) = 0.0;
2165 dpsids(1, 1) = 4.0 * s[1] - 1.0;
2166 dpsids(1, 2) = 0.0;
2167
2168 dpsids(2, 0) = 0.0;
2169 dpsids(2, 1) = 0.0;
2170 dpsids(2, 2) = 4.0 * s[2] - 1.0;
2171
2172 dpsids(3, 0) = -4.0 * s3 + 1.0;
2173 dpsids(3, 1) = -4.0 * s3 + 1.0;
2174 dpsids(3, 2) = -4.0 * s3 + 1.0;
2175
2176 dpsids(4, 0) = 4.0 * s[1];
2177 dpsids(4, 1) = 4.0 * s[0];
2178 dpsids(4, 2) = 0.0;
2179
2180 dpsids(5, 0) = 4.0 * s[2];
2181 dpsids(5, 1) = 0.0;
2182 dpsids(5, 2) = 4.0 * s[0];
2183
2184 dpsids(6, 0) = 4.0 * (s3 - s[0]);
2185 dpsids(6, 1) = -4.0 * s[0];
2186 dpsids(6, 2) = -4.0 * s[0];
2187
2188 dpsids(7, 0) = 0.0;
2189 dpsids(7, 1) = 4.0 * s[2];
2190 dpsids(7, 2) = 4.0 * s[1];
2191
2192 dpsids(8, 0) = -4.0 * s[2];
2193 dpsids(8, 1) = -4.0 * s[2];
2194 dpsids(8, 2) = 4.0 * (s3 - s[2]);
2195
2196 dpsids(9, 0) = -4.0 * s[1];
2197 dpsids(9, 1) = 4.0 * (s3 - s[1]);
2198 dpsids(9, 2) = -4.0 * s[1];
2199 }
2200
2201
2202 //=======================================================================
2203 /// Second derivatives of shape functions for specific TElement<3,3>:
2204 /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
2205 /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
2206 /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_2^2 \f$
2207 /// d2psids(i,3) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
2208 /// d2psids(i,4) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_2 \f$
2209 /// d2psids(i,5) = \f$ \partial^2 \psi_j / \partial s_1 \partial s_2 \f$
2210 //=======================================================================
2212 Shape& psi,
2213 DShape& dpsids,
2214 DShape& d2psids) const
2215 {
2216 // ALH: Don't know why object qualifier is needed
2217 this->dshape_local(s, psi, dpsids);
2218
2219 //(.,3) for mixed derivative s[0]-s[1]
2220 //(.,4) for mixed derivative s[0]-s[2]
2221 //(.,5) for mixed derivative s[1]-s[2]
2222
2223 d2psids(0, 0) = 4.0;
2224 d2psids(0, 1) = 0.0;
2225 d2psids(0, 2) = 0.0;
2226 d2psids(0, 3) = 0.0;
2227 d2psids(0, 4) = 0.0;
2228 d2psids(0, 5) = 0.0;
2229
2230
2231 d2psids(1, 0) = 0.0;
2232 d2psids(1, 1) = 4.0;
2233 d2psids(1, 2) = 0.0;
2234 d2psids(1, 3) = 0.0;
2235 d2psids(1, 4) = 0.0;
2236 d2psids(1, 5) = 0.0;
2237
2238 d2psids(2, 0) = 0.0;
2239 d2psids(2, 1) = 0.0;
2240 d2psids(2, 2) = 4.0;
2241 d2psids(2, 3) = 0.0;
2242 d2psids(2, 4) = 0.0;
2243 d2psids(2, 5) = 0.0;
2244
2245 d2psids(3, 0) = 4.0;
2246 d2psids(3, 1) = 4.0;
2247 d2psids(3, 2) = 4.0;
2248 d2psids(3, 3) = 4.0;
2249 d2psids(3, 4) = 4.0;
2250 d2psids(3, 5) = 4.0;
2251
2252 d2psids(4, 0) = 0.0;
2253 d2psids(4, 1) = 0.0;
2254 d2psids(4, 2) = 0.0;
2255 d2psids(4, 3) = 4.0;
2256 d2psids(4, 4) = 0.0;
2257 d2psids(4, 5) = 0.0;
2258
2259 d2psids(5, 0) = 0.0;
2260 d2psids(5, 1) = 0.0;
2261 d2psids(5, 2) = 0.0;
2262 d2psids(5, 3) = 0.0;
2263 d2psids(5, 4) = 4.0;
2264 d2psids(5, 5) = 0.0;
2265
2266 d2psids(6, 0) = -8.0;
2267 d2psids(6, 1) = 0.0;
2268 d2psids(6, 2) = 0.0;
2269 d2psids(6, 3) = -4.0;
2270 d2psids(6, 4) = -4.0;
2271 d2psids(6, 5) = 0.0;
2272
2273 d2psids(7, 0) = 0.0;
2274 d2psids(7, 1) = 0.0;
2275 d2psids(7, 2) = 0.0;
2276 d2psids(7, 3) = 0.0;
2277 d2psids(7, 4) = 0.0;
2278 d2psids(7, 5) = 4.0;
2279
2280 d2psids(8, 0) = 0.0;
2281 d2psids(8, 1) = 0.0;
2282 d2psids(8, 2) = -8.0;
2283 d2psids(8, 3) = 0.0;
2284 d2psids(8, 4) = -4.0;
2285 d2psids(8, 5) = -4.0;
2286
2287 d2psids(9, 0) = 0.0;
2288 d2psids(9, 1) = -8.0;
2289 d2psids(9, 2) = 0.0;
2290 d2psids(9, 3) = -4.0;
2291 d2psids(9, 4) = 0.0;
2292 d2psids(9, 5) = -4.0;
2293 }
2294 };
2295
2296 /// ///////////////////////////////////////////////////////////////////
2297 /// ///////////////////////////////////////////////////////////////////
2298 /// ///////////////////////////////////////////////////////////////////
2299
2300 //====================================================================
2301 /// Standard quadratic shape functions enriched by the addition of
2302 /// three cubic "face" bubbles and quartic "volume" bubble,
2303 /// which consists of adding a node at the centroid of
2304 /// each face and a single node at the centroid
2305 /// of the tetrahedron
2306 //=========================================================================
2307
2308 //=======================================================================
2309 /// Return local coordinates of node j
2310 //=======================================================================
2311 template<>
2313 {
2314 public:
2316 {
2317 return 5;
2318 }
2319
2320 void local_coordinate_of_node(const unsigned& j, Vector<double>& s) const
2321 {
2322 s.resize(3);
2323
2324 switch (j)
2325 {
2326 case 0:
2327 s[0] = 1.0;
2328 s[1] = 0.0;
2329 s[2] = 0.0;
2330 break;
2331
2332 case 1:
2333 s[0] = 0.0;
2334 s[1] = 1.0;
2335 s[2] = 0.0;
2336 break;
2337
2338 case 2:
2339 s[0] = 0.0;
2340 s[1] = 0.0;
2341 s[2] = 1.0;
2342 break;
2343
2344 case 3:
2345 s[0] = 0.0;
2346 s[1] = 0.0;
2347 s[2] = 0.0;
2348 break;
2349
2350 case 4:
2351 s[0] = 0.5;
2352 s[1] = 0.5;
2353 s[2] = 0.0;
2354 break;
2355
2356 case 5:
2357 s[0] = 0.5;
2358 s[1] = 0.0;
2359 s[2] = 0.5;
2360 break;
2361
2362 case 6:
2363 s[0] = 0.5;
2364 s[1] = 0.0;
2365 s[2] = 0.0;
2366 break;
2367
2368 case 7:
2369 s[0] = 0.0;
2370 s[1] = 0.5;
2371 s[2] = 0.5;
2372 break;
2373
2374 case 8:
2375 s[0] = 0.0;
2376 s[1] = 0.0;
2377 s[2] = 0.5;
2378 break;
2379
2380 case 9:
2381 s[0] = 0.0;
2382 s[1] = 0.5;
2383 s[2] = 0.0;
2384 break;
2385
2386 // Node at centroid of face spanned by nodes 0, 1, 3
2387 case 10:
2388 s[0] = 1.0 / 3.0;
2389 s[1] = 1.0 / 3.0;
2390 s[2] = 0.0;
2391 break;
2392
2393 // Node at centroid of face spanned by nodes 0, 1, 2
2394 case 11:
2395 s[0] = 1.0 / 3.0;
2396 s[1] = 1.0 / 3.0;
2397 s[2] = 1.0 / 3.0;
2398 break;
2399
2400 // Node at centroid of face spanned by nodes 0, 2, 3
2401 case 12:
2402 s[0] = 1.0 / 3.0;
2403 s[1] = 0.0;
2404 s[2] = 1.0 / 3.0;
2405 break;
2406
2407 // Node at centroid of face spannd by nodes 1, 2, 3
2408 case 13:
2409 s[0] = 0.0;
2410 s[1] = 1.0 / 3.0;
2411 s[2] = 1.0 / 3.0;
2412 break;
2413
2414 // Node at centroid of volume
2415 case 14:
2416 s[0] = 0.25;
2417 s[1] = 0.25;
2418 s[2] = 0.25;
2419 break;
2420
2421
2422 default:
2423 std::ostringstream error_message;
2424 error_message
2425 << "Element only has fifteen nodes; called with node number " << j
2426 << std::endl;
2427
2428 throw OomphLibError(error_message.str(),
2429 OOMPH_CURRENT_FUNCTION,
2430 OOMPH_EXCEPTION_LOCATION);
2431 }
2432 }
2433
2434
2435 //=======================================================================
2436 /// Shape function for specific TBubbleEnrichedElement<3,3>
2437 //=======================================================================
2438 void shape(const Vector<double>& s, Shape& psi) const
2439 {
2440 // Constructe the fourth volume coordinate
2441 const double s3 = 1.0 - s[0] - s[1] - s[2];
2442 // calculate the enrichment functions
2443 const double quartic_bubble = s[0] * s[1] * s[2] * s3;
2444 const double cubic_bubble012 = s[0] * s[1] * s[2];
2445 const double cubic_bubble013 = s[0] * s[1] * s3;
2446 const double cubic_bubble023 = s[0] * s[2] * s3;
2447 const double cubic_bubble123 = s[1] * s[2] * s3;
2448
2449 // The appropriate "amount" of cubic and quartic bubble functions are
2450 // added/subtracted
2451 // to each original quadratic shape function to ensure that the new
2452 // shape function is zero at the centroid (0.25,0.25,0.25)
2453 // and at the face centroids
2454 psi[0] = (2.0 * s[0] - 1.0) * s[0] +
2455 3.0 * (cubic_bubble012 + cubic_bubble013 + cubic_bubble023) -
2456 4.0 * quartic_bubble;
2457 psi[1] = (2.0 * s[1] - 1.0) * s[1] +
2458 3.0 * (cubic_bubble012 + cubic_bubble013 + cubic_bubble123) -
2459 4.0 * quartic_bubble;
2460 psi[2] = (2.0 * s[2] - 1.0) * s[2] +
2461 3.0 * (cubic_bubble012 + cubic_bubble023 + cubic_bubble123) -
2462 4.0 * quartic_bubble;
2463 psi[3] = (2.0 * s3 - 1.0) * s3 +
2464 3.0 * (cubic_bubble013 + cubic_bubble023 + cubic_bubble123) -
2465 4.0 * quartic_bubble;
2466 psi[4] = 4.0 * s[0] * s[1] - 12.0 * (cubic_bubble012 + cubic_bubble013) +
2467 32.0 * quartic_bubble;
2468 psi[5] = 4.0 * s[0] * s[2] - 12.0 * (cubic_bubble012 + cubic_bubble023) +
2469 32.0 * quartic_bubble;
2470 psi[6] = 4.0 * s[0] * s3 - 12.0 * (cubic_bubble013 + cubic_bubble023) +
2471 32.0 * quartic_bubble;
2472 psi[7] = 4.0 * s[1] * s[2] - 12.0 * (cubic_bubble012 + cubic_bubble123) +
2473 32.0 * quartic_bubble;
2474 psi[8] = 4.0 * s[2] * s3 - 12.0 * (cubic_bubble023 + cubic_bubble123) +
2475 32.0 * quartic_bubble;
2476 psi[9] = 4.0 * s[1] * s3 - 12.0 * (cubic_bubble013 + cubic_bubble123) +
2477 32.0 * quartic_bubble;
2478 // Add the bubble function on the face spanned by 0 1 3
2479 psi[10] = 27.0 * cubic_bubble013 - 108.0 * quartic_bubble;
2480 // Add the bubble function on the face spanned by 0 1 2
2481 psi[11] = 27.0 * cubic_bubble012 - 108.0 * quartic_bubble;
2482 // Add the bubble function on the face spanned by 0 2 3
2483 psi[12] = 27.0 * cubic_bubble023 - 108.0 * quartic_bubble;
2484 // Add the bubble function on the face spanned by 1 2 3
2485 psi[13] = 27.0 * cubic_bubble123 - 108.0 * quartic_bubble;
2486 // Add the volume bubble function, scaled to have value one
2487 psi[14] = 256.0 * quartic_bubble;
2488 }
2489
2490
2491 //=======================================================================
2492 /// Derivatives of shape functions for specific TElement<3,3>
2493 //=======================================================================
2494 void dshape_local(const Vector<double>& s, Shape& psi, DShape& dpsids) const
2495 {
2496 // ALH: Don't know why object qualifier is needed
2497 this->shape(s, psi);
2498
2499 // Define s3 the fourth volume coordinate
2500 const double s3 = 1.0 - s[0] - s[1] - s[2];
2501
2502 // Calculate derivatives of the bubble function
2503 const double d_quartic_bubble_ds0 =
2504 s[1] * s[2] * (1.0 - s[1] - s[2] - 2.0 * s[0]);
2505 const double d_quartic_bubble_ds1 =
2506 s[0] * s[2] * (1.0 - s[0] - s[2] - 2.0 * s[1]);
2507 const double d_quartic_bubble_ds2 =
2508 s[0] * s[1] * (1.0 - s[0] - s[1] - 2.0 * s[2]);
2509
2510 const double d_cubic_bubble012_ds0 = s[1] * s[2];
2511 const double d_cubic_bubble012_ds1 = s[0] * s[2];
2512 const double d_cubic_bubble012_ds2 = s[0] * s[1];
2513
2514 const double d_cubic_bubble013_ds0 = s[1] * (s3 - s[0]);
2515 const double d_cubic_bubble013_ds1 = s[0] * (s3 - s[1]);
2516 const double d_cubic_bubble013_ds2 = -s[0] * s[1];
2517
2518 const double d_cubic_bubble023_ds0 = s[2] * (s3 - s[0]);
2519 const double d_cubic_bubble023_ds1 = -s[0] * s[2];
2520 const double d_cubic_bubble023_ds2 = s[0] * (s3 - s[2]);
2521
2522 const double d_cubic_bubble123_ds0 = -s[1] * s[2];
2523 const double d_cubic_bubble123_ds1 = s[2] * (s3 - s[1]);
2524 const double d_cubic_bubble123_ds2 = s[1] * (s3 - s[2]);
2525
2526
2527 // Add the appropriate dervatives of the bubble function to the
2528 // shape function derivatives
2529 dpsids(0, 0) = 4.0 * s[0] - 1.0 +
2530 3.0 * (d_cubic_bubble012_ds0 + d_cubic_bubble013_ds0 +
2531 d_cubic_bubble023_ds0) -
2532 4.0 * d_quartic_bubble_ds0;
2533 dpsids(0, 1) = 0.0 +
2534 3.0 * (d_cubic_bubble012_ds1 + d_cubic_bubble013_ds1 +
2535 d_cubic_bubble023_ds1) -
2536 4.0 * d_quartic_bubble_ds1;
2537 dpsids(0, 2) = 0.0 +
2538 3.0 * (d_cubic_bubble012_ds2 + d_cubic_bubble013_ds2 +
2539 d_cubic_bubble023_ds2) -
2540 4.0 * d_quartic_bubble_ds2;
2541
2542 dpsids(1, 0) = 0.0 +
2543 3.0 * (d_cubic_bubble012_ds0 + d_cubic_bubble013_ds0 +
2544 d_cubic_bubble123_ds0) -
2545 4.0 * d_quartic_bubble_ds0;
2546 dpsids(1, 1) = 4.0 * s[1] - 1.0 +
2547 3.0 * (d_cubic_bubble012_ds1 + d_cubic_bubble013_ds1 +
2548 d_cubic_bubble123_ds1) -
2549 4.0 * d_quartic_bubble_ds1;
2550 dpsids(1, 2) = 0.0 +
2551 3.0 * (d_cubic_bubble012_ds2 + d_cubic_bubble013_ds2 +
2552 d_cubic_bubble123_ds2) -
2553 4.0 * d_quartic_bubble_ds2;
2554
2555 dpsids(2, 0) = 0.0 +
2556 3.0 * (d_cubic_bubble012_ds0 + d_cubic_bubble023_ds0 +
2557 d_cubic_bubble123_ds0) -
2558 4.0 * d_quartic_bubble_ds0;
2559 dpsids(2, 1) = 0.0 +
2560 3.0 * (d_cubic_bubble012_ds1 + d_cubic_bubble023_ds1 +
2561 d_cubic_bubble123_ds1) -
2562 4.0 * d_quartic_bubble_ds1;
2563 dpsids(2, 2) = 4.0 * s[2] - 1.0 +
2564 3.0 * (d_cubic_bubble012_ds2 + d_cubic_bubble023_ds2 +
2565 d_cubic_bubble123_ds2) -
2566 4.0 * d_quartic_bubble_ds2;
2567
2568 dpsids(3, 0) = -4.0 * s3 + 1.0 +
2569 3.0 * (d_cubic_bubble013_ds0 + d_cubic_bubble023_ds0 +
2570 d_cubic_bubble123_ds0) -
2571 4.0 * d_quartic_bubble_ds0;
2572 dpsids(3, 1) = -4.0 * s3 + 1.0 +
2573 3.0 * (d_cubic_bubble013_ds1 + d_cubic_bubble023_ds1 +
2574 d_cubic_bubble123_ds1) -
2575 4.0 * d_quartic_bubble_ds1;
2576 dpsids(3, 2) = -4.0 * s3 + 1.0 +
2577 3.0 * (d_cubic_bubble013_ds2 + d_cubic_bubble023_ds2 +
2578 d_cubic_bubble123_ds2) -
2579 4.0 * d_quartic_bubble_ds2;
2580
2581 dpsids(4, 0) = 4.0 * s[1] -
2582 12.0 * (d_cubic_bubble012_ds0 + d_cubic_bubble013_ds0) +
2583 32.0 * d_quartic_bubble_ds0;
2584 dpsids(4, 1) = 4.0 * s[0] -
2585 12.0 * (d_cubic_bubble012_ds1 + d_cubic_bubble013_ds1) +
2586 32.0 * d_quartic_bubble_ds1;
2587 dpsids(4, 2) = 0.0 -
2588 12.0 * (d_cubic_bubble012_ds2 + d_cubic_bubble013_ds2) +
2589 32.0 * d_quartic_bubble_ds2;
2590
2591 dpsids(5, 0) = 4.0 * s[2] -
2592 12.0 * (d_cubic_bubble012_ds0 + d_cubic_bubble023_ds0) +
2593 32.0 * d_quartic_bubble_ds0;
2594 dpsids(5, 1) = 0.0 -
2595 12.0 * (d_cubic_bubble012_ds1 + d_cubic_bubble023_ds1) +
2596 32.0 * d_quartic_bubble_ds1;
2597 dpsids(5, 2) = 4.0 * s[0] -
2598 12.0 * (d_cubic_bubble012_ds2 + d_cubic_bubble023_ds2) +
2599 32.0 * d_quartic_bubble_ds2;
2600
2601 dpsids(6, 0) = 4.0 * (s3 - s[0]) -
2602 12.0 * (d_cubic_bubble013_ds0 + d_cubic_bubble023_ds0) +
2603 32.0 * d_quartic_bubble_ds0;
2604 dpsids(6, 1) = -4.0 * s[0] -
2605 12.0 * (d_cubic_bubble013_ds1 + d_cubic_bubble023_ds1) +
2606 32.0 * d_quartic_bubble_ds1;
2607 dpsids(6, 2) = -4.0 * s[0] -
2608 12.0 * (d_cubic_bubble013_ds2 + d_cubic_bubble023_ds2) +
2609 32.0 * d_quartic_bubble_ds2;
2610
2611 dpsids(7, 0) = 0.0 -
2612 12.0 * (d_cubic_bubble012_ds0 + d_cubic_bubble123_ds0) +
2613 32.0 * d_quartic_bubble_ds0;
2614 dpsids(7, 1) = 4.0 * s[2] -
2615 12.0 * (d_cubic_bubble012_ds1 + d_cubic_bubble123_ds1) +
2616 32.0 * d_quartic_bubble_ds1;
2617 dpsids(7, 2) = 4.0 * s[1] -
2618 12.0 * (d_cubic_bubble012_ds2 + d_cubic_bubble123_ds2) +
2619 32.0 * d_quartic_bubble_ds2;
2620
2621 dpsids(8, 0) = -4.0 * s[2] -
2622 12.0 * (d_cubic_bubble023_ds0 + d_cubic_bubble123_ds0) +
2623 32.0 * d_quartic_bubble_ds0;
2624 dpsids(8, 1) = -4.0 * s[2] -
2625 12.0 * (d_cubic_bubble023_ds1 + d_cubic_bubble123_ds1) +
2626 32.0 * d_quartic_bubble_ds1;
2627 dpsids(8, 2) = 4.0 * (s3 - s[2]) -
2628 12.0 * (d_cubic_bubble023_ds2 + d_cubic_bubble123_ds2) +
2629 32.0 * d_quartic_bubble_ds2;
2630
2631 dpsids(9, 0) = -4.0 * s[1] -
2632 12.0 * (d_cubic_bubble013_ds0 + d_cubic_bubble123_ds0) +
2633 32.0 * d_quartic_bubble_ds0;
2634 dpsids(9, 1) = 4.0 * (s3 - s[1]) -
2635 12.0 * (d_cubic_bubble013_ds1 + d_cubic_bubble123_ds1) +
2636 32.0 * d_quartic_bubble_ds1;
2637 dpsids(9, 2) = -4.0 * s[1] -
2638 12.0 * (d_cubic_bubble013_ds2 + d_cubic_bubble123_ds2) +
2639 32.0 * d_quartic_bubble_ds2;
2640
2641 // Add the bubble function on the face spanned by 0 1 3
2642 dpsids(10, 0) =
2643 27.0 * d_cubic_bubble013_ds0 - 108.0 * d_quartic_bubble_ds0;
2644 dpsids(10, 1) =
2645 27.0 * d_cubic_bubble013_ds1 - 108.0 * d_quartic_bubble_ds1;
2646 dpsids(10, 2) =
2647 27.0 * d_cubic_bubble013_ds2 - 108.0 * d_quartic_bubble_ds2;
2648
2649 // Add the bubble function on the face spanned by 0 1 2
2650 dpsids(11, 0) =
2651 27.0 * d_cubic_bubble012_ds0 - 108.0 * d_quartic_bubble_ds0;
2652 dpsids(11, 1) =
2653 27.0 * d_cubic_bubble012_ds1 - 108.0 * d_quartic_bubble_ds1;
2654 dpsids(11, 2) =
2655 27.0 * d_cubic_bubble012_ds2 - 108.0 * d_quartic_bubble_ds2;
2656
2657 // Add the bubble function on the face spanned by 0 2 3
2658 dpsids(12, 0) =
2659 27.0 * d_cubic_bubble023_ds0 - 108.0 * d_quartic_bubble_ds0;
2660 dpsids(12, 1) =
2661 27.0 * d_cubic_bubble023_ds1 - 108.0 * d_quartic_bubble_ds1;
2662 dpsids(12, 2) =
2663 27.0 * d_cubic_bubble023_ds2 - 108.0 * d_quartic_bubble_ds2;
2664
2665 // Add the bubble function on the face spanned by 1 2 3
2666 dpsids(13, 0) =
2667 27.0 * d_cubic_bubble123_ds0 - 108.0 * d_quartic_bubble_ds0;
2668 dpsids(13, 1) =
2669 27.0 * d_cubic_bubble123_ds1 - 108.0 * d_quartic_bubble_ds1;
2670 dpsids(13, 2) =
2671 27.0 * d_cubic_bubble123_ds2 - 108.0 * d_quartic_bubble_ds2;
2672
2673 // Add the volumetric bubble function derivatives
2674 dpsids(14, 0) = 256.0 * d_quartic_bubble_ds0;
2675 dpsids(14, 1) = 256.0 * d_quartic_bubble_ds1;
2676 dpsids(14, 2) = 256.0 * d_quartic_bubble_ds2;
2677 }
2678
2679
2680 //=======================================================================
2681 /// Second derivatives of shape functions for specific TElement<3,3>:
2682 /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
2683 /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
2684 /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_2^2 \f$
2685 /// d2psids(i,3) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
2686 /// d2psids(i,4) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_2 \f$
2687 /// d2psids(i,5) = \f$ \partial^2 \psi_j / \partial s_1 \partial s_2 \f$
2688 //=======================================================================
2690 Shape& psi,
2691 DShape& dpsids,
2692 DShape& d2psids) const
2693 {
2694 // ALH: Don't know why object qualifier is needed
2695 this->dshape_local(s, psi, dpsids);
2696
2697 // Define s3
2698 const double s3 = 1.0 - s[0] - s[1] - s[2];
2699
2700 // Calculate second derivatives of the bubble functions
2701 //(.,3) for mixed derivative s[0]-s[1]
2702 //(.,4) for mixed derivative s[0]-s[2]
2703 //(.,5) for mixed derivative s[1]-s[2]
2704
2705
2706 const double d2_quartic_bubble_ds0 = -2.0 * s[1] * s[2];
2707 const double d2_quartic_bubble_ds1 = -2.0 * s[0] * s[2];
2708 const double d2_quartic_bubble_ds2 = -2.0 * s[0] * s[1];
2709 const double d2_quartic_bubble_ds3 =
2710 s[2] * (1.0 - 2.0 * s[0] - 2.0 * s[1] - s[2]);
2711 const double d2_quartic_bubble_ds4 =
2712 s[1] * (1.0 - 2.0 * s[0] - 2.0 * s[2] - s[1]);
2713 const double d2_quartic_bubble_ds5 =
2714 s[0] * (1.0 - 2.0 * s[1] - 2.0 * s[2] - s[0]);
2715
2716 const double d2_cubic_bubble012_ds0 = 0.0;
2717 const double d2_cubic_bubble012_ds1 = 0.0;
2718 const double d2_cubic_bubble012_ds2 = 0.0;
2719 const double d2_cubic_bubble012_ds3 = s[2];
2720 const double d2_cubic_bubble012_ds4 = s[1];
2721 const double d2_cubic_bubble012_ds5 = s[0];
2722
2723 const double d2_cubic_bubble013_ds0 = -2.0 * s[1];
2724 const double d2_cubic_bubble013_ds1 = -2.0 * s[0];
2725 const double d2_cubic_bubble013_ds2 = 0.0;
2726 const double d2_cubic_bubble013_ds3 = s3 - s[0] - s[1];
2727 const double d2_cubic_bubble013_ds4 = -s[1];
2728 const double d2_cubic_bubble013_ds5 = -s[0];
2729
2730 const double d2_cubic_bubble023_ds0 = -2.0 * s[2];
2731 const double d2_cubic_bubble023_ds1 = 0.0;
2732 const double d2_cubic_bubble023_ds2 = -2.0 * s[0];
2733 const double d2_cubic_bubble023_ds3 = -s[2];
2734 const double d2_cubic_bubble023_ds4 = s3 - s[0] - s[2];
2735 const double d2_cubic_bubble023_ds5 = -s[0];
2736
2737 const double d2_cubic_bubble123_ds0 = 0.0;
2738 const double d2_cubic_bubble123_ds1 = -2.0 * s[2];
2739 const double d2_cubic_bubble123_ds2 = -2.0 * s[1];
2740 const double d2_cubic_bubble123_ds3 = -s[2];
2741 const double d2_cubic_bubble123_ds4 = -s[1];
2742 const double d2_cubic_bubble123_ds5 = s3 - s[1] - s[2];
2743
2744
2745 d2psids(0, 0) = 4.0 +
2746 3.0 * (d2_cubic_bubble012_ds0 + d2_cubic_bubble013_ds0 +
2747 d2_cubic_bubble023_ds0) -
2748 4.0 * d2_quartic_bubble_ds0;
2749 d2psids(0, 1) = 0.0 +
2750 3.0 * (d2_cubic_bubble012_ds1 + d2_cubic_bubble013_ds1 +
2751 d2_cubic_bubble023_ds1) -
2752 4.0 * d2_quartic_bubble_ds1;
2753 d2psids(0, 2) = 0.0 +
2754 3.0 * (d2_cubic_bubble012_ds2 + d2_cubic_bubble013_ds2 +
2755 d2_cubic_bubble023_ds2) -
2756 4.0 * d2_quartic_bubble_ds2;
2757 d2psids(0, 3) = 0.0 +
2758 3.0 * (d2_cubic_bubble012_ds3 + d2_cubic_bubble013_ds3 +
2759 d2_cubic_bubble023_ds3) -
2760 4.0 * d2_quartic_bubble_ds3;
2761 d2psids(0, 4) = 0.0 +
2762 3.0 * (d2_cubic_bubble012_ds4 + d2_cubic_bubble013_ds4 +
2763 d2_cubic_bubble023_ds4) -
2764 4.0 * d2_quartic_bubble_ds4;
2765 d2psids(0, 5) = 0.0 +
2766 3.0 * (d2_cubic_bubble012_ds5 + d2_cubic_bubble013_ds5 +
2767 d2_cubic_bubble023_ds5) -
2768 4.0 * d2_quartic_bubble_ds5;
2769
2770
2771 d2psids(1, 0) = 0.0 +
2772 3.0 * (d2_cubic_bubble012_ds0 + d2_cubic_bubble013_ds0 +
2773 d2_cubic_bubble123_ds0) -
2774 4.0 * d2_quartic_bubble_ds0;
2775 d2psids(1, 1) = 4.0 +
2776 3.0 * (d2_cubic_bubble012_ds1 + d2_cubic_bubble013_ds1 +
2777 d2_cubic_bubble123_ds1) -
2778 4.0 * d2_quartic_bubble_ds1;
2779 d2psids(1, 2) = 0.0 +
2780 3.0 * (d2_cubic_bubble012_ds2 + d2_cubic_bubble013_ds2 +
2781 d2_cubic_bubble123_ds2) -
2782 4.0 * d2_quartic_bubble_ds2;
2783 d2psids(1, 3) = 0.0 +
2784 3.0 * (d2_cubic_bubble012_ds3 + d2_cubic_bubble013_ds3 +
2785 d2_cubic_bubble123_ds3) -
2786 4.0 * d2_quartic_bubble_ds3;
2787 d2psids(1, 4) = 0.0 +
2788 3.0 * (d2_cubic_bubble012_ds4 + d2_cubic_bubble013_ds4 +
2789 d2_cubic_bubble123_ds4) -
2790 4.0 * d2_quartic_bubble_ds4;
2791 d2psids(1, 5) = 0.0 +
2792 3.0 * (d2_cubic_bubble012_ds5 + d2_cubic_bubble013_ds5 +
2793 d2_cubic_bubble123_ds5) -
2794 4.0 * d2_quartic_bubble_ds5;
2795
2796
2797 d2psids(2, 0) = 0.0 +
2798 3.0 * (d2_cubic_bubble012_ds0 + d2_cubic_bubble023_ds0 +
2799 d2_cubic_bubble123_ds0) -
2800 4.0 * d2_quartic_bubble_ds0;
2801 d2psids(2, 1) = 0.0 +
2802 3.0 * (d2_cubic_bubble012_ds1 + d2_cubic_bubble023_ds1 +
2803 d2_cubic_bubble123_ds1) -
2804 4.0 * d2_quartic_bubble_ds1;
2805 d2psids(2, 2) = 4.0 +
2806 3.0 * (d2_cubic_bubble012_ds2 + d2_cubic_bubble023_ds2 +
2807 d2_cubic_bubble123_ds2) -
2808 4.0 * d2_quartic_bubble_ds2;
2809 d2psids(2, 3) = 0.0 +
2810 3.0 * (d2_cubic_bubble012_ds3 + d2_cubic_bubble023_ds3 +
2811 d2_cubic_bubble123_ds3) -
2812 4.0 * d2_quartic_bubble_ds3;
2813 d2psids(2, 4) = 0.0 +
2814 3.0 * (d2_cubic_bubble012_ds4 + d2_cubic_bubble023_ds4 +
2815 d2_cubic_bubble123_ds4) -
2816 4.0 * d2_quartic_bubble_ds4;
2817 d2psids(2, 5) = 0.0 +
2818 3.0 * (d2_cubic_bubble012_ds5 + d2_cubic_bubble023_ds5 +
2819 d2_cubic_bubble123_ds5) -
2820 4.0 * d2_quartic_bubble_ds5;
2821
2822
2823 d2psids(3, 0) = 4.0 +
2824 3.0 * (d2_cubic_bubble013_ds0 + d2_cubic_bubble023_ds0 +
2825 d2_cubic_bubble123_ds0) -
2826 4.0 * d2_quartic_bubble_ds0;
2827 d2psids(3, 1) = 4.0 +
2828 3.0 * (d2_cubic_bubble013_ds1 + d2_cubic_bubble023_ds1 +
2829 d2_cubic_bubble123_ds1) -
2830 4.0 * d2_quartic_bubble_ds1;
2831 d2psids(3, 2) = 4.0 +
2832 3.0 * (d2_cubic_bubble013_ds2 + d2_cubic_bubble023_ds2 +
2833 d2_cubic_bubble123_ds2) -
2834 4.0 * d2_quartic_bubble_ds2;
2835 d2psids(3, 3) = 4.0 +
2836 3.0 * (d2_cubic_bubble013_ds3 + d2_cubic_bubble023_ds3 +
2837 d2_cubic_bubble123_ds3) -
2838 4.0 * d2_quartic_bubble_ds3;
2839 d2psids(3, 4) = 4.0 +
2840 3.0 * (d2_cubic_bubble013_ds4 + d2_cubic_bubble023_ds4 +
2841 d2_cubic_bubble123_ds4) -
2842 4.0 * d2_quartic_bubble_ds4;
2843 d2psids(3, 5) = 4.0 +
2844 3.0 * (d2_cubic_bubble013_ds5 + d2_cubic_bubble023_ds5 +
2845 d2_cubic_bubble123_ds5) -
2846 4.0 * d2_quartic_bubble_ds5;
2847
2848
2849 d2psids(4, 0) = 0.0 -
2850 12.0 * (d2_cubic_bubble012_ds0 + d2_cubic_bubble013_ds0) +
2851 32.0 * d2_quartic_bubble_ds0;
2852 d2psids(4, 1) = 0.0 -
2853 12.0 * (d2_cubic_bubble012_ds1 + d2_cubic_bubble013_ds1) +
2854 32.0 * d2_quartic_bubble_ds1;
2855 d2psids(4, 2) = 0.0 -
2856 12.0 * (d2_cubic_bubble012_ds2 + d2_cubic_bubble013_ds2) +
2857 32.0 * d2_quartic_bubble_ds2;
2858 d2psids(4, 3) = 4.0 -
2859 12.0 * (d2_cubic_bubble012_ds3 + d2_cubic_bubble013_ds3) +
2860 32.0 * d2_quartic_bubble_ds3;
2861 d2psids(4, 4) = 0.0 -
2862 12.0 * (d2_cubic_bubble012_ds4 + d2_cubic_bubble013_ds4) +
2863 32.0 * d2_quartic_bubble_ds4;
2864 d2psids(4, 5) = 0.0 -
2865 12.0 * (d2_cubic_bubble012_ds5 + d2_cubic_bubble013_ds5) +
2866 32.0 * d2_quartic_bubble_ds5;
2867
2868
2869 d2psids(5, 0) = 0.0 -
2870 12.0 * (d2_cubic_bubble012_ds0 + d2_cubic_bubble023_ds0) +
2871 32.0 * d2_quartic_bubble_ds0;
2872 d2psids(5, 1) = 0.0 -
2873 12.0 * (d2_cubic_bubble012_ds1 + d2_cubic_bubble023_ds1) +
2874 32.0 * d2_quartic_bubble_ds1;
2875 d2psids(5, 2) = 0.0 -
2876 12.0 * (d2_cubic_bubble012_ds2 + d2_cubic_bubble023_ds2) +
2877 32.0 * d2_quartic_bubble_ds2;
2878 d2psids(5, 3) = 0.0 -
2879 12.0 * (d2_cubic_bubble012_ds3 + d2_cubic_bubble023_ds3) +
2880 32.0 * d2_quartic_bubble_ds3;
2881 d2psids(5, 4) = 4.0 -
2882 12.0 * (d2_cubic_bubble012_ds4 + d2_cubic_bubble023_ds4) +
2883 32.0 * d2_quartic_bubble_ds4;
2884 d2psids(5, 5) = 0.0 -
2885 12.0 * (d2_cubic_bubble012_ds5 + d2_cubic_bubble023_ds5) +
2886 32.0 * d2_quartic_bubble_ds5;
2887
2888
2889 d2psids(6, 0) = -8.0 -
2890 12.0 * (d2_cubic_bubble013_ds0 + d2_cubic_bubble023_ds0) +
2891 32.0 * d2_quartic_bubble_ds0;
2892 d2psids(6, 1) = 0.0 -
2893 12.0 * (d2_cubic_bubble013_ds1 + d2_cubic_bubble023_ds1) +
2894 32.0 * d2_quartic_bubble_ds1;
2895 d2psids(6, 2) = 0.0 -
2896 12.0 * (d2_cubic_bubble013_ds2 + d2_cubic_bubble023_ds2) +
2897 32.0 * d2_quartic_bubble_ds2;
2898 d2psids(6, 3) = -4.0 -
2899 12.0 * (d2_cubic_bubble013_ds3 + d2_cubic_bubble023_ds3) +
2900 32.0 * d2_quartic_bubble_ds3;
2901 d2psids(6, 4) = -4.0 -
2902 12.0 * (d2_cubic_bubble013_ds4 + d2_cubic_bubble023_ds4) +
2903 32.0 * d2_quartic_bubble_ds4;
2904 d2psids(6, 5) = 0.0 -
2905 12.0 * (d2_cubic_bubble013_ds5 + d2_cubic_bubble023_ds5) +
2906 32.0 * d2_quartic_bubble_ds5;
2907
2908 d2psids(7, 0) = 0.0 -
2909 12.0 * (d2_cubic_bubble012_ds0 + d2_cubic_bubble123_ds0) +
2910 32.0 * d2_quartic_bubble_ds0;
2911 d2psids(7, 1) = 0.0 -
2912 12.0 * (d2_cubic_bubble012_ds1 + d2_cubic_bubble123_ds1) +
2913 32.0 * d2_quartic_bubble_ds1;
2914 d2psids(7, 2) = 0.0 -
2915 12.0 * (d2_cubic_bubble012_ds2 + d2_cubic_bubble123_ds2) +
2916 32.0 * d2_quartic_bubble_ds2;
2917 d2psids(7, 3) = 0.0 -
2918 12.0 * (d2_cubic_bubble012_ds3 + d2_cubic_bubble123_ds3) +
2919 32.0 * d2_quartic_bubble_ds3;
2920 d2psids(7, 4) = 0.0 -
2921 12.0 * (d2_cubic_bubble012_ds4 + d2_cubic_bubble123_ds4) +
2922 32.0 * d2_quartic_bubble_ds4;
2923 d2psids(7, 5) = 4.0 -
2924 12.0 * (d2_cubic_bubble012_ds5 + d2_cubic_bubble123_ds5) +
2925 32.0 * d2_quartic_bubble_ds5;
2926
2927 d2psids(8, 0) = 0.0 -
2928 12.0 * (d2_cubic_bubble023_ds0 + d2_cubic_bubble123_ds0) +
2929 32.0 * d2_quartic_bubble_ds0;
2930 d2psids(8, 1) = 0.0 -
2931 12.0 * (d2_cubic_bubble023_ds1 + d2_cubic_bubble123_ds1) +
2932 32.0 * d2_quartic_bubble_ds1;
2933 d2psids(8, 2) = -8.0 -
2934 12.0 * (d2_cubic_bubble023_ds2 + d2_cubic_bubble123_ds2) +
2935 32.0 * d2_quartic_bubble_ds2;
2936 d2psids(8, 3) = 0.0 -
2937 12.0 * (d2_cubic_bubble023_ds3 + d2_cubic_bubble123_ds3) +
2938 32.0 * d2_quartic_bubble_ds3;
2939 d2psids(8, 4) = -4.0 -
2940 12.0 * (d2_cubic_bubble023_ds4 + d2_cubic_bubble123_ds4) +
2941 32.0 * d2_quartic_bubble_ds4;
2942 d2psids(8, 5) = -4.0 -
2943 12.0 * (d2_cubic_bubble023_ds5 + d2_cubic_bubble123_ds5) +
2944 32.0 * d2_quartic_bubble_ds5;
2945
2946 d2psids(9, 0) = 0.0 -
2947 12.0 * (d2_cubic_bubble013_ds0 + d2_cubic_bubble123_ds0) +
2948 32.0 * d2_quartic_bubble_ds0;
2949 d2psids(9, 1) = -8.0 -
2950 12.0 * (d2_cubic_bubble013_ds1 + d2_cubic_bubble123_ds1) +
2951 32.0 * d2_quartic_bubble_ds1;
2952 d2psids(9, 2) = 0.0 -
2953 12.0 * (d2_cubic_bubble013_ds2 + d2_cubic_bubble123_ds2) +
2954 32.0 * d2_quartic_bubble_ds3;
2955 d2psids(9, 3) = -4.0 -
2956 12.0 * (d2_cubic_bubble013_ds3 + d2_cubic_bubble123_ds3) +
2957 32.0 * d2_quartic_bubble_ds3;
2958 d2psids(9, 4) = 0.0 -
2959 12.0 * (d2_cubic_bubble013_ds4 + d2_cubic_bubble123_ds4) +
2960 32.0 * d2_quartic_bubble_ds4;
2961 d2psids(9, 5) = -4.0 -
2962 12.0 * (d2_cubic_bubble013_ds5 + d2_cubic_bubble123_ds5) +
2963 32.0 * d2_quartic_bubble_ds5;
2964
2965 // Add the bubble function on the face spanned by 0 1 3
2966 d2psids(10, 0) =
2967 27.0 * d2_cubic_bubble013_ds0 - 108.0 * d2_quartic_bubble_ds0;
2968 d2psids(10, 1) =
2969 27.0 * d2_cubic_bubble013_ds1 - 108.0 * d2_quartic_bubble_ds1;
2970 d2psids(10, 2) =
2971 27.0 * d2_cubic_bubble013_ds2 - 108.0 * d2_quartic_bubble_ds2;
2972 d2psids(10, 3) =
2973 27.0 * d2_cubic_bubble013_ds3 - 108.0 * d2_quartic_bubble_ds3;
2974 d2psids(10, 4) =
2975 27.0 * d2_cubic_bubble013_ds4 - 108.0 * d2_quartic_bubble_ds4;
2976 d2psids(10, 5) =
2977 27.0 * d2_cubic_bubble013_ds5 - 108.0 * d2_quartic_bubble_ds5;
2978
2979 // Add the bubble function on the face spanned by 0 1 2
2980 d2psids(11, 0) =
2981 27.0 * d2_cubic_bubble012_ds0 - 108.0 * d2_quartic_bubble_ds0;
2982 d2psids(11, 1) =
2983 27.0 * d2_cubic_bubble012_ds1 - 108.0 * d2_quartic_bubble_ds1;
2984 d2psids(11, 2) =
2985 27.0 * d2_cubic_bubble012_ds2 - 108.0 * d2_quartic_bubble_ds2;
2986 d2psids(11, 3) =
2987 27.0 * d2_cubic_bubble012_ds3 - 108.0 * d2_quartic_bubble_ds3;
2988 d2psids(11, 4) =
2989 27.0 * d2_cubic_bubble012_ds4 - 108.0 * d2_quartic_bubble_ds4;
2990 d2psids(11, 5) =
2991 27.0 * d2_cubic_bubble012_ds5 - 108.0 * d2_quartic_bubble_ds5;
2992
2993 // Add the bubble function on the face spanned by 0 2 3
2994 d2psids(12, 0) =
2995 27.0 * d2_cubic_bubble023_ds0 - 108.0 * d2_quartic_bubble_ds0;
2996 d2psids(12, 1) =
2997 27.0 * d2_cubic_bubble023_ds1 - 108.0 * d2_quartic_bubble_ds1;
2998 d2psids(12, 2) =
2999 27.0 * d2_cubic_bubble023_ds2 - 108.0 * d2_quartic_bubble_ds2;
3000 d2psids(12, 3) =
3001 27.0 * d2_cubic_bubble023_ds3 - 108.0 * d2_quartic_bubble_ds3;
3002 d2psids(12, 4) =
3003 27.0 * d2_cubic_bubble023_ds4 - 108.0 * d2_quartic_bubble_ds4;
3004 d2psids(12, 5) =
3005 27.0 * d2_cubic_bubble023_ds5 - 108.0 * d2_quartic_bubble_ds5;
3006
3007 // Add the bubble function on the face spanned by 1 2 3
3008 d2psids(13, 0) =
3009 27.0 * d2_cubic_bubble123_ds0 - 108.0 * d2_quartic_bubble_ds0;
3010 d2psids(13, 1) =
3011 27.0 * d2_cubic_bubble123_ds1 - 108.0 * d2_quartic_bubble_ds1;
3012 d2psids(13, 2) =
3013 27.0 * d2_cubic_bubble123_ds2 - 108.0 * d2_quartic_bubble_ds2;
3014 d2psids(13, 3) =
3015 27.0 * d2_cubic_bubble123_ds3 - 108.0 * d2_quartic_bubble_ds3;
3016 d2psids(13, 4) =
3017 27.0 * d2_cubic_bubble123_ds4 - 108.0 * d2_quartic_bubble_ds4;
3018 d2psids(13, 5) =
3019 27.0 * d2_cubic_bubble123_ds5 - 108.0 * d2_quartic_bubble_ds5;
3020
3021 // Add the volumetric bubble function derivatives
3022 d2psids(14, 0) = 256.0 * d2_quartic_bubble_ds0;
3023 d2psids(14, 1) = 256.0 * d2_quartic_bubble_ds1;
3024 d2psids(14, 2) = 256.0 * d2_quartic_bubble_ds2;
3025 d2psids(14, 3) = 256.0 * d2_quartic_bubble_ds3;
3026 d2psids(14, 4) = 256.0 * d2_quartic_bubble_ds4;
3027 d2psids(14, 5) = 256.0 * d2_quartic_bubble_ds5;
3028 }
3029 };
3030
3031
3032 //=======================================================================
3033 /// General TElement class specialised to three spatial dimensions (tet)
3034 /// Ordering of nodes inverted from Zienkiewizc sketches: When looking into
3035 /// the tet from vertex node 0. The vertex nodes on the opposite face are 1 -
3036 /// 2 - 3 in anticlockwise direction. Other nodes filled in edge by edge, then
3037 /// the face ones, then the internal ones.
3038 //=======================================================================
3039 template<unsigned NNODE_1D>
3040 class TElement<3, NNODE_1D> : public virtual TElementBase,
3041 public TElementShape<3, NNODE_1D>
3042 {
3043 private:
3044 /// Nodal translation scheme for use when generating face elements
3045 static const unsigned Node_on_face[4][(NNODE_1D * (NNODE_1D + 1)) / 2];
3046
3047 /// Default integration rule: Gaussian integration of same 'order' as
3048 /// the element
3049 // This is sort of optimal, because it means that the integration is exact
3050 // for the shape functions. Can overwrite this in specific element
3051 // defintion.
3053
3054 public:
3055 /// Constructor
3057 {
3058 switch (NNODE_1D)
3059 {
3060 case 2:
3061 case 3:
3062 break;
3063
3064 /* case 4: */
3065 /* n_node = 20; */
3066 /* break; */
3067
3068 default:
3069 std::string error_message =
3070 "Tets are currently only implemented for\n";
3071 error_message += "four and ten nodes, i.e. NNODE_1D=2 , 3 \n";
3072
3073 throw OomphLibError(
3074 error_message, OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
3075 }
3076
3077
3078 // Set the number of nodes
3079 unsigned n_node =
3080 (NNODE_1D * (NNODE_1D + 1)) / 2 + 1 + 3 * (NNODE_1D - 2);
3081 this->set_n_node(n_node);
3082
3083 // Set the elemental and nodal dimensions
3084 set_dimension(3);
3085
3086 // Assign default (full) spatial integration scheme
3087 set_integration_scheme(&Default_integration_scheme);
3088 }
3089
3090
3091 /// Broken copy constructor
3092 TElement(const TElement&) = delete;
3093
3094 /// Broken assignment operator
3095 /*void operator=(const TElement&) = delete;*/
3096
3097
3098 /// Destructor
3100
3101 /// Number of nodes along each element edge
3102 unsigned nnode_1d() const
3103 {
3104 return NNODE_1D;
3105 }
3106
3107
3108 /// Number of vertex nodes in the element: One more
3109 /// than spatial dimension
3110 unsigned nvertex_node() const
3111 {
3112 return 4;
3113 }
3114
3115 /// Public access function for Node_on_face.
3116 unsigned get_bulk_node_number(const int& face_index,
3117 const unsigned& i) const
3118 {
3119 return Node_on_face[face_index][i];
3120 }
3121
3122 /// Pointer to the j-th vertex node in the element
3123 Node* vertex_node_pt(const unsigned& j) const
3124 {
3125 // Vertex nodes come first:
3126#ifdef PARANOID
3127 if (j > 3)
3128 {
3129 std::ostringstream error_message;
3130 error_message
3131 << "Element only has four vertex nodes; called with node number " << j
3132 << std::endl;
3133 throw OomphLibError(error_message.str(),
3134 OOMPH_CURRENT_FUNCTION,
3135 OOMPH_EXCEPTION_LOCATION);
3136 }
3137#endif
3138 return node_pt(j);
3139 }
3140
3141 /// Calculate the geometric shape functions at local coordinate s
3142 inline void shape(const Vector<double>& s, Shape& psi) const
3143 {
3145 }
3146
3147 /// Compute the geometric shape functions and
3148 /// derivatives w.r.t. local coordinates at local coordinate s
3149 inline void dshape_local(const Vector<double>& s,
3150 Shape& psi,
3151 DShape& dpsids) const
3152 {
3154 }
3155
3156 /// Compute the geometric shape functions, derivatives and
3157 /// second derivatives w.r.t local coordinates at local coordinate s.
3158 /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
3159 /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
3160 /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_2^2 \f$
3161 /// d2psids(i,3) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
3162 /// d2psids(i,4) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_2 \f$
3163 /// d2psids(i,5) = \f$ \partial^2 \psi_j / \partial s_1 \partial s_2 \f$
3164 inline void d2shape_local(const Vector<double>& s,
3165 Shape& psi,
3166 DShape& dpsids,
3167 DShape& d2psids) const
3168 {
3169 TElementShape<3, NNODE_1D>::d2shape_local(s, psi, dpsids, d2psids);
3170 }
3171
3172 /// Overload the template-free interface for the calculation of
3173 /// inverse jacobian matrix. This is a three dimensional element, so use
3174 /// the 3D version.
3176 DenseMatrix<double>& inverse_jacobian) const
3177 {
3178 return FiniteElement::invert_jacobian<3>(jacobian, inverse_jacobian);
3179 }
3180
3181 /// Min. value of local coordinate
3182 double s_min() const
3183 {
3184 return 0.0;
3185 }
3186
3187 /// Max. value of local coordinate
3188 double s_max() const
3189 {
3190 return 1.0;
3191 }
3192
3193 /// Return local coordinates of node j
3194 inline void local_coordinate_of_node(const unsigned& j,
3195 Vector<double>& s) const
3196 {
3198 }
3199
3200 /// Return the number of actual plot points for paraview
3201 /// plot with parameter nplot.
3202 unsigned nplot_points_paraview(const unsigned& nplot) const
3203 {
3204 unsigned node_sum = 0;
3205 for (unsigned j = 1; j <= nplot; j++)
3206 {
3207 for (unsigned i = 1; i <= j; i++)
3208 {
3209 node_sum += i;
3210 }
3211 }
3212 return node_sum;
3213 }
3214
3215 /// Return the number of local sub-elements for paraview plot with
3216 /// parameter nplot.
3217 unsigned nsub_elements_paraview(const unsigned& nplot) const
3218 {
3219 return (nplot - 1) * (nplot - 1) * (nplot - 1);
3220 }
3221
3222 /// Fill in the offset information for paraview plot.
3223 /// Needs to be implemented for each new geometric element type; see
3224 /// http://www.vtk.org/VTK/img/file-formats.pdf
3225 void write_paraview_output_offset_information(std::ofstream& file_out,
3226 const unsigned& nplot,
3227 unsigned& counter) const
3228 {
3229 // Output node lists for sub elements for Paraview (node index
3230 // must start at 0, fixed with magical counter-1)
3231
3232 unsigned paraview_fix = counter - 1;
3233 unsigned nod_count = 1;
3234
3235 for (unsigned i = 0; i < nplot; i++)
3236 {
3237 for (unsigned j = 0; j < nplot - i; j++)
3238 {
3239 for (unsigned k = 0; k < nplot - i - j; k++)
3240 {
3241 if (k < nplot - i - j - 1)
3242 {
3243 file_out << nod_count + paraview_fix << " "
3244 << nod_count + 1 + paraview_fix << " "
3245 << nod_count + nplot - i - j + paraview_fix << " "
3246 << nod_count + nplot - i - j +
3247 ((nplot - 1 - i) * (nplot - i) / 2) + paraview_fix
3248 << std::endl;
3249 if (k < nplot - i - j - 2)
3250 {
3251 file_out << nod_count + 1 + paraview_fix << " "
3252 << nod_count + nplot - i - j + paraview_fix << " "
3253 << nod_count + nplot - i - j +
3254 ((nplot - 1 - i) * (nplot - i) / 2) + paraview_fix
3255 << " "
3256 << nod_count + 2 * (nplot - i - j) - 1 +
3257 ((nplot - 1 - i) * (nplot - i) / 2) + paraview_fix
3258 << std::endl;
3259 file_out << nod_count + 1 + paraview_fix << " "
3260 << nod_count + nplot - i - j + paraview_fix << " "
3261 << nod_count + nplot - i - j + 1 + paraview_fix << " "
3262 << nod_count + 2 * (nplot - i - j) - 1 +
3263 ((nplot - 1 - i) * (nplot - i) / 2) + paraview_fix
3264 << std::endl;
3265 file_out << nod_count + 1 + paraview_fix << " "
3266 << nod_count + nplot - i - j +
3267 ((nplot - 1 - i) * (nplot - i) / 2) + paraview_fix
3268 << " "
3269 << nod_count + nplot - i - j +
3270 ((nplot - 1 - i) * (nplot - i) / 2) + 1 +
3271 paraview_fix
3272 << " "
3273 << nod_count + 2 * (nplot - i - j) - 1 +
3274 ((nplot - 1 - i) * (nplot - i) / 2) + paraview_fix
3275 << std::endl;
3276 file_out << nod_count + 1 + paraview_fix << " "
3277 << nod_count + nplot - i - j + 1 + paraview_fix << " "
3278 << nod_count + nplot - i - j +
3279 ((nplot - 1 - i) * (nplot - i) / 2) + 1 +
3280 paraview_fix
3281 << " "
3282 << nod_count + 2 * (nplot - i - j) - 1 +
3283 ((nplot - 1 - i) * (nplot - i) / 2) + paraview_fix
3284 << std::endl;
3285 }
3286 if (k > 1)
3287 {
3288 file_out << nod_count + nplot - i - j - 1 + paraview_fix << " "
3289 << nod_count + nplot - i - j +
3290 ((nplot - 1 - i) * (nplot - i) / 2) - 1 +
3291 paraview_fix
3292 << " "
3293 << nod_count + 2 * (nplot - i - j - 1) +
3294 ((nplot - 1 - i) * (nplot - i) / 2) - 1 +
3295 paraview_fix
3296 << " "
3297 << nod_count + 2 * (nplot - i - j - 1) +
3298 ((nplot - 1 - i) * (nplot - i) / 2) + paraview_fix
3299 << std::endl;
3300 }
3301 } // end if(k<nplot-i-j-1)
3302 ++nod_count;
3303 }
3304 }
3305 }
3306
3307 // increment the counter to keep track of global connectivity
3308 counter += nplot_points_paraview(nplot);
3309
3310 } // end of write Paraview_element...
3311
3312 /// Return the paraview element type.
3313 /// Needs to be implemented for each new geometric element type; see
3314 /// http://www.vtk.org/VTK/img/file-formats.pdf
3315 void write_paraview_type(std::ofstream& file_out,
3316 const unsigned& nplot) const
3317 {
3318 unsigned local_loop = nsub_elements_paraview(nplot);
3319 for (unsigned i = 0; i < local_loop; i++)
3320 {
3321 file_out << "10" << std::endl;
3322 }
3323 }
3324
3325 /// Return the offsets for the paraview sub-elements. Needs
3326 /// to be implemented for each new geometric element type; see
3327 /// http://www.vtk.org/VTK/img/file-formats.pdf
3328 void write_paraview_offsets(std::ofstream& file_out,
3329 const unsigned& nplot,
3330 unsigned& offset_sum) const
3331 {
3332 unsigned local_loop = nsub_elements_paraview(nplot);
3333 for (unsigned i = 0; i < local_loop; i++)
3334 {
3335 offset_sum += 4;
3336 file_out << offset_sum << std::endl;
3337 }
3338 }
3339
3340 /// Output
3341 void output(std::ostream& output);
3342
3343 /// Output at specified number of plot points
3344 void output(std::ostream& outfile, const unsigned& nplot);
3345
3346 /// C-style output
3347 void output(FILE* file_pt);
3348
3349 /// C_style output at n_plot points
3350 void output(FILE* file_pt, const unsigned& n_plot);
3351
3352 /// Get vector of local coordinates of plot point i (when plotting
3353 /// nplot points in each "coordinate direction).
3355 const unsigned& iplot,
3356 const unsigned& nplot,
3358 const bool& use_equally_spaced_interior_sample_points = false) const
3359 {
3360 if (nplot > 1)
3361 {
3362 unsigned np = 0;
3363 for (unsigned i = 0; i < nplot; ++i)
3364 {
3365 for (unsigned j = 0; j < nplot - i; ++j)
3366 {
3367 for (unsigned k = 0; k < nplot - i - j; ++k)
3368 {
3369 if (np == iplot)
3370 {
3371 {
3372 s[0] = double(j) / double(nplot - 1);
3373 s[1] = double(i) / double(nplot - 1);
3374 s[2] = double(k) / double(nplot - 1);
3375 if (use_equally_spaced_interior_sample_points)
3376 {
3377 double range = 1.0;
3378 double dx_new = range / double(nplot + 1);
3379 double range_new = double(nplot - 1) * dx_new;
3380 s[0] = 0.5 * dx_new + range_new * s[0] / range;
3381 s[1] = 0.5 * dx_new + range_new * s[1] / range;
3382 s[2] = 0.5 * dx_new + range_new * s[2] / range;
3383 }
3384 return;
3385 }
3386 }
3387 np++;
3388 }
3389 }
3390 }
3391 }
3392 else
3393 {
3394 s[0] = 1.0 / 4.0;
3395 s[1] = 1.0 / 4.0;
3396 s[2] = 1.0 / 4.0;
3397 }
3398 }
3399
3400 /// Return string for tecplot zone header (when plotting
3401 /// nplot points in each "coordinate direction)
3402 std::string tecplot_zone_string(const unsigned& nplot) const
3403 {
3404 std::ostringstream header;
3405 unsigned nel = 0;
3406 nel = (nplot - 1) * (nplot - 1) * (nplot - 1);
3407 header << "ZONE N=" << nplot_points(nplot) << ", E=" << nel
3408 << ", F=FEPOINT, ET=TETRAHEDRON\n";
3409 return header.str();
3410 }
3411
3412 /// Add tecplot zone "footer" to output stream (when plotting
3413 /// nplot points in each "coordinate direction).
3414 /// Empty by default -- can be used, e.g., to add FE connectivity
3415 /// lists to elements that need it.
3416 void write_tecplot_zone_footer(std::ostream& outfile,
3417 const unsigned& nplot) const
3418 {
3419 // Output node lists for sub elements for Tecplot (node index
3420 // must start at 1)
3421 unsigned nod_count = 1;
3422 for (unsigned i = 0; i < nplot; i++)
3423 {
3424 for (unsigned j = 0; j < nplot - i; j++)
3425 {
3426 for (unsigned k = 0; k < nplot - i - j; k++)
3427 {
3428 if (k < nplot - i - j - 1)
3429 {
3430 outfile << nod_count << " " << nod_count + 1 << " "
3431 << nod_count + nplot - i - j << " "
3432 << nod_count + nplot - i - j +
3433 ((nplot - 1 - i) * (nplot - i) / 2)
3434 << std::endl;
3435 if (k < nplot - i - j - 2)
3436 {
3437 outfile << nod_count + 1 << " " << nod_count + nplot - i - j
3438 << " "
3439 << nod_count + nplot - i - j +
3440 ((nplot - 1 - i) * (nplot - i) / 2)
3441 << " "
3442 << nod_count + 2 * (nplot - i - j) - 1 +
3443 ((nplot - 1 - i) * (nplot - i) / 2)
3444 << std::endl;
3445 outfile << nod_count + 1 << " " << nod_count + nplot - i - j
3446 << " " << nod_count + nplot - i - j + 1 << " "
3447 << nod_count + 2 * (nplot - i - j) - 1 +
3448 ((nplot - 1 - i) * (nplot - i) / 2)
3449 << std::endl;
3450 outfile << nod_count + 1 << " "
3451 << nod_count + nplot - i - j +
3452 ((nplot - 1 - i) * (nplot - i) / 2)
3453 << " "
3454 << nod_count + nplot - i - j +
3455 ((nplot - 1 - i) * (nplot - i) / 2) + 1
3456 << " "
3457 << nod_count + 2 * (nplot - i - j) - 1 +
3458 ((nplot - 1 - i) * (nplot - i) / 2)
3459 << std::endl;
3460 outfile << nod_count + 1 << " " << nod_count + nplot - i - j + 1
3461 << " "
3462 << nod_count + nplot - i - j +
3463 ((nplot - 1 - i) * (nplot - i) / 2) + 1
3464 << " "
3465 << nod_count + 2 * (nplot - i - j) - 1 +
3466 ((nplot - 1 - i) * (nplot - i) / 2)
3467 << std::endl;
3468 }
3469 if (k > 1)
3470 {
3471 outfile << nod_count + nplot - i - j - 1 << " "
3472 << nod_count + nplot - i - j +
3473 ((nplot - 1 - i) * (nplot - i) / 2) - 1
3474 << " "
3475 << nod_count + 2 * (nplot - i - j - 1) +
3476 ((nplot - 1 - i) * (nplot - i) / 2) - 1
3477 << " "
3478 << nod_count + 2 * (nplot - i - j - 1) +
3479 ((nplot - 1 - i) * (nplot - i) / 2)
3480 << std::endl;
3481 }
3482 } // end if(k<nplot-i-j-1)
3483 ++nod_count;
3484 }
3485 }
3486 }
3487 } // end of write tecplot...
3488
3489
3490 /// Add tecplot zone "footer" to C-style output. (when plotting
3491 /// nplot points in each "coordinate direction).
3492 /// Empty by default -- can be used, e.g., to add FE connectivity
3493 /// lists to elements that need it.
3494 void write_tecplot_zone_footer(FILE* file_pt, const unsigned& nplot) const
3495 {
3496 // Output node lists for sub elements for Tecplot (node index
3497 // must start at 1)
3498 unsigned nod_count = 1;
3499 for (unsigned i = 0; i < nplot; i++)
3500 {
3501 for (unsigned j = 0; j < nplot - i; j++)
3502 {
3503 for (unsigned k = 0; k < nplot - i - j; k++)
3504 {
3505 if (j < nplot - i - 1)
3506 {
3507 fprintf(file_pt,
3508 "%i %i %i \n",
3509 nod_count,
3510 nod_count + 1,
3511 nod_count + nplot - i);
3512 if (j < nplot - i - 2)
3513 {
3514 fprintf(file_pt,
3515 "%i %i %i \n",
3516 nod_count + 1,
3517 nod_count + nplot - i + 1,
3518 nod_count + nplot - i);
3519 }
3520 }
3521 ++nod_count;
3522 }
3523 }
3524 }
3525 }
3526
3527 /// Return total number of plot points (when plotting
3528 /// nplot points in each "coordinate direction)
3529 unsigned nplot_points(const unsigned& nplot) const
3530 {
3531 unsigned res = 0;
3532 if (nplot > 1)
3533 {
3534 res = 4;
3535 for (unsigned i = 3; i <= nplot; i++)
3536 {
3537 res += (i * (i + 1) / 2);
3538 }
3539 return res;
3540 }
3541 // Otherwise we return 1(?)
3542 return 1;
3543 }
3544
3545 /// Build the lower-dimensional FaceElement (an element of type
3546 /// TElement<2,NNODE_1D>). The face index can take one of four values
3547 /// corresponding to the four possible faces:
3548 /// 0: (left) s[0] = 0.0
3549 /// 1: (bottom) s[1] = 0.0
3550 /// 2: (back) s[2] = 0.0
3551 /// 3: (sloping face) s[0] + s[1] + s[2] = 1
3552 void build_face_element(const int& face_index,
3553 FaceElement* face_element_pt);
3554 };
3555
3556
3557 /// ////////////////////////////////////////////////////////////////////
3558 /// ////////////////////////////////////////////////////////////////////
3559 /// ////////////////////////////////////////////////////////////////////
3560
3561
3562 //=======================================================================
3563 /// TElement class for which the shape functions have been enriched
3564 /// by a single bubble function of the next order
3565 ///
3566 /// Empty, just establishes the template parameters
3567 //=======================================================================
3568 template<unsigned DIM, unsigned NNODE_1D>
3570 {
3571 };
3572
3573 //=====================================================================
3574 /// Define integration schemes that are required to exactly integrate
3575 /// the mass matrices of the bubble-enriched elements. The enrichement
3576 /// increases the polynomial order which means that higher-order Gauss
3577 /// rules must be used.
3578 //====================================================================
3579 template<unsigned DIM, unsigned NPTS_1D>
3581 {
3582 };
3583
3584 //====================================================================
3585 /// Specialisation for two-dimensional elements, in which the highest
3586 /// order polynomial is cubic, so we need the integration scheme
3587 /// for the unenriched cubic element
3588 //======================================================================
3589 template<>
3590 class TBubbleEnrichedGauss<2, 3> : public TGauss<2, 4>
3591 {
3592 public:
3594 };
3595
3596 //====================================================================
3597 /// Specialisation for three-dimensional elements, in which the highest
3598 /// order polynomial is quartic, so we need the integration scheme
3599 /// for the unenriched quartic element
3600 //======================================================================
3601 template<>
3602 class TBubbleEnrichedGauss<3, 3> : public TGauss<3, 5>
3603 {
3604 public:
3606 };
3607
3608
3609 //=======================================================================
3610 /// Enriched TElement class specialised to two spatial dimensions
3611 /// and three nodes per side (quadratic element)
3612 /// Ordering of nodes as in Zienkiwizc sketches: vertex nodes
3613 /// 0 - 1 - 2 anticlockwise. Midside nodes filled in progressing
3614 /// along the consecutive edges. Central node(s) come(s) last.
3615 /// The idea is that we inherit from the existing TElement<2,3>, add
3616 /// the single extra node at the centroid and
3617 /// overload the shape functions to be those corresponding to the
3618 /// enriched element.
3619 //=======================================================================
3620 template<unsigned DIM>
3622 : public virtual TElement<DIM, 3>,
3623 public TBubbleEnrichedElementShape<DIM, 3>
3624 {
3625 private:
3626 // Static storage for a new integration scheme
3628
3629 // Static storage for central node
3630 static const unsigned Central_node_on_face[DIM + 1];
3631
3632 public:
3633 /// Constructor
3635 : TElement<DIM, 3>(), TBubbleEnrichedElementShape<DIM, 3>()
3636 {
3637 // Add the additional enrichment nodes
3638 unsigned n_node = this->nnode();
3639 this->set_n_node(n_node +
3641 // Set the new integration scheme
3642 this->set_integration_scheme(&Default_enriched_integration_scheme);
3643 }
3644
3645 /// Broken copy constructor
3647
3648 /// Broken assignment operator
3649 /*void operator=(const TBubbleEnrichedElement&) = delete;*/
3650
3651 /// Destructor
3653
3654 /// Calculate the geometric shape functions at local coordinate s
3655 inline void shape(const Vector<double>& s, Shape& psi) const
3656 {
3658 }
3659
3660 /// Compute the geometric shape functions and
3661 /// derivatives w.r.t. local coordinates at local coordinate s
3662 inline void dshape_local(const Vector<double>& s,
3663 Shape& psi,
3664 DShape& dpsids) const
3665 {
3667 }
3668
3669
3670 /// Compute the geometric shape functions, derivatives and
3671 /// second derivatives w.r.t local coordinates at local coordinate s
3672 /// d2psids(i,0) = \f$ \partial^2 \psi_j / \partial s_0^2 \f$
3673 /// d2psids(i,1) = \f$ \partial^2 \psi_j / \partial s_1^2 \f$
3674 /// d2psids(i,2) = \f$ \partial^2 \psi_j / \partial s_0 \partial s_1 \f$
3675 inline void d2shape_local(const Vector<double>& s,
3676 Shape& psi,
3677 DShape& dpsids,
3678 DShape& d2psids) const
3679 {
3681 s, psi, dpsids, d2psids);
3682 }
3683
3684 /// Return local coordinates of node j
3685 inline void local_coordinate_of_node(const unsigned& j,
3686 Vector<double>& s) const
3687 {
3689 }
3690
3691 /// Build the lower-dimensional FaceElement
3692 void build_face_element(const int& face_index,
3693 FaceElement* face_element_pt);
3694 };
3695
3696
3697 //========================================================================
3698 /// Base class for Solid Telements
3699 //========================================================================
3700 class TSolidElementBase : public virtual TElementBase,
3701 public virtual SolidFiniteElement
3702 {
3703 public:
3704 /// Constructor: Empty
3706
3707 /// Broken copy constructor
3709
3710 /// Broken assignment operator
3711 /*void operator=(const TSolidElementBase&) = delete;*/
3712 };
3713
3714
3715 /// ///////////////////////////////////////////////////////////////////////
3716 /// ///////////////////////////////////////////////////////////////////////
3717 /// ///////////////////////////////////////////////////////////////////////
3718
3719
3720 //=======================================================================
3721 /// SolidTElement elements are triangular/tet elements whose
3722 /// derivatives also include those based upon the lagrangian
3723 /// positions of the nodes.
3724 /// They are the basis for solid mechanics elements.
3725 //=======================================================================
3726 template<unsigned DIM, unsigned NNODE_1D>
3728 {
3729 };
3730
3731
3732 //=======================================================================
3733 /// SolidTElement elements, specialised to one spatial dimension
3734 //=======================================================================
3735 template<unsigned NNODE_1D>
3736 class SolidTElement<1, NNODE_1D> : public virtual TElement<1, NNODE_1D>,
3737 public virtual TSolidElementBase
3738 {
3739 public:
3740 /// Constructor
3742 {
3743 // Set the Lagrangian dimension of the element
3744 set_lagrangian_dimension(1);
3745 }
3746
3747 /// Broken copy constructor
3749
3750 /// Broken assignment operator
3751 /*void operator=(const SolidTElement&) = delete;*/
3752
3753 /// Build the lower-dimensional FaceElement (an element of type
3754 /// SolidPointElement). The face index takes two values
3755 /// corresponding to the two possible faces:
3756 /// -1 (Left) s[0] = -1.0
3757 /// +1 (Right) s[0] = 1.0
3758 inline void build_face_element(const int& face_index,
3759 FaceElement* face_element_pt);
3760 };
3761
3762
3763 /// ////////////////////////////////////////////////////////////////////////
3764 /// ////////////////////////////////////////////////////////////////////////
3765 // SolidTElements
3766 /// ////////////////////////////////////////////////////////////////////////
3767 /// ////////////////////////////////////////////////////////////////////////
3768
3769
3770 /// ////////////////////////////////////////////////////////////////////////
3771 // 1D SolidTElements
3772 /// ////////////////////////////////////////////////////////////////////////
3773
3774
3775 //===========================================================
3776 /// Function to setup geometrical information for lower-dimensional
3777 /// FaceElements (which are of type SolidTElement<0,1>).
3778 //===========================================================
3779 template<unsigned NNODE_1D>
3781 const int& face_index, FaceElement* face_element_pt)
3782 {
3783 // Build the standard non-solid FaceElement
3784 TElement<1, NNODE_1D>::build_face_element(face_index, face_element_pt);
3785
3786 // Set the Lagrangian dimension from the first node of the present element
3787 dynamic_cast<SolidFiniteElement*>(face_element_pt)
3788 ->set_lagrangian_dimension(
3789 static_cast<SolidNode*>(node_pt(0))->nlagrangian());
3790 }
3791
3792
3793 //=======================================================================
3794 /// SolidTElement elements, specialised to two spatial dimensions
3795 //=======================================================================
3796 template<unsigned NNODE_1D>
3797 class SolidTElement<2, NNODE_1D> : public virtual TElement<2, NNODE_1D>,
3798 public virtual TSolidElementBase
3799 {
3800 public:
3801 /// Constructor
3803 : TElementBase(),
3804 TElement<2, NNODE_1D>(),
3807 {
3808 // Set the Lagrangian dimension of the element
3809 set_lagrangian_dimension(2);
3810 }
3811
3812 /// Broken copy constructor
3814
3815 /// Broken assignment operator
3816 /*void operator=(const SolidTElement&) = delete;*/
3817
3818 /// Build the lower-dimensional FaceElement (an element of type
3819 /// SolidTElement<1,NNODE_1D>). The face index takes three possible values:
3820 /// 0 (Left) s[0] = 0.0
3821 /// 1 (Bottom) s[1] = 0.0
3822 /// 2 (Sloping face) s[0] = 1.0 - s[1]
3823 inline void build_face_element(const int& face_index,
3824 FaceElement* face_element_pt);
3825 };
3826
3827
3828 /// ////////////////////////////////////////////////////////////////////////
3829 /// ////////////////////////////////////////////////////////////////////////
3830 // 2D SolidTElements
3831 /// ////////////////////////////////////////////////////////////////////////
3832 /// ////////////////////////////////////////////////////////////////////////
3833
3834
3835 //===========================================================
3836 /// Function to setup geometrical information for lower-dimensional
3837 /// FaceElements (which are of type SolidTElement<1,NNODE_1D>).
3838 //===========================================================
3839 template<unsigned NNODE_1D>
3841 const int& face_index, FaceElement* face_element_pt)
3842 {
3843 // Build the standard non-solid FaceElement
3844 TElement<2, NNODE_1D>::build_face_element(face_index, face_element_pt);
3845
3846 // Set the Lagrangian dimension from the first node of the present element
3847 dynamic_cast<SolidFiniteElement*>(face_element_pt)
3848 ->set_lagrangian_dimension(
3849 static_cast<SolidNode*>(node_pt(0))->nlagrangian());
3850 }
3851
3852
3853 //=======================================================================
3854 /// SolidTElement elements, specialised to three spatial dimensions
3855 //=======================================================================
3856 template<unsigned NNODE_1D>
3857 class SolidTElement<3, NNODE_1D> : public virtual TElement<3, NNODE_1D>,
3858 public virtual TSolidElementBase
3859 {
3860 public:
3861 /// Constructor
3863 : TElementBase(),
3864 TElement<3, NNODE_1D>(),
3867 {
3868 // Set the Lagrangian dimension of the element
3869 set_lagrangian_dimension(3);
3870 }
3871
3872 /// Broken copy constructor
3874
3875 /// Broken assignment operator
3876 /*void operator=(const SolidTElement&) = delete;*/
3877
3878
3879 /// Build the lower-dimensional FaceElement (an element of type
3880 /// SolidTElement<2,NNODE_1D>). The face index can take one of four values
3881 /// corresponding to the four possible faces:
3882 /// 0: (left) s[0] = 0.0
3883 /// 1: (bottom) s[1] = 0.0
3884 /// 2: (back) s[2] = 0.0
3885 /// 3: (sloping face) s[0] + s[1] + s[2] = 1
3886 inline void build_face_element(const int& face_index,
3887 FaceElement* face_element_pt);
3888 };
3889
3890
3891 /// ////////////////////////////////////////////////////////////////////////
3892 // 3D SolidTElements
3893 /// ////////////////////////////////////////////////////////////////////////
3894
3895
3896 //===========================================================
3897 /// Function to setup geometrical information for lower-dimensional
3898 /// FaceElements (which are of type SolidTElement<1,NNODE_1D>).
3899 //===========================================================
3900 template<unsigned NNODE_1D>
3902 const int& face_index, FaceElement* face_element_pt)
3903 {
3904 // Build the standard non-solid FaceElement
3905 TElement<3, NNODE_1D>::build_face_element(face_index, face_element_pt);
3906
3907 // Set the Lagrangian dimension from the first node of the present element
3908 dynamic_cast<SolidFiniteElement*>(face_element_pt)
3909 ->set_lagrangian_dimension(
3910 static_cast<SolidNode*>(node_pt(0))->nlagrangian());
3911 }
3912
3913
3914 /// ////////////////////////////////////////////////////////////////////
3915 /// ////////////////////////////////////////////////////////////////////
3916 /// ////////////////////////////////////////////////////////////////////
3917
3918 //=======================================================================
3919 /// SolidTBubbleEnrichedElement elements are the enriched version
3920 /// of the SolidTElements. They will simply inherit from the appropriate
3921 /// SolidTElement and TBubblEnrichedElement.
3922 /// They are the basis for solid mechanics elements.
3923 //=======================================================================
3924 template<unsigned DIM, unsigned NNODE_1D>
3926 {
3927 };
3928
3929 //===================================================================
3930 /// Specify the SolidTBubbleEnrichedElement corresponding to the
3931 /// quadratic triangle
3932 //===================================================================
3933 template<unsigned DIM>
3935 : public virtual SolidTElement<DIM, 3>,
3936 public virtual TBubbleEnrichedElement<DIM, 3>
3937 {
3938 public:
3939 /// Constructor
3941 : SolidTElement<DIM, 3>(), TBubbleEnrichedElement<DIM, 3>()
3942 {
3943 }
3944
3945 /// Broken copy constructor
3947
3948 /// Broken assignment operator
3949 /*void operator=(const SolidTBubbleEnrichedElement&) = delete;*/
3950
3951 /// Destructor
3953
3954 /// Build the lower-dimensional FaceElement
3955 /// Need to put in a final override here
3956 void build_face_element(const int& face_index,
3957 FaceElement* face_element_pt);
3958 };
3959
3960
3961 //=======================================================================
3962 /// Face geometry for the TElement elements: The spatial
3963 /// dimension of the face elements is one lower than that of the
3964 /// bulk element but they have the same number of points
3965 /// along their 1D edges.
3966 //=======================================================================
3967 template<unsigned DIM, unsigned NNODE_1D>
3968 class FaceGeometry<TElement<DIM, NNODE_1D>>
3969 : public virtual TElement<DIM - 1, NNODE_1D>
3970 {
3971 public:
3972 /// Constructor: Call the constructor for the
3973 /// appropriate lower-dimensional QElement
3974 FaceGeometry() : TElement<DIM - 1, NNODE_1D>() {}
3975 };
3976
3977
3978 //=======================================================================
3979 /// Face geometry for the 1D TElement elements: Point elements
3980 //=======================================================================
3981 template<unsigned NNODE_1D>
3982 class FaceGeometry<TElement<1, NNODE_1D>> : public virtual PointElement
3983 {
3984 public:
3985 /// Constructor: Call the constructor for the
3986 /// appropriate lower-dimensional TElement
3988 };
3989
3990
3991 /// ////////////////////////////////////////////////////////////////////
3992 /// ////////////////////////////////////////////////////////////////////
3993 /// ////////////////////////////////////////////////////////////////////
3994
3995
3996 //=======================================================================
3997 /// Face geometry for the 2D TBubbleEnrichedElement elements is exactly
3998 /// the same as for the corresponding TElement. The spatial
3999 /// dimension of the face elements is one lower than that of the
4000 /// bulk element but they have the same number of points
4001 /// along their 1D edges.
4002 //=======================================================================
4003 template<unsigned NNODE_1D>
4005 : public virtual TElement<1, NNODE_1D>
4006 {
4007 public:
4008 /// Constructor: Call the constructor for the
4009 /// appropriate lower-dimensional QElement
4010 FaceGeometry() : TElement<1, NNODE_1D>() {}
4011 };
4012
4013
4014 //=======================================================================
4015 /// Face geometry for the 3D TBubbleEnrichedElement elements is the
4016 /// 2D TBubbleEnrichedElement. The spatial
4017 /// dimension of the face elements is one lower than that of the
4018 /// bulk element but they have the same number of points
4019 /// along their 1D edges.
4020 //=======================================================================
4021 template<unsigned NNODE_1D>
4023 : public virtual TBubbleEnrichedElement<2, NNODE_1D>
4024 {
4025 public:
4026 /// Constructor: Call the constructor for the
4027 /// appropriate lower-dimensional QElement
4029 };
4030
4031
4032 /// ////////////////////////////////////////////////////////////////////
4033 /// ////////////////////////////////////////////////////////////////////
4034 /// ////////////////////////////////////////////////////////////////////
4035
4036
4037 //=======================================================================
4038 /// Face geometry for the TElement elements: The spatial
4039 /// dimension of the face elements is one lower than that of the
4040 /// bulk element but they have the same number of points
4041 /// along their 1D edges.
4042 //=======================================================================
4043 template<unsigned DIM, unsigned NNODE_1D>
4044 class FaceGeometry<SolidTElement<DIM, NNODE_1D>>
4045 : public virtual SolidTElement<DIM - 1, NNODE_1D>
4046 {
4047 public:
4048 /// Constructor: Call the constructor for the
4049 /// appropriate lower-dimensional QElement
4050 FaceGeometry() : SolidTElement<DIM - 1, NNODE_1D>() {}
4051 };
4052
4053
4054 //=======================================================================
4055 /// Face geometry for the 1D TElement elements: Point elements
4056 //=======================================================================
4057 template<unsigned NNODE_1D>
4058 class FaceGeometry<SolidTElement<1, NNODE_1D>>
4059 : public virtual SolidPointElement
4060 {
4061 public:
4062 /// Constructor: Call the constructor for the
4063 /// appropriate lower-dimensional TElement
4065 };
4066
4067
4068 /// ////////////////////////////////////////////////////////////////////
4069 /// ////////////////////////////////////////////////////////////////////
4070 /// ////////////////////////////////////////////////////////////////////
4071
4072
4073 //=======================================================================
4074 /// Face geometry for the 2D SolidTBubbleEnrichedElement elements is exactly
4075 /// the same as for the corresponding 2D SolidTElement. The spatial
4076 /// dimension of the face elements is one lower than that of the
4077 /// bulk element but they have the same number of points
4078 /// along their 1D edges.
4079 //=======================================================================
4080 template<unsigned NNODE_1D>
4082 : public virtual SolidTElement<1, NNODE_1D>
4083 {
4084 public:
4085 /// Constructor: Call the constructor for the
4086 /// appropriate lower-dimensional QElement
4087 FaceGeometry() : SolidTElement<1, NNODE_1D>() {}
4088 };
4089
4090
4091 //=======================================================================
4092 /// Face geometry for the 3D SolidTBubbleEnrichedElement elements is
4093 /// the 2D SolidTBubbleEnrichedElement. The spatial
4094 /// dimension of the face elements is one lower than that of the
4095 /// bulk element but they have the same number of points
4096 /// along their 1D edges.
4097 //=======================================================================
4098 template<unsigned NNODE_1D>
4100 : public virtual SolidTBubbleEnrichedElement<2, NNODE_1D>
4101 {
4102 public:
4103 /// Constructor: Call the constructor for the
4104 /// appropriate lower-dimensional QElement
4106 };
4107
4108} // namespace oomph
4109
4110
4111#endif
static char t char * s
Definition: cfortran.h:568
cstr elem_len * i
Definition: cfortran.h:603
A class that contains the information required by Nodes that are located on Mesh boundaries....
Definition: nodes.h:1996
A Class for the derivatives of shape functions The class design is essentially the same as Shape,...
Definition: shape.h:278
FaceElements are elements that coincide with the faces of higher-dimensional "bulk" elements....
Definition: elements.h:4338
FaceGeometry()
Constructor: Call the constructor for the appropriate lower-dimensional QElement.
Definition: Telements.h:4087
FaceGeometry()
Constructor: Call the constructor for the appropriate lower-dimensional QElement.
Definition: Telements.h:4105
FaceGeometry()
Constructor: Call the constructor for the appropriate lower-dimensional TElement.
Definition: Telements.h:4064
FaceGeometry()
Constructor: Call the constructor for the appropriate lower-dimensional QElement.
Definition: Telements.h:4050
FaceGeometry()
Constructor: Call the constructor for the appropriate lower-dimensional QElement.
Definition: Telements.h:4010
FaceGeometry()
Constructor: Call the constructor for the appropriate lower-dimensional QElement.
Definition: Telements.h:4028
FaceGeometry()
Constructor: Call the constructor for the appropriate lower-dimensional TElement.
Definition: Telements.h:3987
FaceGeometry()
Constructor: Call the constructor for the appropriate lower-dimensional QElement.
Definition: Telements.h:3974
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
Definition: elements.h:4998
A general Finite Element class.
Definition: elements.h:1313
unsigned dim() const
Return the spatial dimension of the element, i.e. the number of local coordinates required to paramet...
Definition: elements.h:2611
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:906
virtual bool is_on_boundary() const
Test whether the Node lies on a boundary. The "bulk" Node cannot lie on a boundary,...
Definition: nodes.h:1373
virtual void get_boundaries_pt(std::set< unsigned > *&boundaries_pt)
Return a pointer to set of mesh boundaries that this node occupies; this will be overloaded by Bounda...
Definition: nodes.h:1365
An OomphLibError object which should be thrown when an run-time error is encountered....
/////////////////////////////////////////////////////////////////////// /////////////////////////////...
Definition: elements.h:3439
A Class for shape functions. In simple cases, the shape functions have only one index that can be tho...
Definition: shape.h:76
////////////////////////////////////////////////////////////////////// //////////////////////////////...
Definition: elements.h:3561
A Class for nodes that deform elastically (i.e. position is an unknown in the problem)....
Definition: nodes.h:1686
unsigned nlagrangian() const
Return number of lagrangian coordinates.
Definition: nodes.h:1870
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
Definition: elements.h:4980
SolidTBubbleEnrichedElement(const SolidTBubbleEnrichedElement &)=delete
Broken copy constructor.
void build_face_element(const int &face_index, FaceElement *face_element_pt)
Build the lower-dimensional FaceElement Need to put in a final override here.
~SolidTBubbleEnrichedElement()
Broken assignment operator.
Definition: Telements.h:3952
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
Definition: Telements.h:3926
SolidTElement(const SolidTElement &)=delete
Broken copy constructor.
SolidTElement(const SolidTElement &)=delete
Broken copy constructor.
SolidTElement(const SolidTElement &)=delete
Broken copy constructor.
/////////////////////////////////////////////////////////////////////// /////////////////////////////...
Definition: Telements.h:3728
unsigned n_enriched_nodes()
Return the number of nodes required for enrichement.
Definition: Telements.h:921
void d2shape_local(const Vector< double > &s, Shape &psi, DShape &dpsids, DShape &d2psids) const
Second derivatives of shape functions for specific TBubbleElement<2,3>: d2psids(i,...
Definition: Telements.h:1049
void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Derivatives of shape functions for specific TBubbleElement<2,3>
Definition: Telements.h:1015
void shape(const Vector< double > &s, Shape &psi) const
Shape function for specific TBubbleEnrichedElement<2,3>
Definition: Telements.h:987
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Return local coordinates of node j.
Definition: Telements.h:929
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Definition: Telements.h:2320
void d2shape_local(const Vector< double > &s, Shape &psi, DShape &dpsids, DShape &d2psids) const
Second derivatives of shape functions for specific TElement<3,3>: d2psids(i,0) = d2psids(i,...
Definition: Telements.h:2689
void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Derivatives of shape functions for specific TElement<3,3>
Definition: Telements.h:2494
void shape(const Vector< double > &s, Shape &psi) const
Shape function for specific TBubbleEnrichedElement<3,3>
Definition: Telements.h:2438
A class for those member functions that must be fully specialised for Telements that are enriched by ...
Definition: Telements.h:901
TBubbleEnrichedElement(const TBubbleEnrichedElement &)=delete
Broken copy constructor.
void build_face_element(const int &face_index, FaceElement *face_element_pt)
Build the lower-dimensional FaceElement.
void shape(const Vector< double > &s, Shape &psi) const
Calculate the geometric shape functions at local coordinate s.
Definition: Telements.h:3655
~TBubbleEnrichedElement()
Broken assignment operator.
Definition: Telements.h:3652
void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Compute the geometric shape functions and derivatives w.r.t. local coordinates at local coordinate s.
Definition: Telements.h:3662
static TBubbleEnrichedGauss< DIM, 3 > Default_enriched_integration_scheme
Definition: Telements.h:3627
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Return local coordinates of node j.
Definition: Telements.h:3685
void d2shape_local(const Vector< double > &s, Shape &psi, DShape &dpsids, DShape &d2psids) const
Compute the geometric shape functions, derivatives and second derivatives w.r.t local coordinates at ...
Definition: Telements.h:3675
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
Definition: Telements.h:3570
const unsigned Central_node_on_face[3]
Definition: Telements.cc:865
Define integration schemes that are required to exactly integrate the mass matrices of the bubble-enr...
Definition: Telements.h:3581
/////////////////////////////////////////////////////////////////// /////////////////////////////////...
Definition: Telements.h:1130
void move_local_coord_back_into_element(Vector< double > &s) const
Adjust local coordinates so that they're located inside the element.
Definition: Telements.h:1175
TElementBase()
Empty default constructor.
Definition: Telements.h:1133
ElementGeometry::ElementGeometry element_geometry() const
Broken assignment operator.
Definition: Telements.h:1142
TElementBase(const TElementBase &)=delete
Broken copy constructor.
bool local_coord_is_valid(const Vector< double > &s)
Check whether the local coordinates are valid or not.
Definition: Telements.h:1148
/////////////////////////////////////////////////////////////////// /////////////////////////////////...
Definition: Telements.h:1102
TElementGeometricBase(const TElementGeometricBase &)=delete
Broken copy constructor.
TElementGeometricBase()
Empty default constructor.
Definition: Telements.h:1105
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Return local coordinates of node j.
Definition: Telements.h:242
void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Derivatives of shape functions for specific TElement<2,2>
Definition: Telements.h:281
void shape(const Vector< double > &s, Shape &psi) const
Shape function for specific TElement<1,2>
Definition: Telements.h:271
void d2shape_local(const Vector< double > &s, Shape &psi, DShape &dpsids, DShape &d2psids) const
Second derivatives of shape functions for specific TElement<1,2>: d2psids(i,0) = .
Definition: Telements.h:295
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Return local coordinates of node j.
Definition: Telements.h:315
void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Derivatives of shape functions for specific TElement<1,3>
Definition: Telements.h:359
void d2shape_local(const Vector< double > &s, Shape &psi, DShape &dpsids, DShape &d2psids) const
Second derivatives of shape functions for specific TElement<1,3>: d2psids(i,0) = .
Definition: Telements.h:374
void shape(const Vector< double > &s, Shape &psi) const
Shape function for specific TElement<1,3>
Definition: Telements.h:348
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Return local coordinates of node j.
Definition: Telements.h:395
void shape(const Vector< double > &s, Shape &psi) const
Shape function for specific TElement<1,4>
Definition: Telements.h:432
void d2shape_local(const Vector< double > &s, Shape &psi, DShape &dpsids, DShape &d2psids) const
Second derivatives of shape functions for specific TElement<2,4>: d2psids(i,0) = .
Definition: Telements.h:458
void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Derivatives of shape functions for specific TElement<1,4>
Definition: Telements.h:443
void shape(const Vector< double > &s, Shape &psi) const
Shape function for specific TElement<2,2>
Definition: Telements.h:521
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Return local coordinates of node j.
Definition: Telements.h:484
void d2shape_local(const Vector< double > &s, Shape &psi, DShape &dpsids, DShape &d2psids) const
Second derivatives of shape functions for specific TElement<2,2>: d2psids(i,0) = d2psids(i,...
Definition: Telements.h:552
void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Derivatives of shape functions for specific TElement<2,2>
Definition: Telements.h:532
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Return local coordinates of node j.
Definition: Telements.h:575
void shape(const Vector< double > &s, Shape &psi) const
Shape function for specific TElement<2,3>
Definition: Telements.h:627
void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Derivatives of shape functions for specific TElement<2,3>
Definition: Telements.h:647
void d2shape_local(const Vector< double > &s, Shape &psi, DShape &dpsids, DShape &d2psids) const
Second derivatives of shape functions for specific TElement<2,3>: d2psids(i,0) = d2psids(i,...
Definition: Telements.h:673
void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Derivatives of shape functions for specific TElement<2,4>
Definition: Telements.h:805
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Return local coordinates of node j.
Definition: Telements.h:714
void shape(const Vector< double > &s, Shape &psi) const
Shape function for specific TElement<2,4>
Definition: Telements.h:786
void d2shape_local(const Vector< double > &s, Shape &psi, DShape &dpsids, DShape &d2psids) const
Second derivatives of shape functions for specific TElement<2,4>: d2psids(i,0) = d2psids(i,...
Definition: Telements.h:846
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Definition: Telements.h:1932
void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Derivatives of shape functions for specific TElement<3,2>
Definition: Telements.h:1990
void d2shape_local(const Vector< double > &s, Shape &psi, DShape &dpsids, DShape &d2psids) const
Second derivatives of shape functions for specific TElement<3,2>: d2psids(i,0) = d2psids(i,...
Definition: Telements.h:2023
void shape(const Vector< double > &s, Shape &psi) const
Shape function for specific TElement<3,2>
Definition: Telements.h:1978
void shape(const Vector< double > &s, Shape &psi) const
Shape function for specific TElement<3,3>
Definition: Telements.h:2133
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Definition: Telements.h:2051
void d2shape_local(const Vector< double > &s, Shape &psi, DShape &dpsids, DShape &d2psids) const
Second derivatives of shape functions for specific TElement<3,3>: d2psids(i,0) = d2psids(i,...
Definition: Telements.h:2211
void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Derivatives of shape functions for specific TElement<3,3>
Definition: Telements.h:2152
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
Definition: Telements.h:229
void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Compute the geometric shape functions and derivatives w.r.t. local coordinates at local coordinate s.
Definition: Telements.h:1322
std::string tecplot_zone_string(const unsigned &nplot) const
Return string for tecplot zone header (when plotting nplot points in each "coordinate direction)
Definition: Telements.h:1472
unsigned nvertex_node() const
Number of vertex nodes in the element: One more than spatial dimension.
Definition: Telements.h:1282
unsigned nplot_points(const unsigned &nplot) const
Return total number of plot points (when plotting nplot points in each "coordinate direction)
Definition: Telements.h:1481
void d2shape_local(const Vector< double > &s, Shape &psi, DShape &dpsids, DShape &d2psids) const
Compute the geometric shape functions, derivatives and second derivatives w.r.t local coordinates at ...
Definition: Telements.h:1334
void get_s_plot(const unsigned &i, const unsigned &nplot, Vector< double > &s, const bool &use_equally_spaced_interior_sample_points=false) const
Get vector of local coordinates of plot point i (when plotting nplot points in each "coordinate direc...
Definition: Telements.h:1446
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: Telements.h:1405
~TElement()
Broken assignment operator.
Definition: Telements.h:1271
double s_max() const
Max. value of local coordinate.
Definition: Telements.h:1358
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: Telements.h:1387
unsigned nsub_elements_paraview(const unsigned &nplot) const
Return the number of local sub-elements for paraview plot with parameter nplot.
Definition: Telements.h:1379
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....
Definition: Telements.h:1345
TElement(const TElement &)=delete
Broken copy constructor.
unsigned nnode_1d() const
Number of nodes along each element edge.
Definition: Telements.h:1274
void shape(const Vector< double > &s, Shape &psi) const
Calculate the geometric shape functions at local coordinate s.
Definition: Telements.h:1315
static TGauss< 1, NNODE_1D > Default_integration_scheme
Default integration rule: Gaussian integration of same 'order' as the element.
Definition: Telements.h:1228
double s_min() const
Min. value of local coordinate.
Definition: Telements.h:1352
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Return local coordinates of node j.
Definition: Telements.h:1364
Node * vertex_node_pt(const unsigned &j) const
Pointer to the j-th vertex node in the element.
Definition: Telements.h:1288
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: Telements.h:1418
unsigned nplot_points_paraview(const unsigned &nplot) const
Return the number of actual plot points for paraview plot with parameter nplot.
Definition: Telements.h:1372
General TElement class specialised to two spatial dimensions Ordering of nodes as in Zienkiwizc sketc...
Definition: Telements.h:1505
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: Telements.h:1737
unsigned nvertex_node() const
Number of vertex nodes in the element: One more than spatial dimension.
Definition: Telements.h:1592
double s_min() const
Min. value of local coordinate.
Definition: Telements.h:1661
void write_tecplot_zone_footer(std::ostream &outfile, const unsigned &nplot) const
Add tecplot zone "footer" to output stream (when plotting nplot points in each "coordinate direction)...
Definition: Telements.h:1838
void shape(const Vector< double > &s, Shape &psi) const
Calculate the geometric shape functions at local coordinate s.
Definition: Telements.h:1624
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: Telements.h:1752
std::string tecplot_zone_string(const unsigned &nplot) const
Return string for tecplot zone header (when plotting nplot points in each "coordinate direction)
Definition: Telements.h:1821
unsigned nplot_points_paraview(const unsigned &nplot) const
Return the number of actual plot points for paraview plot with parameter nplot.
Definition: Telements.h:1681
double s_max() const
Max. value of local coordinate.
Definition: Telements.h:1667
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: Telements.h:1706
~TElement()
Broken assignment operator.
Definition: Telements.h:1582
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....
Definition: Telements.h:1654
void get_s_plot(const unsigned &iplot, const unsigned &nplot, Vector< double > &s, const bool &use_equally_spaced_interior_sample_points=false) const
Get vector of local coordinates of plot point i (when plotting nplot points in each "coordinate direc...
Definition: Telements.h:1781
Node * vertex_node_pt(const unsigned &j) const
Pointer to the j-th vertex node in the element.
Definition: Telements.h:1605
void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Compute the geometric shape functions and derivatives w.r.t. local coordinates at local coordinate s.
Definition: Telements.h:1631
static TGauss< 2, NNODE_1D > Default_integration_scheme
Default integration rule: Gaussian integration of same 'order' as the element.
Definition: Telements.h:1515
void d2shape_local(const Vector< double > &s, Shape &psi, DShape &dpsids, DShape &d2psids) const
Compute the geometric shape functions, derivatives and second derivatives w.r.t local coordinates at ...
Definition: Telements.h:1643
unsigned nsub_elements_paraview(const unsigned &nplot) const
Return the number of local sub-elements for paraview plot with parameter nplot.
Definition: Telements.h:1693
unsigned nnode_1d() const
Number of nodes along each element edge.
Definition: Telements.h:1585
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Return local coordinates of node j.
Definition: Telements.h:1673
unsigned nplot_points(const unsigned &nplot) const
Return total number of plot points (when plotting nplot points in each "coordinate direction)
Definition: Telements.h:1899
void write_tecplot_zone_footer(FILE *file_pt, const unsigned &nplot) const
Add tecplot zone "footer" to C-style output. (when plotting nplot points in each "coordinate directio...
Definition: Telements.h:1867
unsigned get_bulk_node_number(const int &face_index, const unsigned &i) const
Public access function for Node_on_face.
Definition: Telements.h:1598
TElement(const TElement &)=delete
Broken copy constructor.
TElement(const bool &allow_high_order)
Alternative constructor.
Definition: Telements.h:1551
unsigned get_bulk_node_number(const int &face_index, const unsigned &i) const
Public access function for Node_on_face.
Definition: Telements.h:3116
TElement(const TElement &)=delete
Broken copy constructor.
unsigned nnode_1d() const
Number of nodes along each element edge.
Definition: Telements.h:3102
double s_max() const
Max. value of local coordinate.
Definition: Telements.h:3188
static TGauss< 3, NNODE_1D > Default_integration_scheme
Default integration rule: Gaussian integration of same 'order' as the element.
Definition: Telements.h:3052
unsigned nsub_elements_paraview(const unsigned &nplot) const
Return the number of local sub-elements for paraview plot with parameter nplot.
Definition: Telements.h:3217
void write_tecplot_zone_footer(std::ostream &outfile, const unsigned &nplot) const
Add tecplot zone "footer" to output stream (when plotting nplot points in each "coordinate direction)...
Definition: Telements.h:3416
void d2shape_local(const Vector< double > &s, Shape &psi, DShape &dpsids, DShape &d2psids) const
Compute the geometric shape functions, derivatives and second derivatives w.r.t local coordinates at ...
Definition: Telements.h:3164
~TElement()
Broken assignment operator.
Definition: Telements.h:3099
unsigned nplot_points_paraview(const unsigned &nplot) const
Return the number of actual plot points for paraview plot with parameter nplot.
Definition: Telements.h:3202
std::string tecplot_zone_string(const unsigned &nplot) const
Return string for tecplot zone header (when plotting nplot points in each "coordinate direction)
Definition: Telements.h:3402
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: Telements.h:3225
Node * vertex_node_pt(const unsigned &j) const
Pointer to the j-th vertex node in the element.
Definition: Telements.h:3123
void write_tecplot_zone_footer(FILE *file_pt, const unsigned &nplot) const
Add tecplot zone "footer" to C-style output. (when plotting nplot points in each "coordinate directio...
Definition: Telements.h:3494
void shape(const Vector< double > &s, Shape &psi) const
Calculate the geometric shape functions at local coordinate s.
Definition: Telements.h:3142
unsigned nvertex_node() const
Number of vertex nodes in the element: One more than spatial dimension.
Definition: Telements.h:3110
unsigned nplot_points(const unsigned &nplot) const
Return total number of plot points (when plotting nplot points in each "coordinate direction)
Definition: Telements.h:3529
void local_coordinate_of_node(const unsigned &j, Vector< double > &s) const
Return local coordinates of node j.
Definition: Telements.h:3194
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: Telements.h:3315
double s_min() const
Min. value of local coordinate.
Definition: Telements.h:3182
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: Telements.h:3328
void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Compute the geometric shape functions and derivatives w.r.t. local coordinates at local coordinate s.
Definition: Telements.h:3149
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....
Definition: Telements.h:3175
void get_s_plot(const unsigned &iplot, const unsigned &nplot, Vector< double > &s, const bool &use_equally_spaced_interior_sample_points=false) const
Get vector of local coordinates of plot point i (when plotting nplot points in each "coordinate direc...
Definition: Telements.h:3354
General TElement class.
Definition: Telements.h:1208
const unsigned Node_on_face[3][2]
Assign the nodal translation schemes.
Definition: Telements.cc:272
//////////////////////////////////////////////////////////////////////// ////////////////////////////...
Definition: Telements.h:56
bool is_on_boundary() const
Test whether the face lies on a boundary. Relatively simple test, based on all vertices lying on (som...
Definition: Telements.h:158
Node * Node2_pt
Second vertex node.
Definition: Telements.h:208
Node * node3_pt() const
Access to the third vertex node.
Definition: Telements.h:100
Node * Node3_pt
Third vertex node.
Definition: Telements.h:211
void get_boundaries_pt(std::set< unsigned > *&boundaries_pt)
Access to pointer to set of mesh boundaries that this face occupies; NULL if the node is not on any b...
Definition: Telements.h:178
Node * node1_pt() const
Access to the first vertex node.
Definition: Telements.h:88
TFace(Node *node1_pt, Node *node2_pt, Node *node3_pt)
Constructor: Pass in the three vertex nodes.
Definition: Telements.h:59
Node * Node1_pt
First vertex node.
Definition: Telements.h:205
bool operator<(const TFace &other) const
Less-than operator.
Definition: Telements.h:121
bool is_boundary_face() const
Test whether the face is a boundary face, i.e. does it connnect three boundary nodes?
Definition: Telements.h:167
Node * node2_pt() const
Access to the second vertex node.
Definition: Telements.h:94
bool operator==(const TFace &other) const
Comparison operator.
Definition: Telements.h:106
Class for Gaussian integration rules for triangles/tets.
Definition: integral.h:626
Base class for Solid Telements.
Definition: Telements.h:3702
TSolidElementBase()
Constructor: Empty.
Definition: Telements.h:3705
TSolidElementBase(const TSolidElementBase &)=delete
Broken copy constructor.
void output()
Doc the command line arguments.
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn't been defined.
void shape(const double &s, double *Psi)
Definition for 1D Lagrange shape functions. The value of all the shape functions at the local coordin...
Definition: shape.h:564
//////////////////////////////////////////////////////////////////// ////////////////////////////////...