163 lines
6.7 KiB
C++
163 lines
6.7 KiB
C++
#pragma once
|
|
|
|
#include <mfem.hpp>
|
|
|
|
namespace {
|
|
// U and G are n x 3, component/derivative columns respectively. Keep the
|
|
// nine reductions together instead of invoking a general GEMM per point.
|
|
// The returned 3 x 3 matrix is column-major: A(c,j) = sum_i U(i,c) G(i,j).
|
|
inline void displacement_gradient_3d(
|
|
const mfem::DenseMatrix &direction, const mfem::DenseMatrix &gradients, double *a
|
|
) {
|
|
const int n = direction.Height();
|
|
const double *u = direction.Data();
|
|
const double *g = gradients.Data();
|
|
for (int j = 0; j < 3; ++j) {
|
|
double x = 0.0, y = 0.0, z = 0.0;
|
|
const double *gj = g + j * n;
|
|
for (int i = 0; i < n; ++i) {
|
|
const double v = gj[i];
|
|
x += u[i] * v;
|
|
y += u[i + n] * v;
|
|
z += u[i + 2 * n] * v;
|
|
}
|
|
a[3 * j] = x; a[3 * j + 1] = y; a[3 * j + 2] = z;
|
|
}
|
|
}
|
|
|
|
inline void vector_basis_value_3d(
|
|
const mfem::DenseMatrix &basis, const mfem::Vector &coefficients, double *value
|
|
) {
|
|
const int n = basis.Height();
|
|
const double *b = basis.Data();
|
|
const double *v = coefficients.HostRead();
|
|
double x = 0.0, y = 0.0, z = 0.0;
|
|
for (int i = 0; i < n; ++i) {
|
|
x += b[i] * v[i]; y += b[i + n] * v[i]; z += b[i + 2 * n] * v[i];
|
|
}
|
|
value[0] = x; value[1] = y; value[2] = z;
|
|
}
|
|
|
|
// Matrix cache layout: nq x 9, with row-major matrix entries in columns.
|
|
inline void cached_matrix_vector_3d(
|
|
const mfem::DenseMatrix &cache, const int point, const double *v, double *out
|
|
) {
|
|
const int nq = cache.Height();
|
|
const double *m = cache.Data() + point;
|
|
for (int r = 0; r < 3; ++r)
|
|
out[r] = m[(3 * r) * nq] * v[0] + m[(3 * r + 1) * nq] * v[1] +
|
|
m[(3 * r + 2) * nq] * v[2];
|
|
}
|
|
|
|
inline double displacement_trace_3d(
|
|
const mfem::DenseMatrix &direction, const mfem::DenseMatrix &gradients,
|
|
const mfem::DenseMatrix &inverseJacobians, const int point
|
|
) {
|
|
double a[9];
|
|
displacement_gradient_3d(direction, gradients, a);
|
|
const double *k = inverseJacobians.Data() + point;
|
|
const int nq = inverseJacobians.Height();
|
|
double trace = 0.0;
|
|
for (int j = 0; j < 3; ++j)
|
|
for (int c = 0; c < 3; ++c) trace += k[(3 * j + c) * nq] * a[c + 3 * j];
|
|
return trace;
|
|
}
|
|
|
|
// (du/dxi) v, without constructing du/dxi. v is fixed at this point.
|
|
inline void displacement_directional_value_3d(
|
|
const mfem::DenseMatrix &direction, const mfem::DenseMatrix &gradients,
|
|
const double *v, double *out
|
|
) {
|
|
const int n = direction.Height();
|
|
const double *u = direction.Data();
|
|
const double *g = gradients.Data();
|
|
double x = 0.0, y = 0.0, z = 0.0;
|
|
for (int i = 0; i < n; ++i) {
|
|
const double d = g[i] * v[0] + g[i + n] * v[1] + g[i + 2 * n] * v[2];
|
|
x += u[i] * d; y += u[i + n] * d; z += u[i + 2 * n] * d;
|
|
}
|
|
out[0] = x; out[1] = y; out[2] = z;
|
|
}
|
|
|
|
inline void pressure_displacement_action_3d(
|
|
const mfem::DenseMatrix &direction, const mfem::DenseMatrix &physicalGradients,
|
|
const double pressureWeight, mfem::Vector &action
|
|
) {
|
|
// H = du/dx; d(G dx) = (tr(H) G - G H) dx.
|
|
double h[9];
|
|
displacement_gradient_3d(direction, physicalGradients, h);
|
|
const double trace = h[0] + h[4] + h[8];
|
|
const int n = direction.Height();
|
|
const double *g = physicalGradients.Data();
|
|
double *r = action.HostReadWrite();
|
|
for (int c = 0; c < 3; ++c) {
|
|
const double a = pressureWeight * (h[3 * c] - (c == 0 ? trace : 0.0));
|
|
const double b = pressureWeight * (h[3 * c + 1] - (c == 1 ? trace : 0.0));
|
|
const double d = pressureWeight * (h[3 * c + 2] - (c == 2 ? trace : 0.0));
|
|
for (int i = 0; i < n; ++i) r[i + c * n] += a * g[i] + b * g[i + n] + d * g[i + 2 * n];
|
|
}
|
|
}
|
|
|
|
// Element VDofs are component-blocked, including for a byVDIM global space;
|
|
// this is the ordering consumed by ElementDisplacementDataFromElementVDofs.
|
|
// For an ordinary interior VALUE field, dx = du and
|
|
// d(log det J_element) = tr(J_element^-1 * du/dxi).
|
|
inline void add_interior_functional_row(
|
|
const mfem::DenseMatrix &gradients,
|
|
const mfem::DenseMatrix &values,
|
|
const int point,
|
|
const mfem::DenseMatrix &inverseElementJacobian,
|
|
const double determinantCoefficient,
|
|
const double *positionCoefficient,
|
|
mfem::Vector &row
|
|
) {
|
|
const int n = gradients.Height();
|
|
const int dimension = gradients.Width();
|
|
const int nq = values.Height();
|
|
const double *g = gradients.Data();
|
|
const double *b = values.Data() + point;
|
|
double *r = row.HostReadWrite();
|
|
for (int component = 0; component < dimension; ++component) {
|
|
for (int i = 0; i < n; ++i) {
|
|
double coefficient = positionCoefficient[component] * b[i * nq];
|
|
for (int derivative = 0; derivative < dimension; ++derivative) {
|
|
coefficient += determinantCoefficient * inverseElementJacobian(derivative, component) *
|
|
g[i + derivative * n];
|
|
}
|
|
r[i + component * n] += coefficient;
|
|
}
|
|
}
|
|
}
|
|
|
|
inline double apply_interior_functional(
|
|
const mfem::DenseMatrix &direction,
|
|
const mfem::DenseMatrix &gradients,
|
|
const mfem::DenseMatrix &values,
|
|
const int point,
|
|
const double *inverseElementJacobian,
|
|
const double determinantCoefficient,
|
|
const double *positionCoefficient
|
|
) {
|
|
const int n = direction.Height();
|
|
const int dimension = direction.Width();
|
|
const int nq = values.Height();
|
|
const double *u = direction.Data();
|
|
const double *g = gradients.Data();
|
|
const double *b = values.Data() + point;
|
|
double result = 0.0;
|
|
for (int component = 0; component < dimension; ++component) {
|
|
double value = 0.0;
|
|
for (int i = 0; i < n; ++i) value += u[i + component * n] * b[i * nq];
|
|
result += positionCoefficient[component] * value;
|
|
for (int derivative = 0; derivative < dimension; ++derivative) {
|
|
double gradient = 0.0;
|
|
for (int i = 0; i < n; ++i)
|
|
gradient += u[i + component * n] * g[i + derivative * n];
|
|
result += determinantCoefficient * inverseElementJacobian[derivative + component * dimension] *
|
|
gradient;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
}
|