10#ifndef GOOSEFEM_ELEMENTQUAD4AXISYMMETRIC_H
11#define GOOSEFEM_ELEMENTQUAD4AXISYMMETRIC_H
72 template <
class T,
class X,
class W>
79 m_nelem = m_x.shape(0);
86 m_N = xt::empty<double>({m_nip, s_nne});
87 m_dNxi = xt::empty<double>({m_nip, s_nne, s_ndim});
88 m_B = xt::empty<double>({m_nelem, m_nip, s_nne, s_tdim, s_tdim, s_tdim});
91 for (
size_t q = 0; q < m_nip; ++q) {
92 m_N(q, 0) = 0.25 * (1.0 - m_xi(q, 0)) * (1.0 - m_xi(q, 1));
93 m_N(q, 1) = 0.25 * (1.0 + m_xi(q, 0)) * (1.0 - m_xi(q, 1));
94 m_N(q, 2) = 0.25 * (1.0 + m_xi(q, 0)) * (1.0 + m_xi(q, 1));
95 m_N(q, 3) = 0.25 * (1.0 - m_xi(q, 0)) * (1.0 + m_xi(q, 1));
98 for (
size_t q = 0; q < m_nip; ++q) {
100 m_dNxi(q, 0, 0) = -0.25 * (1.0 - m_xi(q, 1));
101 m_dNxi(q, 1, 0) = +0.25 * (1.0 - m_xi(q, 1));
102 m_dNxi(q, 2, 0) = +0.25 * (1.0 + m_xi(q, 1));
103 m_dNxi(q, 3, 0) = -0.25 * (1.0 + m_xi(q, 1));
105 m_dNxi(q, 0, 1) = -0.25 * (1.0 - m_xi(q, 0));
106 m_dNxi(q, 1, 1) = -0.25 * (1.0 + m_xi(q, 0));
107 m_dNxi(q, 2, 1) = +0.25 * (1.0 + m_xi(q, 0));
108 m_dNxi(q, 3, 1) = +0.25 * (1.0 - m_xi(q, 0));
111 this->compute_dN_impl();
132 template <
class T,
class R>
133 void gradN_vector_impl(
const T& elemvec, R& qtensor)
const
140#pragma omp parallel for
141 for (
size_t e = 0; e < m_nelem; ++e) {
143 auto u = xt::adapt(&elemvec(e, 0, 0), xt::xshape<s_nne, s_ndim>());
145 for (
size_t q = 0; q < m_nip; ++q) {
148 xt::adapt(&m_B(e, q, 0, 0, 0, 0), xt::xshape<s_nne, s_tdim, s_tdim, s_tdim>());
149 auto gradu = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape<s_tdim, s_tdim>());
153 gradu(0, 0) =
B(0, 0, 0, 0) * u(0, 1) +
B(1, 0, 0, 0) * u(1, 1) +
154 B(2, 0, 0, 0) * u(2, 1) +
B(3, 0, 0, 0) * u(3, 1);
155 gradu(1, 1) =
B(0, 1, 1, 0) * u(0, 1) +
B(1, 1, 1, 0) * u(1, 1) +
156 B(2, 1, 1, 0) * u(2, 1) +
B(3, 1, 1, 0) * u(3, 1);
157 gradu(2, 2) =
B(0, 2, 2, 2) * u(0, 0) +
B(1, 2, 2, 2) * u(1, 0) +
158 B(2, 2, 2, 2) * u(2, 0) +
B(3, 2, 2, 2) * u(3, 0);
159 gradu(0, 2) =
B(0, 0, 2, 2) * u(0, 0) +
B(1, 0, 2, 2) * u(1, 0) +
160 B(2, 0, 2, 2) * u(2, 0) +
B(3, 0, 2, 2) * u(3, 0);
161 gradu(2, 0) =
B(0, 2, 0, 0) * u(0, 1) +
B(1, 2, 0, 0) * u(1, 1) +
162 B(2, 2, 0, 0) * u(2, 1) +
B(3, 2, 0, 0) * u(3, 1);
167 template <
class T,
class R>
168 void gradN_vector_T_impl(
const T& elemvec, R& qtensor)
const
175#pragma omp parallel for
176 for (
size_t e = 0; e < m_nelem; ++e) {
178 auto u = xt::adapt(&elemvec(e, 0, 0), xt::xshape<s_nne, s_ndim>());
180 for (
size_t q = 0; q < m_nip; ++q) {
183 xt::adapt(&m_B(e, q, 0, 0, 0, 0), xt::xshape<s_nne, s_tdim, s_tdim, s_tdim>());
184 auto gradu = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape<s_tdim, s_tdim>());
188 gradu(0, 0) =
B(0, 0, 0, 0) * u(0, 1) +
B(1, 0, 0, 0) * u(1, 1) +
189 B(2, 0, 0, 0) * u(2, 1) +
B(3, 0, 0, 0) * u(3, 1);
190 gradu(1, 1) =
B(0, 1, 1, 0) * u(0, 1) +
B(1, 1, 1, 0) * u(1, 1) +
191 B(2, 1, 1, 0) * u(2, 1) +
B(3, 1, 1, 0) * u(3, 1);
192 gradu(2, 2) =
B(0, 2, 2, 2) * u(0, 0) +
B(1, 2, 2, 2) * u(1, 0) +
193 B(2, 2, 2, 2) * u(2, 0) +
B(3, 2, 2, 2) * u(3, 0);
194 gradu(2, 0) =
B(0, 0, 2, 2) * u(0, 0) +
B(1, 0, 2, 2) * u(1, 0) +
195 B(2, 0, 2, 2) * u(2, 0) +
B(3, 0, 2, 2) * u(3, 0);
196 gradu(0, 2) =
B(0, 2, 0, 0) * u(0, 1) +
B(1, 2, 0, 0) * u(1, 1) +
197 B(2, 2, 0, 0) * u(2, 1) +
B(3, 2, 0, 0) * u(3, 1);
202 template <
class T,
class R>
203 void symGradN_vector_impl(
const T& elemvec, R& qtensor)
const
210#pragma omp parallel for
211 for (
size_t e = 0; e < m_nelem; ++e) {
213 auto u = xt::adapt(&elemvec(e, 0, 0), xt::xshape<s_nne, s_ndim>());
215 for (
size_t q = 0; q < m_nip; ++q) {
218 xt::adapt(&m_B(e, q, 0, 0, 0, 0), xt::xshape<s_nne, s_tdim, s_tdim, s_tdim>());
219 auto eps = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape<s_tdim, s_tdim>());
224 eps(0, 0) =
B(0, 0, 0, 0) * u(0, 1) +
B(1, 0, 0, 0) * u(1, 1) +
225 B(2, 0, 0, 0) * u(2, 1) +
B(3, 0, 0, 0) * u(3, 1);
226 eps(1, 1) =
B(0, 1, 1, 0) * u(0, 1) +
B(1, 1, 1, 0) * u(1, 1) +
227 B(2, 1, 1, 0) * u(2, 1) +
B(3, 1, 1, 0) * u(3, 1);
228 eps(2, 2) =
B(0, 2, 2, 2) * u(0, 0) +
B(1, 2, 2, 2) * u(1, 0) +
229 B(2, 2, 2, 2) * u(2, 0) +
B(3, 2, 2, 2) * u(3, 0);
230 eps(2, 0) = 0.5 * (
B(0, 0, 2, 2) * u(0, 0) +
B(1, 0, 2, 2) * u(1, 0) +
231 B(2, 0, 2, 2) * u(2, 0) +
B(3, 0, 2, 2) * u(3, 0) +
232 B(0, 2, 0, 0) * u(0, 1) +
B(1, 2, 0, 0) * u(1, 1) +
233 B(2, 2, 0, 0) * u(2, 1) +
B(3, 2, 0, 0) * u(3, 1));
234 eps(0, 2) = eps(2, 0);
241 template <
class T,
class R>
242 void int_N_scalar_NT_dV_impl(
const T& qscalar, R& elemmat)
const
249#pragma omp parallel for
250 for (
size_t e = 0; e < m_nelem; ++e) {
252 auto M = xt::adapt(&elemmat(e, 0, 0), xt::xshape<s_nne * s_ndim, s_nne * s_ndim>());
254 for (
size_t q = 0; q < m_nip; ++q) {
256 auto N = xt::adapt(&m_N(q, 0), xt::xshape<s_nne>());
257 auto& vol = m_vol(e, q);
258 auto& rho = qscalar(e, q);
261 for (
size_t m = 0; m < s_nne; ++m) {
262 for (
size_t n = 0; n < s_nne; ++n) {
263 M(m * s_ndim + 0, n * s_ndim + 0) += N(m) * rho * N(n) * vol;
264 M(m * s_ndim + 1, n * s_ndim + 1) += N(m) * rho * N(n) * vol;
272 template <
class T,
class R>
273 void int_gradN_dot_tensor2_dV_impl(
const T& qtensor, R& elemvec)
const
280#pragma omp parallel for
281 for (
size_t e = 0; e < m_nelem; ++e) {
283 auto f = xt::adapt(&elemvec(e, 0, 0), xt::xshape<s_nne, s_ndim>());
285 for (
size_t q = 0; q < m_nip; ++q) {
288 xt::adapt(&m_B(e, q, 0, 0, 0, 0), xt::xshape<s_nne, s_tdim, s_tdim, s_tdim>());
289 auto sig = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape<s_tdim, s_tdim>());
290 auto& vol = m_vol(e, q);
294 for (
size_t m = 0; m < s_nne; ++m) {
295 f(m, 0) += vol * (
B(m, 2, 2, 2) * sig(2, 2) +
B(m, 0, 2, 2) * sig(0, 2));
296 f(m, 1) += vol * (
B(m, 0, 0, 0) * sig(0, 0) +
B(m, 1, 1, 0) * sig(1, 1) +
297 B(m, 2, 0, 0) * sig(2, 0));
304 template <
class T,
class R>
305 void int_gradN_dot_tensor4_dot_gradNT_dV_impl(
const T& qtensor, R& elemmat)
const
312#pragma omp parallel for
313 for (
size_t e = 0; e < m_nelem; ++e) {
315 auto K = xt::adapt(&elemmat(e, 0, 0), xt::xshape<s_nne * s_ndim, s_nne * s_ndim>());
317 for (
size_t q = 0; q < m_nip; ++q) {
320 xt::adapt(&m_B(e, q, 0, 0, 0, 0), xt::xshape<s_nne, s_tdim, s_tdim, s_tdim>());
322 &qtensor(e, q, 0, 0, 0, 0), xt::xshape<s_tdim, s_tdim, s_tdim, s_tdim>());
323 auto& vol = m_vol(e, q);
327 for (
size_t m = 0; m < s_nne; ++m) {
328 for (
size_t n = 0; n < s_nne; ++n) {
329 K(m * s_ndim + 1, n * s_ndim + 1) +=
330 B(m, 0, 0, 0) * C(0, 0, 0, 0) *
B(n, 0, 0, 0) * vol;
331 K(m * s_ndim + 1, n * s_ndim + 1) +=
332 B(m, 0, 0, 0) * C(0, 0, 1, 1) *
B(n, 1, 1, 0) * vol;
333 K(m * s_ndim + 1, n * s_ndim + 0) +=
334 B(m, 0, 0, 0) * C(0, 0, 2, 2) *
B(n, 2, 2, 2) * vol;
335 K(m * s_ndim + 1, n * s_ndim + 0) +=
336 B(m, 0, 0, 0) * C(0, 0, 2, 0) *
B(n, 0, 2, 2) * vol;
337 K(m * s_ndim + 1, n * s_ndim + 1) +=
338 B(m, 0, 0, 0) * C(0, 0, 0, 2) *
B(n, 2, 0, 0) * vol;
340 K(m * s_ndim + 1, n * s_ndim + 1) +=
341 B(m, 1, 1, 0) * C(1, 1, 0, 0) *
B(n, 0, 0, 0) * vol;
342 K(m * s_ndim + 1, n * s_ndim + 1) +=
343 B(m, 1, 1, 0) * C(1, 1, 1, 1) *
B(n, 1, 1, 0) * vol;
344 K(m * s_ndim + 1, n * s_ndim + 0) +=
345 B(m, 1, 1, 0) * C(1, 1, 2, 2) *
B(n, 2, 2, 2) * vol;
346 K(m * s_ndim + 1, n * s_ndim + 0) +=
347 B(m, 1, 1, 0) * C(1, 1, 2, 0) *
B(n, 0, 2, 2) * vol;
348 K(m * s_ndim + 1, n * s_ndim + 1) +=
349 B(m, 1, 1, 0) * C(1, 1, 0, 2) *
B(n, 2, 0, 0) * vol;
351 K(m * s_ndim + 0, n * s_ndim + 1) +=
352 B(m, 2, 2, 2) * C(2, 2, 0, 0) *
B(n, 0, 0, 0) * vol;
353 K(m * s_ndim + 0, n * s_ndim + 1) +=
354 B(m, 2, 2, 2) * C(2, 2, 1, 1) *
B(n, 1, 1, 0) * vol;
355 K(m * s_ndim + 0, n * s_ndim + 0) +=
356 B(m, 2, 2, 2) * C(2, 2, 2, 2) *
B(n, 2, 2, 2) * vol;
357 K(m * s_ndim + 0, n * s_ndim + 0) +=
358 B(m, 2, 2, 2) * C(2, 2, 2, 0) *
B(n, 0, 2, 2) * vol;
359 K(m * s_ndim + 0, n * s_ndim + 1) +=
360 B(m, 2, 2, 2) * C(2, 2, 0, 2) *
B(n, 2, 0, 0) * vol;
362 K(m * s_ndim + 0, n * s_ndim + 1) +=
363 B(m, 0, 2, 2) * C(0, 2, 0, 0) *
B(n, 0, 0, 0) * vol;
364 K(m * s_ndim + 0, n * s_ndim + 1) +=
365 B(m, 0, 2, 2) * C(0, 2, 1, 1) *
B(n, 1, 1, 0) * vol;
366 K(m * s_ndim + 0, n * s_ndim + 0) +=
367 B(m, 0, 2, 2) * C(0, 2, 2, 2) *
B(n, 2, 2, 2) * vol;
368 K(m * s_ndim + 0, n * s_ndim + 0) +=
369 B(m, 0, 2, 2) * C(0, 2, 2, 0) *
B(n, 0, 2, 2) * vol;
370 K(m * s_ndim + 0, n * s_ndim + 1) +=
371 B(m, 0, 2, 2) * C(0, 2, 0, 2) *
B(n, 2, 0, 0) * vol;
373 K(m * s_ndim + 1, n * s_ndim + 1) +=
374 B(m, 2, 0, 0) * C(2, 0, 0, 0) *
B(n, 0, 0, 0) * vol;
375 K(m * s_ndim + 1, n * s_ndim + 1) +=
376 B(m, 2, 0, 0) * C(2, 0, 1, 1) *
B(n, 1, 1, 0) * vol;
377 K(m * s_ndim + 1, n * s_ndim + 0) +=
378 B(m, 2, 0, 0) * C(2, 0, 2, 2) *
B(n, 2, 2, 2) * vol;
379 K(m * s_ndim + 1, n * s_ndim + 0) +=
380 B(m, 2, 0, 0) * C(2, 0, 2, 0) *
B(n, 0, 2, 2) * vol;
381 K(m * s_ndim + 1, n * s_ndim + 1) +=
382 B(m, 2, 0, 0) * C(2, 0, 0, 2) *
B(n, 2, 0, 0) * vol;
389 void compute_dN_impl()
396 array_type::tensor<double, 2> J = xt::empty<double>({2, 2});
397 array_type::tensor<double, 2> Jinv = xt::empty<double>({2, 2});
400 for (
size_t e = 0; e < m_nelem; ++e) {
402 auto x = xt::adapt(&m_x(e, 0, 0), xt::xshape<s_nne, s_ndim>());
404 for (
size_t q = 0; q < m_nip; ++q) {
406 auto dNxi = xt::adapt(&m_dNxi(q, 0, 0), xt::xshape<s_nne, s_ndim>());
408 &m_B(e, q, 0, 0, 0, 0), xt::xshape<s_nne, s_tdim, s_tdim, s_tdim>());
409 auto N = xt::adapt(&m_N(q, 0), xt::xshape<s_nne>());
412 J(0, 0) = dNxi(0, 0) * x(0, 0) + dNxi(1, 0) * x(1, 0) + dNxi(2, 0) * x(2, 0) +
413 dNxi(3, 0) * x(3, 0);
414 J(0, 1) = dNxi(0, 0) * x(0, 1) + dNxi(1, 0) * x(1, 1) + dNxi(2, 0) * x(2, 1) +
415 dNxi(3, 0) * x(3, 1);
416 J(1, 0) = dNxi(0, 1) * x(0, 0) + dNxi(1, 1) * x(1, 0) + dNxi(2, 1) * x(2, 0) +
417 dNxi(3, 1) * x(3, 0);
418 J(1, 1) = dNxi(0, 1) * x(0, 1) + dNxi(1, 1) * x(1, 1) + dNxi(2, 1) * x(2, 1) +
419 dNxi(3, 1) * x(3, 1);
421 double Jdet = detail::tensor<2>::inv(J, Jinv);
424 double rq = N(0) * x(0, 1) + N(1) * x(1, 1) + N(2) * x(2, 1) + N(3) * x(3, 1);
427 for (
size_t m = 0; m < s_nne; ++m) {
429 B(m, 0, 0, 0) = Jinv(1, 0) * dNxi(m, 0) + Jinv(1, 1) * dNxi(m, 1);
431 B(m, 0, 2, 2) = Jinv(1, 0) * dNxi(m, 0) + Jinv(1, 1) * dNxi(m, 1);
433 B(m, 1, 1, 0) = 1.0 / rq * N(m);
435 B(m, 2, 0, 0) = Jinv(0, 0) * dNxi(m, 0) + Jinv(0, 1) * dNxi(m, 1);
437 B(m, 2, 2, 2) = Jinv(0, 0) * dNxi(m, 0) + Jinv(0, 1) * dNxi(m, 1);
440 m_vol(e, q) = m_w(q) * Jdet * 2.0 * M_PI * rq;
446 constexpr static size_t s_nne = 4;
447 constexpr static size_t s_ndim = 2;
448 constexpr static size_t s_tdim = 3;
452 array_type::tensor<double, 3> m_x;
453 array_type::tensor<double, 1> m_w;
454 array_type::tensor<double, 2> m_xi;
455 array_type::tensor<double, 2> m_N;
456 array_type::tensor<double, 3> m_dNxi;
457 array_type::tensor<double, 2> m_vol;
458 array_type::tensor<double, 6> m_B;
Interpolation and quadrature.
QuadratureAxisymmetric(const T &x)
Constructor: use default Gauss integration.
const array_type::tensor< double, 6 > & B() const
Get the B-matrix (shape function gradients) (in global coordinates).
QuadratureAxisymmetric(const T &x, const X &xi, const W &w)
Constructor with custom integration.
CRTP base class for interpolation and quadrature for a generic element in Cartesian coordinates.
CRTP base class for quadrature.
auto shape_qscalar() const -> std::array< size_t, 2 >
Get the shape of a "qscalar" (a "qtensor" of rank 0)
auto shape_elemmat() const -> std::array< size_t, 3 >
Get the shape of an "elemmat".
auto shape_elemvec() const -> std::array< size_t, 3 >
Get the shape of an "elemvec".
#define GOOSEFEM_ASSERT(expr)
All assertions are implementation as::
@ Quad4
Quadrilateral: 4-noded element in 2-d.
xt::xtensor< T, N > tensor
Fixed (static) rank array.
Toolbox to perform finite element computations.