currently the barotope and the pressure force operator are migrated to the new support system
770 lines
32 KiB
C++
770 lines
32 KiB
C++
module;
|
|
|
|
#include <cmath>
|
|
#include <memory>
|
|
#include <mfem.hpp>
|
|
#include <stdexcept>
|
|
#include <utility>
|
|
|
|
module mean_field;
|
|
import :mapping.types;
|
|
import :mapping.compactification;
|
|
import :utils.user;
|
|
|
|
namespace {
|
|
bool vector_is_finite(const mfem::Vector &vector) {
|
|
for (int i = 0; i < vector.Size(); ++i) {
|
|
if (!std::isfinite(vector(i)))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool matrix_is_finite(const mfem::DenseMatrix &matrix) {
|
|
for (int i = 0; i < matrix.Height(); ++i) {
|
|
for (int j = 0; j < matrix.Width(); ++j) {
|
|
if (!std::isfinite(matrix(i, j)))
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
} // namespace
|
|
|
|
namespace mean_field::mapping {
|
|
ElementCompactificationData::ElementCompactificationData(
|
|
const mfem::FiniteElement &element,
|
|
const mfem::Vector &dofs
|
|
)
|
|
: m_element(&element),
|
|
m_dofs(dofs) {
|
|
if (element.GetRangeType() != mfem::FiniteElement::SCALAR) {
|
|
throw std::invalid_argument("Compactification coordinate requires a scalar finite element.");
|
|
}
|
|
|
|
if (element.GetMapType() != mfem::FiniteElement::VALUE) {
|
|
throw std::invalid_argument(
|
|
"Compactification coordinate requires a value-mapped scalar "
|
|
"finite "
|
|
"element."
|
|
);
|
|
}
|
|
|
|
if (element.GetDerivType() != mfem::FiniteElement::GRAD) {
|
|
throw std::invalid_argument(
|
|
"Compactification coordinate finite element must provide a "
|
|
"gradient."
|
|
);
|
|
}
|
|
|
|
if (element.GetDof() <= 0) {
|
|
throw std::invalid_argument(
|
|
"Compactification coordinate finite element has no degrees of "
|
|
"freedom."
|
|
);
|
|
}
|
|
|
|
if (dofs.Size() != element.GetDof()) {
|
|
throw std::invalid_argument(
|
|
"Compactification coordinate DOF count does not match its "
|
|
"finite "
|
|
"element."
|
|
);
|
|
}
|
|
}
|
|
|
|
const mfem::FiniteElement &ElementCompactificationData::GetElement() const noexcept {
|
|
return *m_element;
|
|
}
|
|
|
|
const mfem::Vector &ElementCompactificationData::GetDofs() const noexcept {
|
|
return m_dofs;
|
|
}
|
|
|
|
int ElementCompactificationData::GetDofCount() const noexcept {
|
|
return m_dofs.Size();
|
|
}
|
|
|
|
ElementDisplacementData::ElementDisplacementData(
|
|
const mfem::FiniteElement &element,
|
|
const mfem::Vector &displacement_dofs,
|
|
const mfem::Ordering::Type ordering
|
|
)
|
|
: m_element(&element),
|
|
m_dimension(0),
|
|
m_ordering(ordering) {
|
|
const int dof_count = element.GetDof();
|
|
if (dof_count <= 0)
|
|
throw std::invalid_argument(
|
|
"The displacement element must have at least one degree of "
|
|
"freedom."
|
|
);
|
|
if (displacement_dofs.Size() <= 0 || displacement_dofs.Size() % dof_count != 0) {
|
|
throw std::invalid_argument(
|
|
"The displacement vector size must be a positive multiple of "
|
|
"the "
|
|
"element degree-of-freedom count."
|
|
);
|
|
}
|
|
|
|
m_dimension = displacement_dofs.Size() / dof_count;
|
|
m_dof_matrix.SetSize(dof_count, m_dimension);
|
|
|
|
if (ordering == mfem::Ordering::byNODES) {
|
|
for (int component = 0; component < m_dimension; ++component) {
|
|
for (int i = 0; i < dof_count; ++i) {
|
|
m_dof_matrix(i, component) = displacement_dofs(i + component * dof_count);
|
|
}
|
|
}
|
|
} else if (ordering == mfem::Ordering::byVDIM) {
|
|
for (int i = 0; i < dof_count; ++i) {
|
|
for (int component = 0; component < m_dimension; ++component) {
|
|
m_dof_matrix(i, component) = displacement_dofs(component + i * m_dimension);
|
|
}
|
|
}
|
|
} else {
|
|
throw std::invalid_argument("Unsupported MFEM displacement ordering.");
|
|
}
|
|
}
|
|
|
|
const mfem::FiniteElement &ElementDisplacementData::GetElement() const noexcept {
|
|
return *m_element;
|
|
}
|
|
|
|
const mfem::DenseMatrix &ElementDisplacementData::GetDofMatrix() const noexcept {
|
|
return m_dof_matrix;
|
|
}
|
|
|
|
int ElementDisplacementData::GetDimension() const noexcept {
|
|
return m_dimension;
|
|
}
|
|
|
|
int ElementDisplacementData::GetDofCount() const noexcept {
|
|
return m_element->GetDof();
|
|
}
|
|
|
|
mfem::Ordering::Type ElementDisplacementData::GetOrdering() const noexcept {
|
|
return m_ordering;
|
|
}
|
|
|
|
ElementDisplacementData ElementDisplacementDataFromElementVDofs(
|
|
const mfem::FiniteElement &element,
|
|
const mfem::Vector &displacement_dofs
|
|
) {
|
|
return ElementDisplacementData(element, displacement_dofs, mfem::Ordering::byNODES);
|
|
}
|
|
|
|
DomainMapperStateless::Workspace::Workspace(const int dimension) {
|
|
SetDimension(dimension);
|
|
}
|
|
|
|
void DomainMapperStateless::Workspace::SetDimension(const int dimension) {
|
|
if (dimension <= 0) {
|
|
throw std::invalid_argument("Domain mapping workspace dimension must be positive.");
|
|
}
|
|
|
|
m_dimension = dimension;
|
|
|
|
m_field_value.SetSize(dimension);
|
|
m_field_jacobian.SetSize(dimension, dimension);
|
|
|
|
m_compactification_point.coordinate = 0.0;
|
|
m_compactification_point.coordinate_gradient.SetSize(dimension);
|
|
|
|
m_reference_normal.SetSize(dimension);
|
|
m_mapped_normal.SetSize(dimension);
|
|
m_full_element_jacobian.SetSize(dimension, dimension);
|
|
|
|
m_vector_temp.SetSize(dimension);
|
|
m_matrix_temp_1.SetSize(dimension, dimension);
|
|
m_matrix_temp_2.SetSize(dimension, dimension);
|
|
|
|
m_exterior_result.physical_position.SetSize(dimension);
|
|
m_exterior_result.mapping_jacobian.SetSize(dimension, dimension);
|
|
|
|
m_exterior_variation.physical_position_variation.SetSize(dimension);
|
|
m_exterior_variation.mapping_jacobian_variation.SetSize(dimension, dimension);
|
|
}
|
|
|
|
int DomainMapperStateless::Workspace::GetDimension() const noexcept {
|
|
return m_dimension;
|
|
}
|
|
|
|
DomainMapperStateless::DomainMapperStateless(
|
|
const utils::DomainMapperStatelessOptions options,
|
|
std::unique_ptr<const compactification::ExteriorDomainMap> exterior_map
|
|
)
|
|
: m_options(options),
|
|
m_exterior_map(std::move(exterior_map)) {
|
|
if (m_options.dimension <= 0)
|
|
throw std::invalid_argument("The domain-mapping dimension must be positive.");
|
|
if (m_options.vacuum_element_attribute <= 0)
|
|
throw std::invalid_argument("The vacuum element attribute must be positive.");
|
|
if (!m_exterior_map)
|
|
throw std::invalid_argument("DomainMapperStateless requires an exterior-domain mapping.");
|
|
}
|
|
|
|
bool
|
|
DomainMapperStateless::IsCompactifiedElement(const mfem::ElementTransformation &transformation) const noexcept {
|
|
return transformation.Attribute == m_options.vacuum_element_attribute;
|
|
}
|
|
|
|
int DomainMapperStateless::GetDimension() const noexcept {
|
|
return m_options.dimension;
|
|
}
|
|
|
|
int DomainMapperStateless::GetVacuumElementAttribute() const noexcept {
|
|
return m_options.vacuum_element_attribute;
|
|
}
|
|
|
|
const compactification::ExteriorDomainMap &DomainMapperStateless::GetExteriorMap() const noexcept {
|
|
return *m_exterior_map;
|
|
}
|
|
|
|
void DomainMapperStateless::ValidateElementData(const ElementMappingData &element_data) const {
|
|
const ElementDisplacementData &displacement = element_data.displacement;
|
|
const ElementCompactificationData &compactification = element_data.compactification;
|
|
|
|
if (displacement.GetDimension() != m_options.dimension) {
|
|
throw std::invalid_argument(
|
|
"Displacement field dimension does not match the domain mapper "
|
|
"dimension."
|
|
);
|
|
}
|
|
|
|
if (displacement.GetElement().GetDim() != m_options.dimension) {
|
|
throw std::invalid_argument(
|
|
"Displacement finite element dimension does not match the "
|
|
"domain "
|
|
"mapper dimension."
|
|
);
|
|
}
|
|
|
|
if (compactification.GetElement().GetDim() != m_options.dimension) {
|
|
throw std::invalid_argument(
|
|
"Compactification finite element dimension does not match the "
|
|
"domain "
|
|
"mapper dimension."
|
|
);
|
|
}
|
|
|
|
if (displacement.GetElement().GetGeomType() != compactification.GetElement().GetGeomType()) {
|
|
throw std::invalid_argument(
|
|
"Displacement and compactification finite elements have "
|
|
"different "
|
|
"geometries."
|
|
);
|
|
}
|
|
|
|
if (compactification.GetElement().GetRangeType() != mfem::FiniteElement::SCALAR) {
|
|
throw std::invalid_argument("Compactification coordinate requires a scalar finite element.");
|
|
}
|
|
|
|
if (compactification.GetElement().GetMapType() != mfem::FiniteElement::VALUE) {
|
|
throw std::invalid_argument(
|
|
"Compactification coordinate requires a value-mapped finite "
|
|
"element."
|
|
);
|
|
}
|
|
|
|
if (compactification.GetElement().GetDerivType() != mfem::FiniteElement::GRAD) {
|
|
throw std::invalid_argument(
|
|
"Compactification coordinate finite element does not provide a "
|
|
"gradient."
|
|
);
|
|
}
|
|
|
|
if (compactification.GetDofCount() != compactification.GetElement().GetDof()) {
|
|
throw std::invalid_argument(
|
|
"Compactification coordinate DOF count does not match its "
|
|
"finite "
|
|
"element."
|
|
);
|
|
}
|
|
}
|
|
|
|
MappingStatus DomainMapperStateless::EvaluateCompactificationCoordinate(
|
|
const ElementCompactificationData &compactification,
|
|
mfem::ElementTransformation &transformation,
|
|
const mfem::IntegrationPoint &integration_point,
|
|
Workspace &workspace,
|
|
CompactificationPointData &point_data
|
|
) const {
|
|
const mfem::FiniteElement &element = compactification.GetElement();
|
|
const mfem::Vector &dofs = compactification.GetDofs();
|
|
const int dof_count = element.GetDof();
|
|
|
|
if (workspace.GetDimension() != m_options.dimension || transformation.GetSpaceDim() != m_options.dimension ||
|
|
element.GetDim() != m_options.dimension) {
|
|
return MappingStatus::invalid_dimension;
|
|
}
|
|
|
|
if (dofs.Size() != dof_count) {
|
|
return MappingStatus::invalid_dimension;
|
|
}
|
|
|
|
for (int i = 0; i < dofs.Size(); ++i) {
|
|
if (!std::isfinite(dofs(i)))
|
|
return MappingStatus::non_finite_input;
|
|
}
|
|
|
|
transformation.SetIntPoint(&integration_point);
|
|
|
|
workspace.m_compactification_shape.SetSize(dof_count);
|
|
workspace.m_compactification_dshape.SetSize(dof_count, m_options.dimension);
|
|
|
|
element.CalcShape(integration_point, workspace.m_compactification_shape);
|
|
element.CalcPhysDShape(transformation, workspace.m_compactification_dshape);
|
|
|
|
point_data.coordinate = dofs * workspace.m_compactification_shape;
|
|
point_data.coordinate_gradient.SetSize(m_options.dimension);
|
|
workspace.m_compactification_dshape.MultTranspose(dofs, point_data.coordinate_gradient);
|
|
|
|
if (!std::isfinite(point_data.coordinate)) {
|
|
return MappingStatus::non_finite_result;
|
|
}
|
|
|
|
for (int d = 0; d < point_data.coordinate_gradient.Size(); ++d) {
|
|
if (!std::isfinite(point_data.coordinate_gradient(d)))
|
|
return MappingStatus::non_finite_result;
|
|
}
|
|
|
|
return MappingStatus::valid;
|
|
}
|
|
|
|
void DomainMapperStateless::EvaluateField(
|
|
const ElementDisplacementData &field,
|
|
mfem::ElementTransformation &transformation,
|
|
const mfem::IntegrationPoint &integration_point,
|
|
Workspace &workspace,
|
|
mfem::Vector &value,
|
|
mfem::DenseMatrix &jacobian
|
|
) const {
|
|
transformation.SetIntPoint(&integration_point);
|
|
|
|
const mfem::FiniteElement &element = field.GetElement();
|
|
const mfem::DenseMatrix &dof_matrix = field.GetDofMatrix();
|
|
|
|
workspace.m_shape.SetSize(element.GetDof());
|
|
workspace.m_mesh_dshape.SetSize(element.GetDof(), m_options.dimension);
|
|
|
|
element.CalcShape(integration_point, workspace.m_shape);
|
|
element.CalcPhysDShape(transformation, workspace.m_mesh_dshape);
|
|
|
|
value.SetSize(m_options.dimension);
|
|
dof_matrix.MultTranspose(workspace.m_shape, value);
|
|
|
|
jacobian.SetSize(m_options.dimension, m_options.dimension);
|
|
mfem::MultAtB(dof_matrix, workspace.m_mesh_dshape, jacobian);
|
|
}
|
|
|
|
MappingStatus DomainMapperStateless::EvaluatePoint(
|
|
const ElementMappingData &element_data,
|
|
mfem::ElementTransformation &transformation,
|
|
const mfem::IntegrationPoint &integration_point,
|
|
Workspace &workspace,
|
|
MappingPointContext &context
|
|
) const {
|
|
ValidateElementData(element_data);
|
|
|
|
if (workspace.GetDimension() != m_options.dimension)
|
|
throw std::invalid_argument("The mapping workspace has the wrong dimension.");
|
|
if (transformation.GetSpaceDim() != m_options.dimension)
|
|
throw std::invalid_argument("The element transformation has the wrong spatial dimension.");
|
|
if (transformation.GetGeometryType() != element_data.displacement.GetElement().GetGeomType())
|
|
throw std::invalid_argument(
|
|
"The element transformation geometry does not match the "
|
|
"supplied "
|
|
"element data."
|
|
);
|
|
|
|
transformation.SetIntPoint(&integration_point);
|
|
|
|
context.reference_position.SetSize(m_options.dimension);
|
|
transformation.Transform(integration_point, context.reference_position);
|
|
|
|
EvaluateField(
|
|
element_data.displacement, transformation, integration_point, workspace, workspace.m_field_value,
|
|
workspace.m_field_jacobian
|
|
);
|
|
|
|
if (!vector_is_finite(context.reference_position) || !vector_is_finite(workspace.m_field_value) ||
|
|
!matrix_is_finite(workspace.m_field_jacobian)) {
|
|
return MappingStatus::non_finite_input;
|
|
}
|
|
|
|
context.displaced_position.SetSize(m_options.dimension);
|
|
context.displaced_position = context.reference_position;
|
|
context.displaced_position += workspace.m_field_value;
|
|
|
|
context.displacement_jacobian.SetSize(m_options.dimension, m_options.dimension);
|
|
context.displacement_jacobian = workspace.m_field_jacobian;
|
|
for (int i = 0; i < m_options.dimension; ++i)
|
|
context.displacement_jacobian(i, i) += 1.0;
|
|
|
|
context.compactified = IsCompactifiedElement(transformation);
|
|
|
|
if (context.compactified) {
|
|
const MappingStatus coordinate_status = EvaluateCompactificationCoordinate(
|
|
element_data.compactification, transformation, integration_point, workspace,
|
|
workspace.m_compactification_point
|
|
);
|
|
|
|
if (coordinate_status != MappingStatus::valid)
|
|
return coordinate_status;
|
|
|
|
const compactification::ExteriorMapInput exterior_input{
|
|
.reference_position = context.reference_position,
|
|
.displaced_position = context.displaced_position,
|
|
.displacement_jacobian = context.displacement_jacobian,
|
|
.compactification_coordinate = workspace.m_compactification_point.coordinate,
|
|
.compactification_coordinate_gradient = workspace.m_compactification_point.coordinate_gradient
|
|
};
|
|
|
|
const MappingStatus exterior_status = m_exterior_map->Evaluate(exterior_input, workspace.m_exterior_result);
|
|
if (exterior_status != MappingStatus::valid)
|
|
return exterior_status;
|
|
|
|
context.physical_position = workspace.m_exterior_result.physical_position;
|
|
context.mapping_jacobian = workspace.m_exterior_result.mapping_jacobian;
|
|
} else {
|
|
context.physical_position = context.displaced_position;
|
|
context.mapping_jacobian = context.displacement_jacobian;
|
|
}
|
|
|
|
if (!vector_is_finite(context.physical_position) || !matrix_is_finite(context.mapping_jacobian))
|
|
return MappingStatus::non_finite_result;
|
|
|
|
context.mapping_determinant = context.mapping_jacobian.Det();
|
|
if (!std::isfinite(context.mapping_determinant))
|
|
return MappingStatus::non_finite_result;
|
|
if (context.mapping_determinant <= 0.0)
|
|
return MappingStatus::non_positive_determinant;
|
|
|
|
context.inverse_mapping_jacobian.SetSize(m_options.dimension, m_options.dimension);
|
|
mfem::CalcInverse(context.mapping_jacobian, context.inverse_mapping_jacobian);
|
|
|
|
if (!matrix_is_finite(context.inverse_mapping_jacobian))
|
|
return MappingStatus::non_finite_result;
|
|
|
|
return MappingStatus::valid;
|
|
}
|
|
|
|
MappingStatus DomainMapperStateless::EvaluateVolume(
|
|
const ElementMappingData &element_data,
|
|
mfem::ElementTransformation &transformation,
|
|
const mfem::IntegrationPoint &integration_point,
|
|
Workspace &workspace,
|
|
VolumeMappingContext &context
|
|
) const {
|
|
const MappingStatus point_status =
|
|
EvaluatePoint(element_data, transformation, integration_point, workspace, context.mapping);
|
|
if (point_status != MappingStatus::valid)
|
|
return point_status;
|
|
|
|
transformation.SetIntPoint(&integration_point);
|
|
mfem::Mult(context.mapping.mapping_jacobian, transformation.Jacobian(), workspace.m_full_element_jacobian);
|
|
|
|
context.quadrature.J_inv.SetSize(m_options.dimension, m_options.dimension);
|
|
mfem::CalcInverse(workspace.m_full_element_jacobian, context.quadrature.J_inv);
|
|
|
|
context.quadrature.detJ = context.mapping.mapping_determinant;
|
|
context.quadrature.weight =
|
|
integration_point.weight * transformation.Weight() * context.mapping.mapping_determinant;
|
|
|
|
if (!matrix_is_finite(context.quadrature.J_inv) || !std::isfinite(context.quadrature.weight))
|
|
return MappingStatus::non_finite_result;
|
|
if (context.quadrature.weight <= 0.0)
|
|
return MappingStatus::non_positive_determinant;
|
|
|
|
return MappingStatus::valid;
|
|
}
|
|
|
|
mfem::ElementTransformation &DomainMapperStateless::SelectFaceElementTransformation(
|
|
mfem::FaceElementTransformations &transformation,
|
|
const FaceElementSide side
|
|
) {
|
|
if (side == FaceElementSide::element_1) {
|
|
MFEM_VERIFY(transformation.Elem1 != nullptr, "The face does not have an element-1 transformation.");
|
|
return *transformation.Elem1;
|
|
}
|
|
|
|
MFEM_VERIFY(transformation.Elem2 != nullptr, "The face does not have an element-2 transformation.");
|
|
return *transformation.Elem2;
|
|
}
|
|
|
|
const mfem::IntegrationPoint &DomainMapperStateless::SelectFaceElementIntegrationPoint(
|
|
mfem::FaceElementTransformations &transformation,
|
|
const FaceElementSide side
|
|
) {
|
|
mfem::ElementTransformation &element_transformation = SelectFaceElementTransformation(transformation, side);
|
|
return element_transformation.GetIntPoint();
|
|
}
|
|
|
|
MappingStatus DomainMapperStateless::EvaluateFace(
|
|
const ElementMappingData &element_data,
|
|
mfem::FaceElementTransformations &transformation,
|
|
const FaceElementSide side,
|
|
const mfem::IntegrationPoint &integration_point,
|
|
Workspace &workspace,
|
|
FaceMappingContext &context
|
|
) const {
|
|
transformation.SetAllIntPoints(&integration_point);
|
|
mfem::ElementTransformation &element_transformation = SelectFaceElementTransformation(transformation, side);
|
|
const mfem::IntegrationPoint &element_integration_point =
|
|
SelectFaceElementIntegrationPoint(transformation, side);
|
|
|
|
const MappingStatus point_status =
|
|
EvaluatePoint(element_data, element_transformation, element_integration_point, workspace, context.mapping);
|
|
if (point_status != MappingStatus::valid)
|
|
return point_status;
|
|
|
|
workspace.m_reference_normal.SetSize(m_options.dimension);
|
|
mfem::CalcOrtho(transformation.Jacobian(), workspace.m_reference_normal);
|
|
if (side == FaceElementSide::element_2)
|
|
workspace.m_reference_normal *= -1.0;
|
|
|
|
const double reference_normal_magnitude = workspace.m_reference_normal.Norml2();
|
|
if (!std::isfinite(reference_normal_magnitude) || reference_normal_magnitude <= 0.0)
|
|
return MappingStatus::non_finite_result;
|
|
|
|
context.reference_normal.SetSize(m_options.dimension);
|
|
context.reference_normal = workspace.m_reference_normal;
|
|
context.reference_normal /= reference_normal_magnitude;
|
|
|
|
context.mapping.inverse_mapping_jacobian.MultTranspose(workspace.m_reference_normal, workspace.m_mapped_normal);
|
|
workspace.m_mapped_normal *= context.mapping.mapping_determinant;
|
|
|
|
const double mapped_normal_magnitude = workspace.m_mapped_normal.Norml2();
|
|
if (!std::isfinite(mapped_normal_magnitude) || mapped_normal_magnitude <= 0.0)
|
|
return MappingStatus::non_finite_result;
|
|
|
|
context.quadrature.normal.SetSize(m_options.dimension);
|
|
context.quadrature.normal = workspace.m_mapped_normal;
|
|
context.quadrature.normal /= mapped_normal_magnitude;
|
|
|
|
context.reference_surface_weight = integration_point.weight * reference_normal_magnitude;
|
|
context.physical_surface_weight = integration_point.weight * mapped_normal_magnitude;
|
|
|
|
context.quadrature.ds = context.reference_surface_weight;
|
|
context.quadrature.v_dot_n_scale = mapped_normal_magnitude / reference_normal_magnitude;
|
|
|
|
if (!vector_is_finite(context.quadrature.normal) || !std::isfinite(context.reference_surface_weight) ||
|
|
!std::isfinite(context.physical_surface_weight) || !std::isfinite(context.quadrature.v_dot_n_scale)) {
|
|
return MappingStatus::non_finite_result;
|
|
}
|
|
|
|
return MappingStatus::valid;
|
|
}
|
|
|
|
MappingStatus DomainMapperStateless::EvaluatePointVariation(
|
|
const ElementMappingData &element_data,
|
|
const ElementDisplacementData &direction,
|
|
mfem::ElementTransformation &transformation,
|
|
const mfem::IntegrationPoint &integration_point,
|
|
const MappingPointContext &base_context,
|
|
Workspace &workspace,
|
|
MappingPointVariation &variation
|
|
) const {
|
|
ValidateElementData(element_data);
|
|
const ElementMappingData direction_data{
|
|
.displacement = direction, .compactification = element_data.compactification
|
|
};
|
|
ValidateElementData(direction_data);
|
|
|
|
if (element_data.displacement.GetDofCount() != direction.GetDofCount())
|
|
throw std::invalid_argument(
|
|
"The displacement and direction elements have different "
|
|
"degree-of-freedom counts."
|
|
);
|
|
if (workspace.GetDimension() != m_options.dimension)
|
|
throw std::invalid_argument("The mapping workspace has the wrong dimension.");
|
|
if (base_context.compactified != IsCompactifiedElement(transformation))
|
|
throw std::invalid_argument(
|
|
"The base mapping context does not match the current element "
|
|
"domain."
|
|
);
|
|
|
|
EvaluateField(
|
|
direction, transformation, integration_point, workspace, workspace.m_field_value, workspace.m_field_jacobian
|
|
);
|
|
|
|
if (!vector_is_finite(workspace.m_field_value) || !matrix_is_finite(workspace.m_field_jacobian))
|
|
return MappingStatus::non_finite_input;
|
|
|
|
variation.displacement_variation = workspace.m_field_value;
|
|
variation.displacement_jacobian_variation = workspace.m_field_jacobian;
|
|
|
|
if (base_context.compactified) {
|
|
const MappingStatus coordinate_status = EvaluateCompactificationCoordinate(
|
|
element_data.compactification, transformation, integration_point, workspace,
|
|
workspace.m_compactification_point
|
|
);
|
|
|
|
if (coordinate_status != MappingStatus::valid)
|
|
return coordinate_status;
|
|
|
|
const compactification::ExteriorMapInput exterior_input{
|
|
.reference_position = base_context.reference_position,
|
|
.displaced_position = base_context.displaced_position,
|
|
.displacement_jacobian = base_context.displacement_jacobian,
|
|
.compactification_coordinate = workspace.m_compactification_point.coordinate,
|
|
.compactification_coordinate_gradient = workspace.m_compactification_point.coordinate_gradient
|
|
};
|
|
|
|
workspace.m_exterior_result.physical_position = base_context.physical_position;
|
|
workspace.m_exterior_result.mapping_jacobian = base_context.mapping_jacobian;
|
|
|
|
const compactification::ExteriorMapDirection exterior_direction{
|
|
.displaced_position_variation = variation.displacement_variation,
|
|
.displacement_jacobian_variation = variation.displacement_jacobian_variation
|
|
};
|
|
|
|
// ReSharper disable once CppTooWideScopeInitStatement
|
|
const MappingStatus exterior_status = m_exterior_map->EvaluateVariation(
|
|
exterior_input, workspace.m_exterior_result, exterior_direction, workspace.m_exterior_variation
|
|
);
|
|
|
|
if (exterior_status != MappingStatus::valid) {
|
|
return exterior_status;
|
|
}
|
|
|
|
variation.physical_position_variation = workspace.m_exterior_variation.physical_position_variation;
|
|
variation.mapping_jacobian_variation = workspace.m_exterior_variation.mapping_jacobian_variation;
|
|
} else {
|
|
variation.physical_position_variation = variation.displacement_variation;
|
|
variation.mapping_jacobian_variation = variation.displacement_jacobian_variation;
|
|
}
|
|
|
|
mfem::Mult(
|
|
base_context.inverse_mapping_jacobian, variation.mapping_jacobian_variation, workspace.m_matrix_temp_1
|
|
);
|
|
|
|
double trace = 0.0;
|
|
for (int i = 0; i < m_options.dimension; ++i)
|
|
trace += workspace.m_matrix_temp_1(i, i);
|
|
variation.mapping_determinant_variation = base_context.mapping_determinant * trace;
|
|
|
|
variation.inverse_mapping_jacobian_variation.SetSize(m_options.dimension, m_options.dimension);
|
|
mfem::Mult(
|
|
workspace.m_matrix_temp_1, base_context.inverse_mapping_jacobian,
|
|
variation.inverse_mapping_jacobian_variation
|
|
);
|
|
variation.inverse_mapping_jacobian_variation *= -1.0;
|
|
|
|
if (!vector_is_finite(variation.physical_position_variation) ||
|
|
!matrix_is_finite(variation.mapping_jacobian_variation) ||
|
|
!matrix_is_finite(variation.inverse_mapping_jacobian_variation) ||
|
|
!std::isfinite(variation.mapping_determinant_variation)) {
|
|
return MappingStatus::non_finite_result;
|
|
}
|
|
|
|
return MappingStatus::valid;
|
|
}
|
|
|
|
MappingStatus DomainMapperStateless::EvaluateVolumeVariation(
|
|
const ElementMappingData &element_data,
|
|
const ElementDisplacementData &direction,
|
|
mfem::ElementTransformation &transformation,
|
|
const mfem::IntegrationPoint &integration_point,
|
|
const VolumeMappingContext &base_context,
|
|
Workspace &workspace,
|
|
VolumeMappingVariation &variation
|
|
) const {
|
|
const MappingStatus point_status = EvaluatePointVariation(
|
|
element_data, direction, transformation, integration_point, base_context.mapping, workspace,
|
|
variation.mapping
|
|
);
|
|
if (point_status != MappingStatus::valid)
|
|
return point_status;
|
|
|
|
transformation.SetIntPoint(&integration_point);
|
|
mfem::Mult(
|
|
variation.mapping.mapping_jacobian_variation, transformation.Jacobian(), workspace.m_full_element_jacobian
|
|
);
|
|
mfem::Mult(base_context.quadrature.J_inv, workspace.m_full_element_jacobian, workspace.m_matrix_temp_1);
|
|
|
|
variation.inverse_element_jacobian_variation.SetSize(m_options.dimension, m_options.dimension);
|
|
mfem::Mult(
|
|
workspace.m_matrix_temp_1, base_context.quadrature.J_inv, variation.inverse_element_jacobian_variation
|
|
);
|
|
variation.inverse_element_jacobian_variation *= -1.0;
|
|
|
|
variation.weight_variation =
|
|
integration_point.weight * transformation.Weight() * variation.mapping.mapping_determinant_variation;
|
|
|
|
if (!matrix_is_finite(variation.inverse_element_jacobian_variation) ||
|
|
!std::isfinite(variation.weight_variation))
|
|
return MappingStatus::non_finite_result;
|
|
|
|
return MappingStatus::valid;
|
|
}
|
|
|
|
MappingStatus DomainMapperStateless::EvaluateFaceVariation(
|
|
const ElementMappingData &element_data,
|
|
const ElementDisplacementData &direction,
|
|
mfem::FaceElementTransformations &transformation,
|
|
const FaceElementSide side,
|
|
const mfem::IntegrationPoint &integration_point,
|
|
const FaceMappingContext &base_context,
|
|
Workspace &workspace,
|
|
FaceMappingVariation &variation
|
|
) const {
|
|
transformation.SetAllIntPoints(&integration_point);
|
|
mfem::ElementTransformation &element_transformation = SelectFaceElementTransformation(transformation, side);
|
|
const mfem::IntegrationPoint &element_integration_point =
|
|
SelectFaceElementIntegrationPoint(transformation, side);
|
|
|
|
const MappingStatus point_status = EvaluatePointVariation(
|
|
element_data, direction, element_transformation, element_integration_point, base_context.mapping, workspace,
|
|
variation.mapping
|
|
);
|
|
if (point_status != MappingStatus::valid)
|
|
return point_status;
|
|
|
|
workspace.m_reference_normal.SetSize(m_options.dimension);
|
|
mfem::CalcOrtho(transformation.Jacobian(), workspace.m_reference_normal);
|
|
if (side == FaceElementSide::element_2)
|
|
workspace.m_reference_normal *= -1.0;
|
|
|
|
const double reference_normal_magnitude = workspace.m_reference_normal.Norml2();
|
|
if (!std::isfinite(reference_normal_magnitude) || reference_normal_magnitude <= 0.0)
|
|
return MappingStatus::non_finite_result;
|
|
|
|
base_context.mapping.inverse_mapping_jacobian.MultTranspose(
|
|
workspace.m_reference_normal, workspace.m_vector_temp
|
|
);
|
|
workspace.m_mapped_normal = workspace.m_vector_temp;
|
|
workspace.m_mapped_normal *= base_context.mapping.mapping_determinant;
|
|
|
|
variation.physical_normal_variation.SetSize(m_options.dimension);
|
|
variation.mapping.inverse_mapping_jacobian_variation.MultTranspose(
|
|
workspace.m_reference_normal, variation.physical_normal_variation
|
|
);
|
|
variation.physical_normal_variation *= base_context.mapping.mapping_determinant;
|
|
variation.physical_normal_variation.Add(
|
|
variation.mapping.mapping_determinant_variation, workspace.m_vector_temp
|
|
);
|
|
|
|
const double mapped_normal_magnitude = workspace.m_mapped_normal.Norml2();
|
|
if (!std::isfinite(mapped_normal_magnitude) || mapped_normal_magnitude <= 0.0)
|
|
return MappingStatus::non_finite_result;
|
|
|
|
const double mapped_normal_magnitude_variation =
|
|
base_context.quadrature.normal * variation.physical_normal_variation;
|
|
|
|
variation.physical_normal_variation.Add(-mapped_normal_magnitude_variation, base_context.quadrature.normal);
|
|
variation.physical_normal_variation /= mapped_normal_magnitude;
|
|
|
|
variation.physical_surface_weight_variation = integration_point.weight * mapped_normal_magnitude_variation;
|
|
variation.normal_flux_scale_variation = mapped_normal_magnitude_variation / reference_normal_magnitude;
|
|
|
|
if (!vector_is_finite(variation.physical_normal_variation) ||
|
|
!std::isfinite(variation.physical_surface_weight_variation) ||
|
|
!std::isfinite(variation.normal_flux_scale_variation)) {
|
|
return MappingStatus::non_finite_result;
|
|
}
|
|
|
|
return MappingStatus::valid;
|
|
}
|
|
} // namespace mean_field::mapping
|