10#ifndef GOOSEFEM_ELEMENTHEX8_H
11#define GOOSEFEM_ELEMENTHEX8_H
52 xi(0, 0) = -1.0 / std::sqrt(3.0);
53 xi(0, 1) = -1.0 / std::sqrt(3.0);
54 xi(0, 2) = -1.0 / std::sqrt(3.0);
56 xi(1, 0) = +1.0 / std::sqrt(3.0);
57 xi(1, 1) = -1.0 / std::sqrt(3.0);
58 xi(1, 2) = -1.0 / std::sqrt(3.0);
60 xi(2, 0) = +1.0 / std::sqrt(3.0);
61 xi(2, 1) = +1.0 / std::sqrt(3.0);
62 xi(2, 2) = -1.0 / std::sqrt(3.0);
64 xi(3, 0) = -1.0 / std::sqrt(3.0);
65 xi(3, 1) = +1.0 / std::sqrt(3.0);
66 xi(3, 2) = -1.0 / std::sqrt(3.0);
68 xi(4, 0) = -1.0 / std::sqrt(3.0);
69 xi(4, 1) = -1.0 / std::sqrt(3.0);
70 xi(4, 2) = +1.0 / std::sqrt(3.0);
72 xi(5, 0) = +1.0 / std::sqrt(3.0);
73 xi(5, 1) = -1.0 / std::sqrt(3.0);
74 xi(5, 2) = +1.0 / std::sqrt(3.0);
76 xi(6, 0) = +1.0 / std::sqrt(3.0);
77 xi(6, 1) = +1.0 / std::sqrt(3.0);
78 xi(6, 2) = +1.0 / std::sqrt(3.0);
80 xi(7, 0) = -1.0 / std::sqrt(3.0);
81 xi(7, 1) = +1.0 / std::sqrt(3.0);
82 xi(7, 2) = +1.0 / std::sqrt(3.0);
254 template <
class T,
class X,
class W>
261 m_nelem = m_x.shape(0);
262 m_N = xt::empty<double>({m_nip, s_nne});
263 m_dNxi = xt::empty<double>({m_nip, s_nne, s_ndim});
265 for (
size_t q = 0; q < m_nip; ++q) {
266 m_N(q, 0) = 0.125 * (1.0 - xi(q, 0)) * (1.0 - xi(q, 1)) * (1.0 - xi(q, 2));
267 m_N(q, 1) = 0.125 * (1.0 + xi(q, 0)) * (1.0 - xi(q, 1)) * (1.0 - xi(q, 2));
268 m_N(q, 2) = 0.125 * (1.0 + xi(q, 0)) * (1.0 + xi(q, 1)) * (1.0 - xi(q, 2));
269 m_N(q, 3) = 0.125 * (1.0 - xi(q, 0)) * (1.0 + xi(q, 1)) * (1.0 - xi(q, 2));
270 m_N(q, 4) = 0.125 * (1.0 - xi(q, 0)) * (1.0 - xi(q, 1)) * (1.0 + xi(q, 2));
271 m_N(q, 5) = 0.125 * (1.0 + xi(q, 0)) * (1.0 - xi(q, 1)) * (1.0 + xi(q, 2));
272 m_N(q, 6) = 0.125 * (1.0 + xi(q, 0)) * (1.0 + xi(q, 1)) * (1.0 + xi(q, 2));
273 m_N(q, 7) = 0.125 * (1.0 - xi(q, 0)) * (1.0 + xi(q, 1)) * (1.0 + xi(q, 2));
276 for (
size_t q = 0; q < m_nip; ++q) {
278 m_dNxi(q, 0, 0) = -0.125 * (1.0 - xi(q, 1)) * (1.0 - xi(q, 2));
279 m_dNxi(q, 1, 0) = +0.125 * (1.0 - xi(q, 1)) * (1.0 - xi(q, 2));
280 m_dNxi(q, 2, 0) = +0.125 * (1.0 + xi(q, 1)) * (1.0 - xi(q, 2));
281 m_dNxi(q, 3, 0) = -0.125 * (1.0 + xi(q, 1)) * (1.0 - xi(q, 2));
282 m_dNxi(q, 4, 0) = -0.125 * (1.0 - xi(q, 1)) * (1.0 + xi(q, 2));
283 m_dNxi(q, 5, 0) = +0.125 * (1.0 - xi(q, 1)) * (1.0 + xi(q, 2));
284 m_dNxi(q, 6, 0) = +0.125 * (1.0 + xi(q, 1)) * (1.0 + xi(q, 2));
285 m_dNxi(q, 7, 0) = -0.125 * (1.0 + xi(q, 1)) * (1.0 + xi(q, 2));
287 m_dNxi(q, 0, 1) = -0.125 * (1.0 - xi(q, 0)) * (1.0 - xi(q, 2));
288 m_dNxi(q, 1, 1) = -0.125 * (1.0 + xi(q, 0)) * (1.0 - xi(q, 2));
289 m_dNxi(q, 2, 1) = +0.125 * (1.0 + xi(q, 0)) * (1.0 - xi(q, 2));
290 m_dNxi(q, 3, 1) = +0.125 * (1.0 - xi(q, 0)) * (1.0 - xi(q, 2));
291 m_dNxi(q, 4, 1) = -0.125 * (1.0 - xi(q, 0)) * (1.0 + xi(q, 2));
292 m_dNxi(q, 5, 1) = -0.125 * (1.0 + xi(q, 0)) * (1.0 + xi(q, 2));
293 m_dNxi(q, 6, 1) = +0.125 * (1.0 + xi(q, 0)) * (1.0 + xi(q, 2));
294 m_dNxi(q, 7, 1) = +0.125 * (1.0 - xi(q, 0)) * (1.0 + xi(q, 2));
296 m_dNxi(q, 0, 2) = -0.125 * (1.0 - xi(q, 0)) * (1.0 - xi(q, 1));
297 m_dNxi(q, 1, 2) = -0.125 * (1.0 + xi(q, 0)) * (1.0 - xi(q, 1));
298 m_dNxi(q, 2, 2) = -0.125 * (1.0 + xi(q, 0)) * (1.0 + xi(q, 1));
299 m_dNxi(q, 3, 2) = -0.125 * (1.0 - xi(q, 0)) * (1.0 + xi(q, 1));
300 m_dNxi(q, 4, 2) = +0.125 * (1.0 - xi(q, 0)) * (1.0 - xi(q, 1));
301 m_dNxi(q, 5, 2) = +0.125 * (1.0 + xi(q, 0)) * (1.0 - xi(q, 1));
302 m_dNxi(q, 6, 2) = +0.125 * (1.0 + xi(q, 0)) * (1.0 + xi(q, 1));
303 m_dNxi(q, 7, 2) = +0.125 * (1.0 - xi(q, 0)) * (1.0 + xi(q, 1));
313 m_dNx = xt::empty<double>({m_nelem, m_nip, s_nne, s_ndim});
323 template <
class T,
class R>
324 void int_N_scalar_NT_dV_impl(
const T& qscalar, R& elemmat)
const
331#pragma omp parallel for
332 for (
size_t e = 0; e < m_nelem; ++e) {
334 auto M = xt::adapt(&elemmat(e, 0, 0), xt::xshape<s_nne * s_ndim, s_nne * s_ndim>());
336 for (
size_t q = 0; q < m_nip; ++q) {
338 auto N = xt::adapt(&m_N(q, 0), xt::xshape<s_nne>());
339 auto& vol = m_vol(e, q);
340 auto& rho = qscalar(e, q);
343 for (
size_t m = 0; m < s_nne; ++m) {
344 for (
size_t n = 0; n < s_nne; ++n) {
345 M(m * s_ndim + 0, n * s_ndim + 0) += N(m) * rho * N(n) * vol;
346 M(m * s_ndim + 1, n * s_ndim + 1) += N(m) * rho * N(n) * vol;
347 M(m * s_ndim + 2, n * s_ndim + 2) += N(m) * rho * N(n) * vol;
354 template <
class T,
class R>
355 void int_gradN_dot_tensor2_dV_impl(
const T& qtensor, R& elemvec)
const
362#pragma omp parallel for
363 for (
size_t e = 0; e < m_nelem; ++e) {
365 auto f = xt::adapt(&elemvec(e, 0, 0), xt::xshape<s_nne, s_ndim>());
367 for (
size_t q = 0; q < m_nip; ++q) {
369 auto dNx = xt::adapt(&m_dNx(e, q, 0, 0), xt::xshape<s_nne, s_ndim>());
370 auto sig = xt::adapt(&qtensor(e, q, 0, 0), xt::xshape<s_ndim, s_ndim>());
371 auto& v = m_vol(e, q);
373 for (
size_t m = 0; m < s_nne; ++m) {
375 (dNx(m, 0) * sig(0, 0) + dNx(m, 1) * sig(1, 0) + dNx(m, 2) * sig(2, 0)) * v;
377 (dNx(m, 0) * sig(0, 1) + dNx(m, 1) * sig(1, 1) + dNx(m, 2) * sig(2, 1)) * v;
379 (dNx(m, 0) * sig(0, 2) + dNx(m, 1) * sig(1, 2) + dNx(m, 2) * sig(2, 2)) * v;
385 constexpr static size_t s_nne = 8;
386 constexpr static size_t s_ndim = 3;
387 constexpr static size_t s_tdim = 3;
391 array_type::tensor<double, 3> m_x;
392 array_type::tensor<double, 1> m_w;
393 array_type::tensor<double, 2> m_xi;
394 array_type::tensor<double, 2> m_N;
395 array_type::tensor<double, 3> m_dNxi;
396 array_type::tensor<double, 4> m_dNx;
397 array_type::tensor<double, 2> m_vol;
Interpolation and quadrature.
Quadrature(const T &x, const X &xi, const W &w)
Constructor with custom integration.
Quadrature(const T &x)
Constructor: use default Gauss integration.
CRTP base class for interpolation and quadrature for a generic element in Cartesian coordinates.
void compute_dN()
Update the shape function gradients (called when the nodal positions are updated).
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::
size_t nip()
Number of integration points:
array_type::tensor< double, 2 > xi()
Integration point coordinates (local coordinates).
array_type::tensor< double, 1 > w()
Integration point weights.
array_type::tensor< double, 2 > xi()
Integration point coordinates (local coordinates).
array_type::tensor< double, 1 > w()
Integration point weights.
size_t nip()
Number of integration points:
xt::xtensor< T, N > tensor
Fixed (static) rank array.
Toolbox to perform finite element computations.