2026-07-15 09:44:43 -04:00
|
|
|
module;
|
|
|
|
|
|
|
|
|
|
#include "mean_field.h"
|
2026-09-16 14:34:06 -04:00
|
|
|
#include <cstddef>
|
|
|
|
|
#include <cstdint>
|
2026-07-15 09:44:43 -04:00
|
|
|
|
|
|
|
|
export module mean_field:mapping.domain_mapper;
|
2026-08-04 14:24:55 -04:00
|
|
|
export import :mapping.types;
|
|
|
|
|
import :mapping.compactification;
|
|
|
|
|
import :utils.user;
|
2026-07-15 09:44:43 -04:00
|
|
|
|
|
|
|
|
export namespace mean_field::mapping {
|
2026-08-30 16:41:14 -04:00
|
|
|
enum class FaceElementSide : uint8_t { element_1, element_2 };
|
|
|
|
|
|
|
|
|
|
class ElementDisplacementData {
|
|
|
|
|
public:
|
|
|
|
|
ElementDisplacementData(
|
|
|
|
|
const mfem::FiniteElement &element,
|
|
|
|
|
const mfem::Vector &displacement_dofs,
|
|
|
|
|
mfem::Ordering::Type ordering = mfem::Ordering::byNODES
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] const mfem::FiniteElement &GetElement() const noexcept;
|
|
|
|
|
[[nodiscard]] const mfem::DenseMatrix &GetDofMatrix() const noexcept;
|
|
|
|
|
[[nodiscard]] int GetDimension() const noexcept;
|
|
|
|
|
[[nodiscard]] int GetDofCount() const noexcept;
|
|
|
|
|
[[nodiscard]] mfem::Ordering::Type GetOrdering() const noexcept;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const mfem::FiniteElement *m_element;
|
|
|
|
|
mfem::DenseMatrix m_dof_matrix;
|
|
|
|
|
int m_dimension;
|
|
|
|
|
mfem::Ordering::Type m_ordering;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CompactificationPointData {
|
|
|
|
|
double coordinate{0.0};
|
|
|
|
|
mfem::Vector coordinate_gradient;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] ElementDisplacementData ElementDisplacementDataFromElementVDofs(
|
|
|
|
|
const mfem::FiniteElement &element,
|
|
|
|
|
const mfem::Vector &displacement_dofs
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
class ElementCompactificationData {
|
|
|
|
|
public:
|
|
|
|
|
ElementCompactificationData(
|
|
|
|
|
const mfem::FiniteElement &element,
|
|
|
|
|
const mfem::Vector &dofs
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] const mfem::FiniteElement &GetElement() const noexcept;
|
|
|
|
|
[[nodiscard]] const mfem::Vector &GetDofs() const noexcept;
|
|
|
|
|
[[nodiscard]] int GetDofCount() const noexcept;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const mfem::FiniteElement *m_element;
|
|
|
|
|
mfem::Vector m_dofs;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct ElementMappingData {
|
|
|
|
|
const ElementDisplacementData &displacement;
|
|
|
|
|
const ElementCompactificationData &compactification;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class DomainMapper {
|
|
|
|
|
public:
|
|
|
|
|
class Workspace {
|
|
|
|
|
public:
|
|
|
|
|
explicit Workspace(int dimension = 3);
|
|
|
|
|
|
|
|
|
|
void SetDimension(int dimension);
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] int GetDimension() const noexcept;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
friend class DomainMapper;
|
|
|
|
|
|
|
|
|
|
int m_dimension;
|
|
|
|
|
|
|
|
|
|
mfem::Vector m_shape;
|
2026-09-02 17:01:50 -04:00
|
|
|
mfem::DenseMatrix m_reference_dshape;
|
2026-08-30 16:41:14 -04:00
|
|
|
mfem::DenseMatrix m_mesh_dshape;
|
2026-09-10 06:50:56 -04:00
|
|
|
mfem::DenseMatrix m_reference_field_jacobian;
|
2026-08-30 16:41:14 -04:00
|
|
|
mfem::Vector m_field_value;
|
|
|
|
|
mfem::DenseMatrix m_field_jacobian;
|
|
|
|
|
|
|
|
|
|
mfem::Vector m_compactification_shape;
|
|
|
|
|
mfem::DenseMatrix m_compactification_dshape;
|
|
|
|
|
CompactificationPointData m_compactification_point;
|
|
|
|
|
|
|
|
|
|
mfem::Vector m_reference_normal;
|
|
|
|
|
mfem::Vector m_mapped_normal;
|
|
|
|
|
mfem::DenseMatrix m_full_element_jacobian;
|
|
|
|
|
|
|
|
|
|
mfem::Vector m_vector_temp;
|
|
|
|
|
mfem::DenseMatrix m_matrix_temp_1;
|
|
|
|
|
mfem::DenseMatrix m_matrix_temp_2;
|
|
|
|
|
|
|
|
|
|
compactification::ExteriorMapResult m_exterior_result;
|
|
|
|
|
compactification::ExteriorMapVariation m_exterior_variation;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
DomainMapper(
|
|
|
|
|
utils::DomainMapperOptions options,
|
|
|
|
|
std::unique_ptr<const compactification::ExteriorDomainMap> exterior_map
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
DomainMapper(const DomainMapper &) = delete;
|
|
|
|
|
DomainMapper &operator=(const DomainMapper &) = delete;
|
2026-09-16 14:34:06 -04:00
|
|
|
~DomainMapper();
|
|
|
|
|
DomainMapper(DomainMapper &&) noexcept;
|
|
|
|
|
DomainMapper &operator=(DomainMapper &&) noexcept;
|
|
|
|
|
|
|
|
|
|
struct FixedMeshGeometry {
|
|
|
|
|
mfem::Vector position;
|
|
|
|
|
mfem::DenseMatrix jacobian, inverseJacobian;
|
|
|
|
|
double weight{0.0};
|
|
|
|
|
};
|
|
|
|
|
struct GeometryCacheStatistics {
|
|
|
|
|
std::uint64_t hits{0}, misses{0};
|
|
|
|
|
std::size_t points{0};
|
|
|
|
|
};
|
|
|
|
|
// Only computational-mesh geometry is cached, never displacement or
|
|
|
|
|
// compactification state. MFEM mesh/node sequence changes invalidate it.
|
|
|
|
|
// After raw coordinate edits call Mesh::NodesUpdated(), as required by
|
|
|
|
|
// MFEM's own geometric-factor cache, or ClearGeometryCache(). A mesh
|
|
|
|
|
// must outlive its cached entries; clear before destroying/replacing it.
|
|
|
|
|
// Like MFEM element transformations, this cache is not thread-safe.
|
|
|
|
|
void SetGeometryCacheEnabled(bool enabled) const;
|
|
|
|
|
[[nodiscard]] bool IsGeometryCacheEnabled() const noexcept;
|
|
|
|
|
void ClearGeometryCache() const;
|
|
|
|
|
[[nodiscard]] GeometryCacheStatistics GetGeometryCacheStatistics() const;
|
|
|
|
|
// Sets the transformation's integration point. nullptr means use MFEM
|
|
|
|
|
// directly (disabled cache, non-mesh transformation, or unsupported data).
|
|
|
|
|
// Returned data remains valid until cache invalidation or mapper destruction.
|
|
|
|
|
[[nodiscard]] const FixedMeshGeometry *GetFixedMeshGeometry(
|
|
|
|
|
mfem::ElementTransformation &transformation, const mfem::IntegrationPoint &point
|
|
|
|
|
) const;
|
2026-08-30 16:41:14 -04:00
|
|
|
|
|
|
|
|
[[nodiscard]] MappingStatus EvaluatePoint(
|
|
|
|
|
const ElementMappingData &element_data,
|
|
|
|
|
mfem::ElementTransformation &transformation,
|
|
|
|
|
const mfem::IntegrationPoint &integration_point,
|
|
|
|
|
Workspace &workspace,
|
|
|
|
|
MappingPointContext &context
|
|
|
|
|
) const;
|
|
|
|
|
|
2026-09-16 14:34:06 -04:00
|
|
|
// A sample from the same element DOFs and integration point. Its
|
|
|
|
|
// gradient is with respect to finite-element coordinates, not the mesh.
|
|
|
|
|
struct ReferenceDisplacementSample {
|
|
|
|
|
const mfem::Vector &value;
|
|
|
|
|
const mfem::DenseMatrix &gradient;
|
|
|
|
|
};
|
2026-08-30 16:41:14 -04:00
|
|
|
[[nodiscard]] MappingStatus EvaluateVolume(
|
|
|
|
|
const ElementMappingData &element_data,
|
|
|
|
|
mfem::ElementTransformation &transformation,
|
|
|
|
|
const mfem::IntegrationPoint &integration_point,
|
|
|
|
|
Workspace &workspace,
|
2026-09-16 14:34:06 -04:00
|
|
|
VolumeMappingContext &context,
|
|
|
|
|
const ReferenceDisplacementSample *displacementSample = nullptr
|
2026-08-30 16:41:14 -04:00
|
|
|
) const;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] MappingStatus EvaluateFace(
|
|
|
|
|
const ElementMappingData &element_data,
|
|
|
|
|
mfem::FaceElementTransformations &transformation,
|
|
|
|
|
FaceElementSide side,
|
|
|
|
|
const mfem::IntegrationPoint &integration_point,
|
|
|
|
|
Workspace &workspace,
|
|
|
|
|
FaceMappingContext &context
|
|
|
|
|
) const;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] MappingStatus 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;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] MappingStatus 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;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] MappingStatus EvaluateFaceVariation(
|
|
|
|
|
const ElementMappingData &element_data,
|
|
|
|
|
const ElementDisplacementData &direction,
|
|
|
|
|
mfem::FaceElementTransformations &transformation,
|
|
|
|
|
FaceElementSide side,
|
|
|
|
|
const mfem::IntegrationPoint &integration_point,
|
|
|
|
|
const FaceMappingContext &base_context,
|
|
|
|
|
Workspace &workspace,
|
|
|
|
|
FaceMappingVariation &variation
|
|
|
|
|
) const;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] bool IsCompactifiedElement(const mfem::ElementTransformation &transformation) const noexcept;
|
|
|
|
|
[[nodiscard]] int GetDimension() const noexcept;
|
|
|
|
|
[[nodiscard]] const compactification::ExteriorDomainMap &GetExteriorMap() const noexcept;
|
|
|
|
|
|
|
|
|
|
private:
|
2026-09-16 14:34:06 -04:00
|
|
|
[[nodiscard]] MappingStatus EvaluatePointImpl(
|
|
|
|
|
const ElementMappingData &element_data, mfem::ElementTransformation &transformation,
|
|
|
|
|
const mfem::IntegrationPoint &integration_point, Workspace &workspace,
|
|
|
|
|
MappingPointContext &context, const FixedMeshGeometry *meshGeometry,
|
|
|
|
|
const ReferenceDisplacementSample *displacementSample = nullptr
|
|
|
|
|
) const;
|
2026-08-30 16:41:14 -04:00
|
|
|
void ValidateElementData(const ElementMappingData &element_data) const;
|
|
|
|
|
|
|
|
|
|
void EvaluateField(
|
|
|
|
|
const ElementDisplacementData &field,
|
|
|
|
|
mfem::ElementTransformation &transformation,
|
|
|
|
|
const mfem::IntegrationPoint &integration_point,
|
|
|
|
|
Workspace &workspace,
|
|
|
|
|
mfem::Vector &value,
|
2026-09-02 17:01:50 -04:00
|
|
|
mfem::DenseMatrix &jacobian,
|
|
|
|
|
const mfem::DenseMatrix *inverse_mesh_jacobian
|
2026-08-30 16:41:14 -04:00
|
|
|
) const;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] MappingStatus EvaluateCompactificationCoordinate(
|
|
|
|
|
const ElementCompactificationData &compactification,
|
|
|
|
|
mfem::ElementTransformation &transformation,
|
|
|
|
|
const mfem::IntegrationPoint &integration_point,
|
|
|
|
|
Workspace &workspace,
|
2026-09-02 17:01:50 -04:00
|
|
|
CompactificationPointData &point_data,
|
|
|
|
|
const mfem::DenseMatrix *inverse_mesh_jacobian
|
|
|
|
|
) const;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] MappingStatus EvaluatePointVariationImpl(
|
|
|
|
|
const ElementMappingData &element_data,
|
|
|
|
|
const ElementDisplacementData &direction,
|
|
|
|
|
mfem::ElementTransformation &transformation,
|
|
|
|
|
const mfem::IntegrationPoint &integration_point,
|
|
|
|
|
const MappingPointContext &base_context,
|
|
|
|
|
Workspace &workspace,
|
|
|
|
|
MappingPointVariation &variation,
|
|
|
|
|
const mfem::DenseMatrix *inverse_mesh_jacobian
|
2026-08-30 16:41:14 -04:00
|
|
|
) const;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] static mfem::ElementTransformation &SelectFaceElementTransformation(
|
|
|
|
|
mfem::FaceElementTransformations &transformation,
|
|
|
|
|
FaceElementSide side
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] static const mfem::IntegrationPoint &SelectFaceElementIntegrationPoint(
|
|
|
|
|
mfem::FaceElementTransformations &transformation,
|
|
|
|
|
FaceElementSide side
|
|
|
|
|
);
|
|
|
|
|
|
2026-09-16 14:34:06 -04:00
|
|
|
struct GeometryCache;
|
|
|
|
|
mutable std::unique_ptr<GeometryCache> m_geometryCache;
|
2026-08-30 16:41:14 -04:00
|
|
|
utils::DomainMapperOptions m_options;
|
|
|
|
|
std::unique_ptr<const compactification::ExteriorDomainMap> m_exterior_map;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class GridFunctionMappingEvaluator {
|
|
|
|
|
public:
|
|
|
|
|
/*
|
|
|
|
|
* The evaluator references the supplied grid functions and caches copies of
|
|
|
|
|
* their element-local DOFs. Call InvalidateCache() or Refresh() after either
|
|
|
|
|
* grid function's values are modified. Finite-element-space sequence changes
|
|
|
|
|
* are detected automatically.
|
|
|
|
|
*
|
|
|
|
|
* This object owns mutable workspace and cache state and is not thread-safe.
|
|
|
|
|
*/
|
|
|
|
|
GridFunctionMappingEvaluator(
|
|
|
|
|
const DomainMapper &mapper,
|
|
|
|
|
const mfem::GridFunction &displacement,
|
|
|
|
|
const mfem::GridFunction &compactification_coordinate
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Discard all element-local field data. The next evaluation reloads its
|
|
|
|
|
* requested element lazily. This operation is idempotent.
|
|
|
|
|
*/
|
|
|
|
|
void InvalidateCache() noexcept;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Reload the currently cached element immediately. If no element has been
|
|
|
|
|
* evaluated yet, Refresh() is a validated no-op. If either finite-element
|
|
|
|
|
* space changed sequence, the old element ID is discarded and the next
|
|
|
|
|
* evaluation reloads lazily against the updated spaces.
|
|
|
|
|
*/
|
|
|
|
|
void Refresh();
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] MappingStatus EvaluatePoint(
|
|
|
|
|
mfem::ElementTransformation &transformation,
|
|
|
|
|
const mfem::IntegrationPoint &integration_point,
|
|
|
|
|
MappingPointContext &context
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] MappingStatus EvaluateVolume(
|
|
|
|
|
mfem::ElementTransformation &transformation,
|
|
|
|
|
const mfem::IntegrationPoint &integration_point,
|
|
|
|
|
VolumeMappingContext &context
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] MappingStatus EvaluateFace(
|
|
|
|
|
mfem::FaceElementTransformations &transformation,
|
|
|
|
|
FaceElementSide side,
|
|
|
|
|
const mfem::IntegrationPoint &integration_point,
|
|
|
|
|
FaceMappingContext &context
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] VolumeQuadratureContext GetQuadratureContext(
|
|
|
|
|
mfem::ElementTransformation &transformation,
|
|
|
|
|
const mfem::IntegrationPoint &integration_point
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] FaceQuadratureContext GetFaceQuadratureContext(
|
|
|
|
|
mfem::FaceElementTransformations &transformation,
|
|
|
|
|
const mfem::IntegrationPoint &integration_point,
|
|
|
|
|
FaceElementSide side = FaceElementSide::element_1
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
void GetPhysicalPoint(
|
|
|
|
|
mfem::ElementTransformation &transformation,
|
|
|
|
|
const mfem::IntegrationPoint &integration_point,
|
|
|
|
|
mfem::Vector &physical_position
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void ValidateFieldBindings() const;
|
|
|
|
|
[[nodiscard]] bool InvalidateForChangedSpaces();
|
|
|
|
|
void LoadElement(int element_id);
|
|
|
|
|
|
|
|
|
|
const DomainMapper &m_mapper;
|
|
|
|
|
const mfem::GridFunction &m_displacement;
|
|
|
|
|
const mfem::GridFunction &m_compactification_coordinate;
|
|
|
|
|
const mfem::FiniteElementSpace *m_displacement_space;
|
|
|
|
|
const mfem::FiniteElementSpace *m_compactification_space;
|
|
|
|
|
long m_displacement_space_sequence;
|
|
|
|
|
long m_compactification_space_sequence;
|
|
|
|
|
DomainMapper::Workspace m_workspace;
|
|
|
|
|
|
|
|
|
|
mfem::Array<int> m_displacement_dofs;
|
|
|
|
|
mfem::Array<int> m_compactification_dofs;
|
|
|
|
|
mfem::Vector m_element_displacement;
|
|
|
|
|
mfem::Vector m_element_compactification;
|
|
|
|
|
std::unique_ptr<ElementDisplacementData> m_displacement_data;
|
|
|
|
|
std::unique_ptr<ElementCompactificationData> m_compactification_data;
|
|
|
|
|
int m_cached_element_id{-1};
|
|
|
|
|
};
|
2026-07-15 09:44:43 -04:00
|
|
|
|
2026-08-04 14:24:55 -04:00
|
|
|
} // namespace mean_field::mapping
|