GooseFEM 1.4.1.dev2+g78f16df
Loading...
Searching...
No Matches
Element.h
Go to the documentation of this file.
1
9#ifndef GOOSEFEM_ELEMENT_H
10#define GOOSEFEM_ELEMENT_H
11
12#include "Allocate.h"
13#include "config.h"
14#include "detail.h"
15
16namespace GooseFEM {
17
21namespace Element {
22
34)
35{
36 size_t nelem = conn.shape(0);
37 size_t nne = conn.shape(1);
38 size_t ndim = nodevec.shape(1);
39
40 array_type::tensor<double, 3> elemvec = xt::empty<double>({nelem, nne, ndim});
41
42#pragma omp parallel for
43 for (size_t e = 0; e < nelem; ++e) {
44 for (size_t m = 0; m < nne; ++m) {
45 for (size_t i = 0; i < ndim; ++i) {
46 elemvec(e, m, i) = nodevec(conn(e, m), i);
47 }
48 }
49 }
50
51 return elemvec;
52}
53
66)
67{
68 size_t nelem = conn.shape(0);
69 size_t nne = conn.shape(1);
70 size_t ndim = elemvec.shape(2);
71 size_t nnode = xt::amax(conn)() + 1;
72
73 GOOSEFEM_ASSERT(elemvec.shape(0) == nelem);
74 GOOSEFEM_ASSERT(elemvec.shape(1) == nne);
75
76 array_type::tensor<double, 2> nodevec = xt::zeros<double>({nnode, ndim});
77
78 for (size_t e = 0; e < nelem; ++e) {
79 for (size_t m = 0; m < nne; ++m) {
80 for (size_t i = 0; i < ndim; ++i) {
81 nodevec(conn(e, m), i) += elemvec(e, m, i);
82 }
83 }
84 }
85
86 return nodevec;
87}
88
95template <class E>
96inline bool isSequential(const E& dofs)
97{
98 size_t ndof = xt::amax(dofs)() + 1;
99
100 array_type::tensor<int, 1> exists = xt::zeros<int>({ndof});
101
102 for (auto& i : dofs) {
103 exists[i]++;
104 }
105
106 for (auto& i : dofs) {
107 if (exists[i] == 0) {
108 return false;
109 }
110 }
111
112 return true;
113}
114
123{
124 GOOSEFEM_ASSERT(elemmat.shape(1) == elemmat.shape(2));
125
126 size_t nelem = elemmat.shape(0);
127 size_t N = elemmat.shape(1);
128
129 double eps = std::numeric_limits<double>::epsilon();
130
131#pragma omp parallel for
132 for (size_t e = 0; e < nelem; ++e) {
133 for (size_t i = 0; i < N; ++i) {
134 for (size_t j = 0; j < N; ++j) {
135 if (i != j) {
136 if (std::abs(elemmat(e, i, j)) > eps) {
137 return false;
138 }
139 }
140 }
141 }
142 }
143
144 return true;
145}
146
150template <class D>
152public:
156 using derived_type = D;
157
163 auto nelem() const
164 {
165 return derived_cast().m_nelem;
166 }
167
173 auto nne() const
174 {
175 return D::s_nne;
176 }
177
183 auto ndim() const
184 {
185 return D::s_ndim;
186 }
187
193 auto tdim() const
194 {
195 return D::s_tdim;
196 }
197
203 auto nip() const
204 {
205 return derived_cast().m_nip;
206 }
207
215 template <class T, class R>
216 void asTensor(const T& arg, R& ret) const
217 {
218 GOOSEFEM_ASSERT(xt::has_shape(arg, this->shape_qscalar()));
219 GooseFEM::asTensor(arg, ret);
220 }
221
228 template <size_t rank, class T>
229 auto AsTensor(const T& arg) const
230 {
231 return GooseFEM::AsTensor<rank>(arg, derived_cast().m_tdim);
232 }
233
241 template <class T>
242 auto AsTensor(size_t rank, const T& arg) const
243 {
244 return GooseFEM::AsTensor(rank, arg, derived_cast().m_tdim);
245 }
246
252 auto shape_elemvec() const -> std::array<size_t, 3>
253 {
254 return std::array<size_t, 3>{derived_cast().m_nelem, D::s_nne, D::s_ndim};
255 }
256
263 auto shape_elemvec(size_t arg) const -> std::array<size_t, 3>
264 {
265 return std::array<size_t, 3>{derived_cast().m_nelem, D::s_nne, arg};
266 }
267
273 auto shape_elemmat() const -> std::array<size_t, 3>
274 {
275 return std::array<size_t, 3>{
276 derived_cast().m_nelem, D::s_nne * D::s_ndim, D::s_nne * D::s_ndim
277 };
278 }
279
287 template <size_t rank = 0>
288 auto shape_qtensor() const -> std::array<size_t, 2 + rank>
289 {
290 std::array<size_t, 2 + rank> shape;
291 shape[0] = derived_cast().m_nelem;
292 shape[1] = derived_cast().m_nip;
293 std::fill(shape.begin() + 2, shape.end(), derived_cast().m_tdim);
294 return shape;
295 }
296
304 auto shape_qtensor(size_t rank) const -> std::vector<size_t>
305 {
306 std::vector<size_t> shape(2 + rank);
307 shape[0] = derived_cast().m_nelem;
308 shape[1] = derived_cast().m_nip;
309 std::fill(shape.begin() + 2, shape.end(), derived_cast().m_tdim);
310 return shape;
311 }
312
322 template <size_t trank>
323 auto shape_qtensor(size_t rank, size_t arg) const -> std::array<size_t, 2 + trank>
324 {
326 std::array<size_t, 2 + trank> shape;
327 shape[0] = derived_cast().m_nelem;
328 shape[1] = derived_cast().m_nip;
329 std::fill(shape.begin() + 2, shape.end(), arg);
330 return shape;
331 }
332
341 auto shape_qtensor(size_t rank, size_t arg) const -> std::vector<size_t>
342 {
343 std::vector<size_t> shape(2 + rank);
344 shape[0] = derived_cast().m_nelem;
345 shape[1] = derived_cast().m_nip;
346 std::fill(shape.begin() + 2, shape.end(), arg);
347 return shape;
348 }
349
354 auto shape_qscalar() const -> std::array<size_t, 2>
355 {
356 return std::array<size_t, 2>{derived_cast().m_nelem, derived_cast().m_nip};
357 }
358
363 auto shape_qvector() const -> std::array<size_t, 3>
364 {
365 return std::array<size_t, 3>{derived_cast().m_nelem, derived_cast().m_nip, D::s_tdim};
366 }
367
373 auto shape_qvector(size_t arg) const -> std::array<size_t, 3>
374 {
375 return std::array<size_t, 3>{derived_cast().m_nelem, derived_cast().m_nip, arg};
376 }
377
385 template <class R>
386 auto allocate_elemvec() const
387 {
389 }
390
398 template <class R>
400 {
402 ret.fill(val);
403 return ret;
404 }
405
413 template <class R>
414 auto allocate_elemmat() const
415 {
417 }
418
426 template <class R>
428 {
430 ret.fill(val);
431 return ret;
432 }
433
443 template <size_t rank = 0, class R>
448
458 template <size_t rank = 0, class R>
460 {
462 ret.fill(val);
463 return ret;
464 }
465
475 template <class R>
476 auto allocate_qtensor(size_t rank) const
477 {
478 return xt::xarray<R>::from_shape(this->shape_qtensor(rank));
479 }
480
490 template <class R>
491 auto allocate_qtensor(size_t rank, R val) const
492 {
493 auto ret = xt::xarray<R>::from_shape(this->shape_qtensor(rank));
494 ret.fill(val);
495 return ret;
496 }
497
505 template <class R>
506 auto allocate_qscalar() const
507 {
508 return this->allocate_qtensor<0, R>();
509 }
510
518 template <class R>
520 {
521 return this->allocate_qtensor<0, R>(val);
522 }
523
524private:
525 auto derived_cast() -> derived_type&
526 {
527 return *static_cast<derived_type*>(this);
528 }
529
530 auto derived_cast() const -> const derived_type&
531 {
532 return *static_cast<const derived_type*>(this);
533 }
534};
535
545template <class D>
547public:
552
563 template <class T>
564 void update_x(const T& x)
565 {
566 GOOSEFEM_ASSERT(xt::has_shape(x, derived_cast().m_x.shape()));
567 xt::noalias(derived_cast().m_x) = x;
568 derived_cast().compute_dN_impl();
569 }
570
575 auto GradN() const -> const array_type::tensor<double, 4>&
576 {
577 return derived_cast().m_dNx;
578 }
579
584 auto dV() const -> const array_type::tensor<double, 2>&
585 {
586 return derived_cast().m_vol;
587 }
588
597 template <class T>
599 {
600 size_t n = elemvec.shape(2);
602 derived_cast().interpQuad_vector_impl(elemvec, qvector);
603 return qvector;
604 }
605
612 template <class T, class R>
613 void interpQuad_vector(const T& elemvec, R& qvector) const
614 {
615 derived_cast().interpQuad_vector_impl(elemvec, qvector);
616 }
617
634 template <class T>
636 {
638 derived_cast().gradN_vector_impl(elemvec, qtensor);
639 return qtensor;
640 }
641
648 template <class T, class R>
649 void gradN_vector(const T& elemvec, R& qtensor) const
650 {
651 derived_cast().gradN_vector_impl(elemvec, qtensor);
652 }
653
666 template <class T>
668 {
670 derived_cast().gradN_vector_T_impl(elemvec, qtensor);
671 return qtensor;
672 }
673
680 template <class T, class R>
681 void gradN_vector_T(const T& elemvec, R& qtensor) const
682 {
683 derived_cast().gradN_vector_T_impl(elemvec, qtensor);
684 }
685
699 template <class T>
701 {
703 derived_cast().symGradN_vector_impl(elemvec, qtensor);
704 return qtensor;
705 }
706
713 template <class T, class R>
714 void symGradN_vector(const T& elemvec, R& qtensor) const
715 {
716 derived_cast().symGradN_vector_impl(elemvec, qtensor);
717 }
718
731 template <class T>
733 {
734 size_t n = qvector.shape(2);
736 derived_cast().int_N_vector_dV_impl(qvector, elemvec);
737 return elemvec;
738 }
739
746 template <class T, class R>
747 void int_N_vector_dV(const T& qvector, R& elemvec) const
748 {
749 derived_cast().int_N_vector_dV_impl(qvector, elemvec);
750 }
751
770 template <class T>
772 {
774 derived_cast().int_N_scalar_NT_dV_impl(qscalar, elemmat);
775 return elemmat;
776 }
777
784 template <class T, class R>
785 void int_N_scalar_NT_dV(const T& qscalar, R& elemmat) const
786 {
787 derived_cast().int_N_scalar_NT_dV_impl(qscalar, elemmat);
788 }
789
807 template <class T>
809 {
811 derived_cast().int_gradN_dot_tensor2_dV_impl(qtensor, elemvec);
812 return elemvec;
813 }
814
821 template <class T, class R>
823 {
824 derived_cast().int_gradN_dot_tensor2_dV_impl(qtensor, elemvec);
825 }
826
827 // Integral of the dot product
828 // elemmat(m*2+j, n*2+k) += dNdx(m,i) * qtensor(i,j,k,l) * dNdx(n,l) * dV
829
849 template <class T>
852 {
854 derived_cast().int_gradN_dot_tensor4_dot_gradNT_dV_impl(qtensor, elemmat);
855 return elemmat;
856 }
857
864 template <class T, class R>
866 {
867 derived_cast().int_gradN_dot_tensor4_dot_gradNT_dV_impl(qtensor, elemmat);
868 }
869
870protected:
875 {
876 derived_cast().compute_dN_impl();
877 }
878
879private:
880 auto derived_cast() -> derived_type&
881 {
882 return *static_cast<derived_type*>(this);
883 }
884
885 auto derived_cast() const -> const derived_type&
886 {
887 return *static_cast<const derived_type*>(this);
888 }
889
890 friend class QuadratureBase<D>;
891
892 template <class T, class R>
893 void interpQuad_vector_impl(const T& elemvec, R& qvector) const
894 {
895 size_t n = elemvec.shape(2);
896 GOOSEFEM_ASSERT(xt::has_shape(elemvec, this->shape_elemvec(n)));
897 GOOSEFEM_ASSERT(xt::has_shape(qvector, this->shape_qvector(n)));
898
899 auto nelem = derived_cast().m_nelem;
900 auto nip = derived_cast().m_nip;
901 auto& N = derived_cast().m_N;
902
903 qvector.fill(0.0);
904
905#pragma omp parallel for
906 for (size_t e = 0; e < nelem; ++e) {
907
908 auto fq = &elemvec(e, 0, 0);
909
910 for (size_t q = 0; q < nip; ++q) {
911
912 auto Nq = &N(q, 0);
913 auto tq = &qvector(e, q, 0);
914
915 for (size_t m = 0; m < D::s_nne; ++m) {
916 for (size_t i = 0; i < n; ++i) {
917 tq[i] += Nq[m] * fq[m * n + i];
918 }
919 }
920 }
921 }
922 }
923
924 template <class T, class R>
925 void gradN_vector_impl(const T& elemvec, R& qtensor) const
926 {
927 GOOSEFEM_ASSERT(xt::has_shape(elemvec, this->shape_elemvec()));
928 GOOSEFEM_ASSERT(xt::has_shape(qtensor, this->template shape_qtensor<2>()));
929
930 auto nelem = derived_cast().m_nelem;
931 auto nip = derived_cast().m_nip;
932 auto& dNx = derived_cast().m_dNx;
933
934 qtensor.fill(0.0);
935
936#pragma omp parallel for
937 for (size_t e = 0; e < nelem; ++e) {
938
939 auto ue = xt::adapt(&elemvec(e, 0, 0), xt::xshape<D::s_nne, D::s_ndim>());
940
941 for (size_t q = 0; q < nip; ++q) {
942
943 auto dNxq = xt::adapt(&dNx(e, q, 0, 0), xt::xshape<D::s_nne, D::s_ndim>());
944 auto graduq = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape<D::s_tdim, D::s_tdim>());
945
946 for (size_t m = 0; m < D::s_nne; ++m) {
947 for (size_t i = 0; i < D::s_ndim; ++i) {
948 for (size_t j = 0; j < D::s_ndim; ++j) {
949 graduq(i, j) += dNxq(m, i) * ue(m, j);
950 }
951 }
952 }
953 }
954 }
955 }
956
957 template <class T, class R>
958 void gradN_vector_T_impl(const T& elemvec, R& qtensor) const
959 {
960 GOOSEFEM_ASSERT(xt::has_shape(elemvec, this->shape_elemvec()));
961 GOOSEFEM_ASSERT(xt::has_shape(qtensor, this->template shape_qtensor<2>()));
962
963 auto nelem = derived_cast().m_nelem;
964 auto nip = derived_cast().m_nip;
965 auto& dNx = derived_cast().m_dNx;
966
967 qtensor.fill(0.0);
968
969#pragma omp parallel for
970 for (size_t e = 0; e < nelem; ++e) {
971
972 auto ue = xt::adapt(&elemvec(e, 0, 0), xt::xshape<D::s_nne, D::s_ndim>());
973
974 for (size_t q = 0; q < nip; ++q) {
975
976 auto dNxq = xt::adapt(&dNx(e, q, 0, 0), xt::xshape<D::s_nne, D::s_ndim>());
977 auto graduq = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape<D::s_tdim, D::s_tdim>());
978
979 for (size_t m = 0; m < D::s_nne; ++m) {
980 for (size_t i = 0; i < D::s_ndim; ++i) {
981 for (size_t j = 0; j < D::s_ndim; ++j) {
982 graduq(j, i) += dNxq(m, i) * ue(m, j);
983 }
984 }
985 }
986 }
987 }
988 }
989
990 template <class T, class R>
991 void symGradN_vector_impl(const T& elemvec, R& qtensor) const
992 {
993 GOOSEFEM_ASSERT(xt::has_shape(elemvec, this->shape_elemvec()));
994 GOOSEFEM_ASSERT(xt::has_shape(qtensor, this->template shape_qtensor<2>()));
995
996 auto nelem = derived_cast().m_nelem;
997 auto nip = derived_cast().m_nip;
998 auto& dNx = derived_cast().m_dNx;
999
1000 qtensor.fill(0.0);
1001
1002#pragma omp parallel for
1003 for (size_t e = 0; e < nelem; ++e) {
1004
1005 auto ue = xt::adapt(&elemvec(e, 0, 0), xt::xshape<D::s_nne, D::s_ndim>());
1006
1007 for (size_t q = 0; q < nip; ++q) {
1008
1009 auto dNxq = xt::adapt(&dNx(e, q, 0, 0), xt::xshape<D::s_nne, D::s_ndim>());
1010 auto epsq = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape<D::s_tdim, D::s_tdim>());
1011
1012 for (size_t m = 0; m < D::s_nne; ++m) {
1013 for (size_t i = 0; i < D::s_ndim; ++i) {
1014 for (size_t j = 0; j < D::s_ndim; ++j) {
1015 epsq(i, j) += 0.5 * dNxq(m, i) * ue(m, j);
1016 epsq(j, i) += 0.5 * dNxq(m, i) * ue(m, j);
1017 }
1018 }
1019 }
1020 }
1021 }
1022 }
1023
1024 template <class T, class R>
1025 void int_N_vector_dV_impl(const T& qvector, R& elemvec) const
1026 {
1027 size_t n = qvector.shape(2);
1028 GOOSEFEM_ASSERT(xt::has_shape(qvector, this->shape_qvector(n)));
1029 GOOSEFEM_ASSERT(xt::has_shape(elemvec, this->shape_elemvec(n)));
1030
1031 auto nelem = derived_cast().m_nelem;
1032 auto nip = derived_cast().m_nip;
1033 auto& N = derived_cast().m_N;
1034 auto& vol = derived_cast().m_vol;
1035
1036 elemvec.fill(0.0);
1037
1038#pragma omp parallel for
1039 for (size_t e = 0; e < nelem; ++e) {
1040
1041 auto f = &elemvec(e, 0, 0);
1042
1043 for (size_t q = 0; q < nip; ++q) {
1044
1045 auto Ne = &N(q, 0);
1046 auto tq = &qvector(e, q, 0);
1047 auto& volq = vol(e, q);
1048
1049 for (size_t m = 0; m < D::s_nne; ++m) {
1050 for (size_t i = 0; i < n; ++i) {
1051 f[m * n + i] += Ne[m] * tq[i] * volq;
1052 }
1053 }
1054 }
1055 }
1056 }
1057
1058 template <class T, class R>
1059 void int_N_scalar_NT_dV_impl(const T& qscalar, R& elemmat) const
1060 {
1061 GOOSEFEM_ASSERT(xt::has_shape(qscalar, this->shape_qscalar()));
1062 GOOSEFEM_ASSERT(xt::has_shape(elemmat, this->shape_elemmat()));
1063
1064 auto nelem = derived_cast().m_nelem;
1065 auto nip = derived_cast().m_nip;
1066 auto& N = derived_cast().m_N;
1067 auto& vol = derived_cast().m_vol;
1068
1069 elemmat.fill(0.0);
1070
1071#pragma omp parallel for
1072 for (size_t e = 0; e < nelem; ++e) {
1073
1074 auto Me = xt::adapt(
1075 &elemmat(e, 0, 0), xt::xshape<D::s_nne * D::s_ndim, D::s_nne * D::s_ndim>()
1076 );
1077
1078 for (size_t q = 0; q < nip; ++q) {
1079
1080 auto Ne = xt::adapt(&N(q, 0), xt::xshape<D::s_nne>());
1081 auto& volq = vol(e, q);
1082 auto& rho = qscalar(e, q);
1083
1084 // M(m * D::s_ndim + i, n * D::s_ndim + i) += N(m) * scalar * N(n) * dV
1085 for (size_t m = 0; m < D::s_nne; ++m) {
1086 for (size_t n = 0; n < D::s_nne; ++n) {
1087 for (size_t i = 0; i < D::s_ndim; ++i) {
1088 Me(m * D::s_ndim + i, n * D::s_ndim + i) += Ne(m) * rho * Ne(n) * volq;
1089 }
1090 }
1091 }
1092 }
1093 }
1094 }
1095
1096 template <class T, class R>
1097 void int_gradN_dot_tensor2_dV_impl(const T& qtensor, R& elemvec) const
1098 {
1099 GOOSEFEM_ASSERT(xt::has_shape(qtensor, this->template shape_qtensor<2>()));
1100 GOOSEFEM_ASSERT(xt::has_shape(elemvec, this->shape_elemvec()));
1101
1102 auto nelem = derived_cast().m_nelem;
1103 auto nip = derived_cast().m_nip;
1104 auto& dNx = derived_cast().m_m_dNx;
1105 auto& vol = derived_cast().m_vol;
1106
1107 elemvec.fill(0.0);
1108
1109#pragma omp parallel for
1110 for (size_t e = 0; e < nelem; ++e) {
1111
1112 auto fe = xt::adapt(&elemvec(e, 0, 0), xt::xshape<D::s_nne, D::s_ndim>());
1113
1114 for (size_t q = 0; q < nip; ++q) {
1115
1116 auto dNxq = xt::adapt(&dNx(e, q, 0, 0), xt::xshape<D::s_nne, D::s_ndim>());
1117 auto sigq = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape<D::s_tdim, D::s_tdim>());
1118 auto& volq = vol(e, q);
1119
1120 for (size_t m = 0; m < D::s_nne; ++m) {
1121 for (size_t i = 0; i < D::s_ndim; ++i) {
1122 for (size_t j = 0; j < D::s_ndim; ++j) {
1123 fe(m, j) += dNxq(m, i) * sigq(i, j) * volq;
1124 }
1125 }
1126 }
1127 }
1128 }
1129 }
1130
1131 template <class T, class R>
1132 void int_gradN_dot_tensor4_dot_gradNT_dV_impl(const T& qtensor, R& elemmat) const
1133 {
1134 GOOSEFEM_ASSERT(xt::has_shape(qtensor, this->template shape_qtensor<4>()));
1135 GOOSEFEM_ASSERT(xt::has_shape(elemmat, this->shape_elemmat()));
1136
1137 auto nelem = derived_cast().m_nelem;
1138 auto nip = derived_cast().m_nip;
1139 auto& dNx = derived_cast().m_dNx;
1140 auto& vol = derived_cast().m_vol;
1141
1142 elemmat.fill(0.0);
1143
1144#pragma omp parallel for
1145 for (size_t e = 0; e < nelem; ++e) {
1146
1147 auto K = xt::adapt(
1148 &elemmat(e, 0, 0), xt::xshape<D::s_nne * D::s_ndim, D::s_nne * D::s_ndim>()
1149 );
1150
1151 for (size_t q = 0; q < nip; ++q) {
1152
1153 auto dNxq = xt::adapt(&dNx(e, q, 0, 0), xt::xshape<D::s_nne, D::s_ndim>());
1154 auto Cq = xt::adapt(
1155 &qtensor(e, q, 0, 0, 0, 0),
1156 xt::xshape<D::s_tdim, D::s_tdim, D::s_tdim, D::s_tdim>()
1157 );
1158 auto& volq = vol(e, q);
1159
1160 for (size_t m = 0; m < D::s_nne; ++m) {
1161 for (size_t n = 0; n < D::s_nne; ++n) {
1162 for (size_t i = 0; i < D::s_ndim; ++i) {
1163 for (size_t j = 0; j < D::s_ndim; ++j) {
1164 for (size_t k = 0; k < D::s_ndim; ++k) {
1165 for (size_t l = 0; l < D::s_ndim; ++l) {
1166 K(m * D::s_ndim + j, n * D::s_ndim + k) +=
1167 dNxq(m, i) * Cq(i, j, k, l) * dNxq(n, l) * volq;
1168 }
1169 }
1170 }
1171 }
1172 }
1173 }
1174 }
1175 }
1176 }
1177
1178 void compute_dN_impl()
1179 {
1180 auto nelem = derived_cast().m_nelem;
1181 auto nip = derived_cast().m_nip;
1182 auto& vol = derived_cast().m_vol;
1183 auto& w = derived_cast().m_w;
1184 auto& dNxi = derived_cast().m_dNxi;
1185 auto& dNx = derived_cast().m_dNx;
1186 auto& x = derived_cast().m_x;
1187
1188 dNx.fill(0.0);
1189
1190#pragma omp parallel
1191 {
1192 auto J = array_type::tensor<double, 2>::from_shape({D::s_ndim, D::s_ndim});
1193 auto Jinv = array_type::tensor<double, 2>::from_shape({D::s_ndim, D::s_ndim});
1194
1195#pragma omp for
1196 for (size_t e = 0; e < nelem; ++e) {
1197
1198 auto xe = xt::adapt(&x(e, 0, 0), xt::xshape<D::s_nne, D::s_ndim>());
1199
1200 for (size_t q = 0; q < nip; ++q) {
1201
1202 auto dNxiq = xt::adapt(&dNxi(q, 0, 0), xt::xshape<D::s_nne, D::s_ndim>());
1203 auto dNxq = xt::adapt(&dNx(e, q, 0, 0), xt::xshape<D::s_nne, D::s_ndim>());
1204
1205 J.fill(0.0);
1206
1207 for (size_t m = 0; m < D::s_nne; ++m) {
1208 for (size_t i = 0; i < D::s_ndim; ++i) {
1209 for (size_t j = 0; j < D::s_ndim; ++j) {
1210 J(i, j) += dNxiq(m, i) * xe(m, j);
1211 }
1212 }
1213 }
1214
1215 double Jdet = detail::tensor<D::s_ndim>::inv(J, Jinv);
1216
1217 for (size_t m = 0; m < D::s_nne; ++m) {
1218 for (size_t i = 0; i < D::s_ndim; ++i) {
1219 for (size_t j = 0; j < D::s_ndim; ++j) {
1220 dNxq(m, i) += Jinv(i, j) * dNxiq(m, i);
1221 }
1222 }
1223 }
1224
1225 vol(e, q) = w(q) * Jdet;
1226 }
1227 }
1228 }
1229 }
1230};
1231
1232} // namespace Element
1233} // namespace GooseFEM
1234
1235#endif
Common allocation methods.
CRTP base class for interpolation and quadrature for a generic element in Cartesian coordinates.
Definition Element.h:546
auto Int_gradN_dot_tensor2_dV(const T &qtensor) const -> array_type::tensor< double, 3 >
Element-by-element: integral of the dot product of the shape function gradients with a second order t...
Definition Element.h:808
auto Int_N_scalar_NT_dV(const T &qscalar) const -> array_type::tensor< double, 3 >
Element-by-element: integral of the scalar product of the shape function with a scalar.
Definition Element.h:771
void gradN_vector(const T &elemvec, R &qtensor) const
Same as GradN_vector(), but writing to preallocated return.
Definition Element.h:649
auto SymGradN_vector(const T &elemvec) const -> array_type::tensor< double, 4 >
The symmetric output of GradN_vector().
Definition Element.h:700
void symGradN_vector(const T &elemvec, R &qtensor) const
Same as SymGradN_vector(), but writing to preallocated return.
Definition Element.h:714
void int_gradN_dot_tensor2_dV(const T &qtensor, R &elemvec) const
Same as Int_gradN_dot_tensor2_dV(), but writing to preallocated return.
Definition Element.h:822
auto InterpQuad_vector(const T &elemvec) const -> array_type::tensor< double, 3 >
Interpolate element vector and evaluate at each quadrature point.
Definition Element.h:598
void int_gradN_dot_tensor4_dot_gradNT_dV(const T &qtensor, R &elemmat) const
Same as Int_gradN_dot_tensor4_dot_gradNT_dV(), but writing to preallocated return.
Definition Element.h:865
auto dV() const -> const array_type::tensor< double, 2 > &
Integration volume.
Definition Element.h:584
void gradN_vector_T(const T &elemvec, R &qtensor) const
Same as GradN_vector_T(), but writing to preallocated return.
Definition Element.h:681
auto GradN_vector_T(const T &elemvec) const -> array_type::tensor< double, 4 >
The transposed output of GradN_vector().
Definition Element.h:667
void int_N_vector_dV(const T &qvector, R &elemvec) const
Same as Int_N_vector_dV(), but writing to preallocated return.
Definition Element.h:747
auto Int_gradN_dot_tensor4_dot_gradNT_dV(const T &qtensor) const -> array_type::tensor< double, 3 >
Element-by-element: integral of the dot products of the shape function gradients with a fourth order ...
Definition Element.h:850
auto GradN_vector(const T &elemvec) const -> array_type::tensor< double, 4 >
Element-by-element: dyadic product of the shape function gradients and a nodal vector.
Definition Element.h:635
void interpQuad_vector(const T &elemvec, R &qvector) const
Same as InterpQuad_vector(), but writing to preallocated return.
Definition Element.h:613
void compute_dN()
Update the shape function gradients (called when the nodal positions are updated).
Definition Element.h:874
void int_N_scalar_NT_dV(const T &qscalar, R &elemmat) const
Same as Int_N_scalar_NT_dV(), but writing to preallocated return.
Definition Element.h:785
void update_x(const T &x)
Update the nodal positions.
Definition Element.h:564
auto GradN() const -> const array_type::tensor< double, 4 > &
Shape function gradients (in global coordinates).
Definition Element.h:575
auto Int_N_vector_dV(const T &qvector) const -> array_type::tensor< double, 3 >
Element-by-element: integral of a continuous vector-field.
Definition Element.h:732
CRTP base class for quadrature.
Definition Element.h:151
auto shape_qscalar() const -> std::array< size_t, 2 >
Get the shape of a "qscalar" (a "qtensor" of rank 0)
Definition Element.h:354
auto shape_qtensor(size_t rank, size_t arg) const -> std::vector< size_t >
Get the shape of a "qtensor" of a certain rank (0 = scalar, 1, vector, 2 = 2nd-order tensor,...
Definition Element.h:341
auto shape_elemvec(size_t arg) const -> std::array< size_t, 3 >
Get the shape of an "elemvec".
Definition Element.h:263
auto shape_qvector() const -> std::array< size_t, 3 >
Get the shape of a "qvector" (a "qtensor" of rank 1)
Definition Element.h:363
auto nip() const
Number of integration points.
Definition Element.h:203
auto allocate_elemmat() const
Get an allocated array_type::tensor to store a "elemmat".
Definition Element.h:414
auto nelem() const
Number of elements.
Definition Element.h:163
auto nne() const
Number of nodes per element.
Definition Element.h:173
void asTensor(const T &arg, R &ret) const
Convert "qscalar" to "qtensor" of certain rank.
Definition Element.h:216
auto shape_qtensor() const -> std::array< size_t, 2+rank >
Get the shape of a "qtensor" of a certain rank (0 = scalar, 1, vector, 2 = 2nd-order tensor,...
Definition Element.h:288
auto allocate_elemvec() const
Get an allocated array_type::tensor to store a "elemvec".
Definition Element.h:386
auto shape_elemmat() const -> std::array< size_t, 3 >
Get the shape of an "elemmat".
Definition Element.h:273
auto allocate_elemvec(R val) const
Get an allocated and initialised xt::xarray to store a "elemvec".
Definition Element.h:399
auto shape_qvector(size_t arg) const -> std::array< size_t, 3 >
Get the shape of a "qvector" (a "qtensor" of rank 1)
Definition Element.h:373
auto allocate_elemmat(R val) const
Get an allocated and initialised xt::xarray to store a "elemmat".
Definition Element.h:427
auto shape_elemvec() const -> std::array< size_t, 3 >
Get the shape of an "elemvec".
Definition Element.h:252
auto allocate_qscalar(R val) const
Get an allocated and initialised xt::xarray to store a "qscalar" (a "qtensor" of rank 0).
Definition Element.h:519
auto AsTensor(const T &arg) const
Convert "qscalar" to "qtensor" of certain rank.
Definition Element.h:229
auto tdim() const
Number of dimensions for integration point tensors.
Definition Element.h:193
auto allocate_qtensor(size_t rank) const
Get an allocated xt::xarray to store a "qtensor" of a certain rank (0 = scalar, 1,...
Definition Element.h:476
auto shape_qtensor(size_t rank) const -> std::vector< size_t >
Get the shape of a "qtensor" of a certain rank (0 = scalar, 1, vector, 2 = 2nd-order tensor,...
Definition Element.h:304
auto allocate_qtensor() const
Get an allocated array_type::tensor to store a "qtensor" of a certain rank (0 = scalar,...
Definition Element.h:444
auto allocate_qtensor(size_t rank, R val) const
Get an allocated and initialised xt::xarray to store a "qtensor" of a certain rank (0 = scalar,...
Definition Element.h:491
auto shape_qtensor(size_t rank, size_t arg) const -> std::array< size_t, 2+trank >
Get the shape of a "qtensor" of a certain rank (0 = scalar, 1, vector, 2 = 2nd-order tensor,...
Definition Element.h:323
auto ndim() const
Number of dimensions for node vectors.
Definition Element.h:183
auto allocate_qscalar() const
Get an allocated array_type::tensor to store a "qscalar" (a "qtensor" of rank 0).
Definition Element.h:506
auto AsTensor(size_t rank, const T &arg) const
Convert "qscalar" to "qtensor" of certain rank.
Definition Element.h:242
auto allocate_qtensor(R val) const
Get an allocated and initialised array_type::tensor to store a "qtensor" of a certain rank (0 = scala...
Definition Element.h:459
D derived_type
Underlying type.
Definition Element.h:156
Basic configuration:
#define GOOSEFEM_ASSERT(expr)
All assertions are implementation as::
Definition config.h:97
array_type::tensor< double, 1 > w()
Integration point weights.
Definition ElementHex8.h:92
bool isDiagonal(const array_type::tensor< double, 3 > &elemmat)
Check that all of the matrices stored per elemmat (shape: [nelem, nne * ndim, nne * ndim]) are diagon...
Definition Element.h:122
array_type::tensor< double, 3 > asElementVector(const array_type::tensor< size_t, 2 > &conn, const array_type::tensor< double, 2 > &nodevec)
Convert nodal vector with ("nodevec", shape:[nnode, ndim]) to nodal vector stored per element ("elemv...
Definition Element.h:31
bool isSequential(const E &dofs)
Check that DOFs leave no holes.
Definition Element.h:96
array_type::tensor< double, 2 > assembleNodeVector(const array_type::tensor< size_t, 2 > &conn, const array_type::tensor< double, 3 > &elemvec)
Assemble nodal vector stored per element ("elemvec", shape [nelem, nne, ndim]) to nodal vector ("node...
Definition Element.h:63
xt::xtensor< T, N > tensor
Fixed (static) rank array.
Definition config.h:177
Toolbox to perform finite element computations.
Definition Allocate.h:14
auto AsTensor(const T &arg, const S &shape)
"Broadcast" a scalar stored in an array (e.g.
Definition Allocate.h:167
void asTensor(const T &arg, R &ret)
"Broadcast" a scalar stored in an array (e.g.
Definition Allocate.h:153