feat(surface): surface deformation prescriptions
restricted the unknown state vector to surface deformation and implemented one prescription, NodalRadialSurface, while the full volumetric displacment field is reconstructed analytically from that. This reduced the number of degrees of freedom in the system by a factor of 80 while also removing many null vectors from the system.
This commit is contained in:
111
libmeanfield/interface/deformation/descriptors.cppm
Normal file
111
libmeanfield/interface/deformation/descriptors.cppm
Normal file
@@ -0,0 +1,111 @@
|
||||
module;
|
||||
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
|
||||
export module mean_field:deformation.descriptors;
|
||||
|
||||
export namespace mean_field::deformation {
|
||||
enum class SurfaceMotionKind : std::uint8_t { Radial, Normal, GeneralVector };
|
||||
|
||||
enum class GeometricGaugeTreatment : std::uint8_t {
|
||||
Retained,
|
||||
ExcludedByParameterization,
|
||||
ConstrainedByPrescription
|
||||
};
|
||||
|
||||
enum class InteriorCenterBehavior : std::uint8_t { Unspecified, FixedAtReferenceCenter, DeterminedBySurfaceMotion };
|
||||
|
||||
enum class VacuumOuterBoundaryBehavior : std::uint8_t {
|
||||
Unspecified,
|
||||
FixedAtReferenceInfinity,
|
||||
DeterminedBySurfaceMotion
|
||||
};
|
||||
|
||||
struct SurfaceDeformationDescriptor final {
|
||||
std::string_view name;
|
||||
int spatialDimension;
|
||||
SurfaceMotionKind motionKind;
|
||||
bool linearOnReferenceGeometry;
|
||||
bool requiresStarShapedReferenceSurface;
|
||||
bool hasExactDerivativeTranspose;
|
||||
bool hasExactPullbackDerivative;
|
||||
GeometricGaugeTreatment translationTreatment;
|
||||
GeometricGaugeTreatment orientationTreatment;
|
||||
|
||||
[[nodiscard]] constexpr bool isValid() const noexcept {
|
||||
return !name.empty() && spatialDimension > 0;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool supportsExactNewtonLinearization() const noexcept {
|
||||
return hasExactDerivativeTranspose && hasExactPullbackDerivative;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const SurfaceDeformationDescriptor &) const = default;
|
||||
};
|
||||
|
||||
struct InteriorDeformationExtensionDescriptor final {
|
||||
std::string_view name;
|
||||
int spatialDimension;
|
||||
bool linearOnReferenceGeometry;
|
||||
bool requiresRadialFoliation;
|
||||
bool requiresAuxiliarySolve;
|
||||
bool hasExactDerivativeTranspose;
|
||||
bool hasExactPullbackDerivative;
|
||||
InteriorCenterBehavior centerBehavior;
|
||||
|
||||
[[nodiscard]] constexpr bool isValid() const noexcept {
|
||||
return !name.empty() && spatialDimension > 0 && centerBehavior != InteriorCenterBehavior::Unspecified;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool supportsExactNewtonLinearization() const noexcept {
|
||||
return hasExactDerivativeTranspose && hasExactPullbackDerivative;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const InteriorDeformationExtensionDescriptor &) const = default;
|
||||
};
|
||||
|
||||
struct VacuumDeformationExtensionDescriptor final {
|
||||
std::string_view name;
|
||||
int spatialDimension;
|
||||
bool linearOnReferenceGeometry;
|
||||
bool requiresRadialFoliation;
|
||||
bool requiresAuxiliarySolve;
|
||||
bool hasExactDerivativeTranspose;
|
||||
bool hasExactPullbackDerivative;
|
||||
VacuumOuterBoundaryBehavior outerBoundaryBehavior;
|
||||
|
||||
[[nodiscard]] constexpr bool isValid() const noexcept {
|
||||
return !name.empty() && spatialDimension > 0 &&
|
||||
outerBoundaryBehavior != VacuumOuterBoundaryBehavior::Unspecified;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool supportsExactNewtonLinearization() const noexcept {
|
||||
return hasExactDerivativeTranspose && hasExactPullbackDerivative;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const VacuumDeformationExtensionDescriptor &) const = default;
|
||||
};
|
||||
|
||||
struct DomainDeformationDescriptor final {
|
||||
SurfaceDeformationDescriptor surfaceDeformation;
|
||||
InteriorDeformationExtensionDescriptor stellarInteriorExtension;
|
||||
VacuumDeformationExtensionDescriptor vacuumExtension;
|
||||
bool linearOnReferenceGeometry;
|
||||
bool requiresAuxiliarySolve;
|
||||
bool hasExactDerivativeTranspose;
|
||||
bool hasExactPullbackDerivative;
|
||||
|
||||
[[nodiscard]] constexpr bool isValid() const noexcept {
|
||||
return surfaceDeformation.isValid() && stellarInteriorExtension.isValid() && vacuumExtension.isValid() &&
|
||||
surfaceDeformation.spatialDimension == stellarInteriorExtension.spatialDimension &&
|
||||
surfaceDeformation.spatialDimension == vacuumExtension.spatialDimension;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool supportsExactNewtonLinearization() const noexcept {
|
||||
return hasExactDerivativeTranspose && hasExactPullbackDerivative;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const DomainDeformationDescriptor &) const = default;
|
||||
};
|
||||
} // namespace mean_field::deformation
|
||||
870
libmeanfield/interface/deformation/domain_deformation.cppm
Normal file
870
libmeanfield/interface/deformation/domain_deformation.cppm
Normal file
@@ -0,0 +1,870 @@
|
||||
module;
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <compare>
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <mfem.hpp>
|
||||
#include <mpi.h>
|
||||
|
||||
export module mean_field:deformation.domain_deformation;
|
||||
|
||||
export import :deformation.interior_extension;
|
||||
export import :deformation.nodal_radial_surface;
|
||||
export import :deformation.radial_extensions;
|
||||
export import :deformation.surface_prescription;
|
||||
export import :deformation.vacuum_extension;
|
||||
export import :fem;
|
||||
export import :field.mfem;
|
||||
export import :utils.domain;
|
||||
|
||||
export namespace mean_field::deformation {
|
||||
enum class VolumeDeformationOwner : std::uint8_t { StellarInterior, Vacuum };
|
||||
|
||||
struct DomainDeformationDiscretizationDependencies final {
|
||||
const mfem::Mesh *physicalMeshIdentity{nullptr};
|
||||
const mfem::ParMesh *logicalReferenceMeshIdentity{nullptr};
|
||||
const mfem::ParFiniteElementSpace *surfaceScalarSpaceIdentity{nullptr};
|
||||
const mfem::ParFiniteElementSpace *volumeDisplacementSpaceIdentity{nullptr};
|
||||
long physicalMeshSequence{-1};
|
||||
long logicalReferenceMeshSequence{-1};
|
||||
long surfaceScalarSpaceSequence{-1};
|
||||
long volumeDisplacementSpaceSequence{-1};
|
||||
|
||||
[[nodiscard]] bool isCurrent() const noexcept {
|
||||
return physicalMeshIdentity != nullptr && logicalReferenceMeshIdentity != nullptr &&
|
||||
surfaceScalarSpaceIdentity != nullptr && volumeDisplacementSpaceIdentity != nullptr &&
|
||||
physicalMeshIdentity->GetSequence() == physicalMeshSequence &&
|
||||
logicalReferenceMeshIdentity->GetSequence() == logicalReferenceMeshSequence &&
|
||||
surfaceScalarSpaceIdentity->GetSequence() == surfaceScalarSpaceSequence &&
|
||||
volumeDisplacementSpaceIdentity->GetSequence() == volumeDisplacementSpaceSequence;
|
||||
}
|
||||
};
|
||||
|
||||
struct DomainDeformationCompositionReport final {
|
||||
int scalarTrueDofCount{0};
|
||||
int stellarInteriorOwnedScalarDofCount{0};
|
||||
int vacuumOwnedScalarDofCount{0};
|
||||
int sharedSurfaceScalarDofCount{0};
|
||||
|
||||
[[nodiscard]] constexpr int assignedScalarDofCount() const noexcept {
|
||||
return stellarInteriorOwnedScalarDofCount + vacuumOwnedScalarDofCount;
|
||||
}
|
||||
|
||||
constexpr auto operator<=>(const DomainDeformationCompositionReport &) const = default;
|
||||
};
|
||||
|
||||
struct DomainDeformationGeometryReport final {
|
||||
double minimumJacobianDeterminant{std::numeric_limits<double>::infinity()};
|
||||
|
||||
[[nodiscard]] bool isOrientationPreserving(const double determinantFloor = 0.0) const noexcept {
|
||||
return std::isfinite(minimumJacobianDeterminant) && std::isfinite(determinantFloor) &&
|
||||
determinantFloor >= 0.0 && minimumJacobianDeterminant > determinantFloor;
|
||||
}
|
||||
};
|
||||
|
||||
struct PreparedDomainDeformationActionStatistics final {
|
||||
std::uint64_t volumeBuildApplications{0};
|
||||
std::uint64_t jacobianApplications{0};
|
||||
std::uint64_t jacobianTransposeApplications{0};
|
||||
std::uint64_t pullbackDerivativeApplications{0};
|
||||
std::uint64_t geometryInspections{0};
|
||||
|
||||
constexpr auto operator<=>(const PreparedDomainDeformationActionStatistics &) const = default;
|
||||
};
|
||||
|
||||
template <typename Candidate>
|
||||
concept PreparedDomainDeformationOperator = requires(
|
||||
const std::remove_cvref_t<Candidate> &preparedDeformation,
|
||||
const mfem::Vector ¶meters,
|
||||
const mfem::Vector ¶meterDirection,
|
||||
const mfem::Vector &volumeDisplacementDual,
|
||||
mfem::Vector &volumeDisplacement,
|
||||
mfem::Vector ¶meterDual
|
||||
) {
|
||||
{ preparedDeformation.descriptor() } noexcept -> std::same_as<DomainDeformationDescriptor>;
|
||||
{ preparedDeformation.parameterCount() } noexcept -> std::same_as<int>;
|
||||
{ preparedDeformation.surfaceDisplacementSize() } noexcept -> std::same_as<int>;
|
||||
{ preparedDeformation.volumeDisplacementSize() } noexcept -> std::same_as<int>;
|
||||
{ preparedDeformation.buildVolumeDisplacement(parameters, volumeDisplacement) } -> std::same_as<void>;
|
||||
{ preparedDeformation.applyJacobian(parameters, parameterDirection, volumeDisplacement) } -> std::same_as<void>;
|
||||
{
|
||||
preparedDeformation.applyJacobianTranspose(parameters, volumeDisplacementDual, parameterDual)
|
||||
} -> std::same_as<void>;
|
||||
{
|
||||
preparedDeformation.applyPullbackDerivative(
|
||||
parameters, parameterDirection, volumeDisplacementDual, parameterDual
|
||||
)
|
||||
} -> std::same_as<void>;
|
||||
};
|
||||
|
||||
template <
|
||||
PreparedSurfaceDeformationPrescription PreparedSurface,
|
||||
PreparedInteriorDeformationExtension PreparedInterior,
|
||||
PreparedVacuumDeformationExtension PreparedVacuum>
|
||||
class PreparedDomainDeformation final {
|
||||
public:
|
||||
PreparedDomainDeformation(
|
||||
PreparedSurface preparedSurface,
|
||||
PreparedInterior preparedInterior,
|
||||
PreparedVacuum preparedVacuum,
|
||||
mfem::ParFiniteElementSpace &surfaceScalarSpace,
|
||||
mfem::ParFiniteElementSpace &volumeDisplacementSpace,
|
||||
mfem::ParMesh &logicalReferenceMesh
|
||||
)
|
||||
: m_surface(std::move(preparedSurface)),
|
||||
m_interior(std::move(preparedInterior)),
|
||||
m_vacuum(std::move(preparedVacuum)),
|
||||
m_volumeDisplacementSpace(&volumeDisplacementSpace),
|
||||
m_descriptor(makeDescriptor(
|
||||
m_surface,
|
||||
m_interior,
|
||||
m_vacuum
|
||||
)),
|
||||
m_surfaceDisplacementWorkspace(surfaceDisplacementSize()),
|
||||
m_surfaceDirectionWorkspace(surfaceDisplacementSize()),
|
||||
m_interiorVolumeWorkspace(volumeDisplacementSize()),
|
||||
m_vacuumVolumeWorkspace(volumeDisplacementSize()),
|
||||
m_interiorVolumeDualWorkspace(volumeDisplacementSize()),
|
||||
m_vacuumVolumeDualWorkspace(volumeDisplacementSize()),
|
||||
m_interiorSurfaceDualWorkspace(surfaceDisplacementSize()),
|
||||
m_vacuumSurfaceDualWorkspace(surfaceDisplacementSize()),
|
||||
m_surfaceDualWorkspace(surfaceDisplacementSize()),
|
||||
m_interiorSurfacePullbackWorkspace(surfaceDisplacementSize()),
|
||||
m_vacuumSurfacePullbackWorkspace(surfaceDisplacementSize()),
|
||||
m_surfacePullbackWorkspace(surfaceDisplacementSize()),
|
||||
m_parameterPullbackWorkspace(parameterCount()),
|
||||
m_volumeGridFunctionWorkspace(std::make_unique<mfem::ParGridFunction>(&volumeDisplacementSpace)) {
|
||||
validateCompatibility(surfaceScalarSpace, volumeDisplacementSpace, logicalReferenceMesh);
|
||||
compileOwnership();
|
||||
|
||||
const mfem::Mesh *physicalMesh = volumeDisplacementSpace.GetMesh();
|
||||
m_discretizationDependencies = {
|
||||
.physicalMeshIdentity = physicalMesh,
|
||||
.logicalReferenceMeshIdentity = &logicalReferenceMesh,
|
||||
.surfaceScalarSpaceIdentity = &surfaceScalarSpace,
|
||||
.volumeDisplacementSpaceIdentity = &volumeDisplacementSpace,
|
||||
.physicalMeshSequence = physicalMesh->GetSequence(),
|
||||
.logicalReferenceMeshSequence = logicalReferenceMesh.GetSequence(),
|
||||
.surfaceScalarSpaceSequence = surfaceScalarSpace.GetSequence(),
|
||||
.volumeDisplacementSpaceSequence = volumeDisplacementSpace.GetSequence()
|
||||
};
|
||||
}
|
||||
|
||||
PreparedDomainDeformation(const PreparedDomainDeformation &) = delete;
|
||||
PreparedDomainDeformation &operator=(const PreparedDomainDeformation &) = delete;
|
||||
PreparedDomainDeformation(PreparedDomainDeformation &&) noexcept = default;
|
||||
PreparedDomainDeformation &operator=(PreparedDomainDeformation &&) noexcept = default;
|
||||
|
||||
[[nodiscard]] DomainDeformationDescriptor descriptor() const noexcept {
|
||||
return m_descriptor;
|
||||
}
|
||||
|
||||
[[nodiscard]] int parameterCount() const noexcept {
|
||||
return m_surface.parameterCount();
|
||||
}
|
||||
|
||||
[[nodiscard]] int surfaceDisplacementSize() const noexcept {
|
||||
return m_surface.surfaceDisplacementSize();
|
||||
}
|
||||
|
||||
[[nodiscard]] int volumeDisplacementSize() const noexcept {
|
||||
return m_interior.interiorDisplacementSize();
|
||||
}
|
||||
|
||||
[[nodiscard]] int scalarTrueDofCount() const noexcept {
|
||||
return m_interior.scalarTrueDofCount();
|
||||
}
|
||||
|
||||
[[nodiscard]] int spatialDimension() const noexcept {
|
||||
return m_descriptor.surfaceDeformation.spatialDimension;
|
||||
}
|
||||
|
||||
[[nodiscard]] VolumeDeformationOwner volumeOwner(const int scalarTrueDof) const {
|
||||
requireScalarTrueDof(scalarTrueDof);
|
||||
return m_volumeOwners[static_cast<std::size_t>(scalarTrueDof)];
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isSharedSurfaceDof(const int scalarTrueDof) const {
|
||||
requireScalarTrueDof(scalarTrueDof);
|
||||
return m_interior.hasStellarSupport(scalarTrueDof) && m_vacuum.hasVacuumSupport(scalarTrueDof);
|
||||
}
|
||||
|
||||
[[nodiscard]] const DomainDeformationCompositionReport &compositionReport() const noexcept {
|
||||
return m_compositionReport;
|
||||
}
|
||||
|
||||
[[nodiscard]] const DomainDeformationDiscretizationDependencies &discretizationDependencies() const noexcept {
|
||||
return m_discretizationDependencies;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool matchesCurrentDiscretization() const noexcept {
|
||||
return m_discretizationDependencies.isCurrent();
|
||||
}
|
||||
|
||||
[[nodiscard]] const PreparedDomainDeformationActionStatistics &actionStatistics() const noexcept {
|
||||
return m_actionStatistics;
|
||||
}
|
||||
|
||||
[[nodiscard]] const PreparedSurface &surfaceDeformationPrescription() const noexcept {
|
||||
return m_surface;
|
||||
}
|
||||
|
||||
[[nodiscard]] const PreparedInterior &stellarInteriorExtension() const noexcept {
|
||||
return m_interior;
|
||||
}
|
||||
|
||||
[[nodiscard]] const PreparedVacuum &vacuumExtension() const noexcept {
|
||||
return m_vacuum;
|
||||
}
|
||||
|
||||
void buildVolumeDisplacement(
|
||||
const mfem::Vector ¶meters,
|
||||
mfem::Vector &volumeDisplacement
|
||||
) const {
|
||||
requireCurrentDiscretization();
|
||||
requireParameterSize(parameters);
|
||||
requireVolumeSize(volumeDisplacement);
|
||||
|
||||
m_surface.buildSurfaceDisplacement(parameters, m_surfaceDisplacementWorkspace);
|
||||
m_interior.buildInteriorDisplacement(m_surfaceDisplacementWorkspace, m_interiorVolumeWorkspace);
|
||||
m_vacuum.buildVacuumDisplacement(m_surfaceDisplacementWorkspace, m_vacuumVolumeWorkspace);
|
||||
mergeVolumeFields(m_interiorVolumeWorkspace, m_vacuumVolumeWorkspace, volumeDisplacement);
|
||||
++m_actionStatistics.volumeBuildApplications;
|
||||
}
|
||||
|
||||
void applyJacobian(
|
||||
const mfem::Vector ¶meters,
|
||||
const mfem::Vector ¶meterDirection,
|
||||
mfem::Vector &volumeDisplacementDirection
|
||||
) const {
|
||||
requireCurrentDiscretization();
|
||||
requireParameterSize(parameters);
|
||||
requireParameterSize(parameterDirection);
|
||||
requireVolumeSize(volumeDisplacementDirection);
|
||||
|
||||
m_surface.buildSurfaceDisplacement(parameters, m_surfaceDisplacementWorkspace);
|
||||
m_surface.applyJacobian(parameters, parameterDirection, m_surfaceDirectionWorkspace);
|
||||
m_interior.applyJacobian(
|
||||
m_surfaceDisplacementWorkspace, m_surfaceDirectionWorkspace, m_interiorVolumeWorkspace
|
||||
);
|
||||
m_vacuum.applyJacobian(
|
||||
m_surfaceDisplacementWorkspace, m_surfaceDirectionWorkspace, m_vacuumVolumeWorkspace
|
||||
);
|
||||
mergeVolumeFields(m_interiorVolumeWorkspace, m_vacuumVolumeWorkspace, volumeDisplacementDirection);
|
||||
++m_actionStatistics.jacobianApplications;
|
||||
}
|
||||
|
||||
void applyJacobianTranspose(
|
||||
const mfem::Vector ¶meters,
|
||||
const mfem::Vector &volumeDisplacementDual,
|
||||
mfem::Vector ¶meterDual
|
||||
) const {
|
||||
requireCurrentDiscretization();
|
||||
requireParameterSize(parameters);
|
||||
requireVolumeSize(volumeDisplacementDual);
|
||||
requireParameterSize(parameterDual);
|
||||
|
||||
m_surface.buildSurfaceDisplacement(parameters, m_surfaceDisplacementWorkspace);
|
||||
splitVolumeDual(volumeDisplacementDual);
|
||||
applyExtensionTransposes();
|
||||
m_surface.applyJacobianTranspose(parameters, m_surfaceDualWorkspace, parameterDual);
|
||||
++m_actionStatistics.jacobianTransposeApplications;
|
||||
}
|
||||
|
||||
void applyPullbackDerivative(
|
||||
const mfem::Vector ¶meters,
|
||||
const mfem::Vector ¶meterDirection,
|
||||
const mfem::Vector &volumeDisplacementDual,
|
||||
mfem::Vector ¶meterDualAction
|
||||
) const {
|
||||
requireCurrentDiscretization();
|
||||
requireParameterSize(parameters);
|
||||
requireParameterSize(parameterDirection);
|
||||
requireVolumeSize(volumeDisplacementDual);
|
||||
requireParameterSize(parameterDualAction);
|
||||
|
||||
m_surface.buildSurfaceDisplacement(parameters, m_surfaceDisplacementWorkspace);
|
||||
m_surface.applyJacobian(parameters, parameterDirection, m_surfaceDirectionWorkspace);
|
||||
splitVolumeDual(volumeDisplacementDual);
|
||||
applyExtensionTransposes();
|
||||
|
||||
m_interior.applyPullbackDerivative(
|
||||
m_surfaceDisplacementWorkspace, m_surfaceDirectionWorkspace, m_interiorVolumeDualWorkspace,
|
||||
m_interiorSurfacePullbackWorkspace
|
||||
);
|
||||
m_vacuum.applyPullbackDerivative(
|
||||
m_surfaceDisplacementWorkspace, m_surfaceDirectionWorkspace, m_vacuumVolumeDualWorkspace,
|
||||
m_vacuumSurfacePullbackWorkspace
|
||||
);
|
||||
addSurfaceFields(
|
||||
m_interiorSurfacePullbackWorkspace, m_vacuumSurfacePullbackWorkspace, m_surfacePullbackWorkspace
|
||||
);
|
||||
|
||||
m_surface.applyJacobianTranspose(parameters, m_surfacePullbackWorkspace, parameterDualAction);
|
||||
m_surface.applyPullbackDerivative(
|
||||
parameters, parameterDirection, m_surfaceDualWorkspace, m_parameterPullbackWorkspace
|
||||
);
|
||||
parameterDualAction += m_parameterPullbackWorkspace;
|
||||
++m_actionStatistics.pullbackDerivativeApplications;
|
||||
}
|
||||
|
||||
[[nodiscard]] DomainDeformationGeometryReport
|
||||
inspectMappedGeometry(const mfem::Vector &volumeDisplacement) const {
|
||||
requireCurrentDiscretization();
|
||||
requireVolumeSize(volumeDisplacement);
|
||||
|
||||
m_volumeGridFunctionWorkspace->SetFromTrueDofs(volumeDisplacement);
|
||||
mfem::Mesh *mesh = m_volumeDisplacementSpace->GetMesh();
|
||||
double localMinimumDeterminant = std::numeric_limits<double>::infinity();
|
||||
int localGeometryIsFinite = 1;
|
||||
|
||||
for (int element = 0; element < mesh->GetNE(); ++element) {
|
||||
mfem::ElementTransformation *transformation = mesh->GetElementTransformation(element);
|
||||
const mfem::FiniteElement *finiteElement = m_volumeDisplacementSpace->GetFE(element);
|
||||
// Positivity is a pointwise geometry requirement, not an
|
||||
// integration-accuracy requirement. A rule only slightly
|
||||
// above the displacement order can miss a narrow negative
|
||||
// region of the determinant even when a downstream physics
|
||||
// rule samples it. The determinant of a d-dimensional
|
||||
// degree-p deformation gradient can vary at substantially
|
||||
// higher order, so inspect at a conservative d*p scale.
|
||||
const int geometryInspectionOrder =
|
||||
std::max(finiteElement->GetOrder() + 2, 2 * spatialDimension() * finiteElement->GetOrder());
|
||||
const mfem::IntegrationRule &rule =
|
||||
mfem::IntRules.Get(transformation->GetGeometryType(), geometryInspectionOrder);
|
||||
|
||||
for (int point = 0; point < rule.GetNPoints(); ++point) {
|
||||
transformation->SetIntPoint(&rule.IntPoint(point));
|
||||
mfem::DenseMatrix deformationGradient;
|
||||
m_volumeGridFunctionWorkspace->GetVectorGradient(*transformation, deformationGradient);
|
||||
for (int component = 0; component < spatialDimension(); ++component) {
|
||||
deformationGradient(component, component) += 1.0;
|
||||
}
|
||||
const double determinant = deformationGradient.Det();
|
||||
if (!std::isfinite(determinant)) {
|
||||
localGeometryIsFinite = 0;
|
||||
} else {
|
||||
localMinimumDeterminant = std::min(localMinimumDeterminant, determinant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double globalMinimumDeterminant = 0.0;
|
||||
int globalGeometryIsFinite = 0;
|
||||
MPI_Allreduce(
|
||||
&localMinimumDeterminant, &globalMinimumDeterminant, 1, MPI_DOUBLE, MPI_MIN,
|
||||
m_volumeDisplacementSpace->GetComm()
|
||||
);
|
||||
MPI_Allreduce(
|
||||
&localGeometryIsFinite, &globalGeometryIsFinite, 1, MPI_INT, MPI_MIN,
|
||||
m_volumeDisplacementSpace->GetComm()
|
||||
);
|
||||
if (globalGeometryIsFinite == 0) {
|
||||
globalMinimumDeterminant = std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
++m_actionStatistics.geometryInspections;
|
||||
return {.minimumJacobianDeterminant = globalMinimumDeterminant};
|
||||
}
|
||||
|
||||
[[nodiscard]] DomainDeformationGeometryReport buildValidatedVolumeDisplacement(
|
||||
const mfem::Vector ¶meters,
|
||||
mfem::Vector &volumeDisplacement,
|
||||
const double determinantFloor = 0.0
|
||||
) const {
|
||||
if (!std::isfinite(determinantFloor) || determinantFloor < 0.0) {
|
||||
throw std::invalid_argument("The mapped-geometry determinant floor must be finite and non-negative.");
|
||||
}
|
||||
buildVolumeDisplacement(parameters, volumeDisplacement);
|
||||
const DomainDeformationGeometryReport report = inspectMappedGeometry(volumeDisplacement);
|
||||
if (!report.isOrientationPreserving(determinantFloor)) {
|
||||
throw std::domain_error("The prepared domain deformation inverts at least one volume element.");
|
||||
}
|
||||
return report;
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] static DomainDeformationDescriptor makeDescriptor(
|
||||
const PreparedSurface &surface,
|
||||
const PreparedInterior &interior,
|
||||
const PreparedVacuum &vacuum
|
||||
) noexcept {
|
||||
const SurfaceDeformationDescriptor surfaceDescriptor = surface.descriptor();
|
||||
const InteriorDeformationExtensionDescriptor interiorDescriptor = interior.descriptor();
|
||||
const VacuumDeformationExtensionDescriptor vacuumDescriptor = vacuum.descriptor();
|
||||
return {
|
||||
.surfaceDeformation = surfaceDescriptor,
|
||||
.stellarInteriorExtension = interiorDescriptor,
|
||||
.vacuumExtension = vacuumDescriptor,
|
||||
.linearOnReferenceGeometry = surfaceDescriptor.linearOnReferenceGeometry &&
|
||||
interiorDescriptor.linearOnReferenceGeometry &&
|
||||
vacuumDescriptor.linearOnReferenceGeometry,
|
||||
.requiresAuxiliarySolve =
|
||||
interiorDescriptor.requiresAuxiliarySolve || vacuumDescriptor.requiresAuxiliarySolve,
|
||||
.hasExactDerivativeTranspose = surfaceDescriptor.hasExactDerivativeTranspose &&
|
||||
interiorDescriptor.hasExactDerivativeTranspose &&
|
||||
vacuumDescriptor.hasExactDerivativeTranspose,
|
||||
.hasExactPullbackDerivative = surfaceDescriptor.hasExactPullbackDerivative &&
|
||||
interiorDescriptor.hasExactPullbackDerivative &&
|
||||
vacuumDescriptor.hasExactPullbackDerivative
|
||||
};
|
||||
}
|
||||
|
||||
void validateCompatibility(
|
||||
mfem::ParFiniteElementSpace &surfaceScalarSpace,
|
||||
mfem::ParFiniteElementSpace &volumeDisplacementSpace,
|
||||
mfem::ParMesh &logicalReferenceMesh
|
||||
) const {
|
||||
const mfem::Mesh *physicalMesh = volumeDisplacementSpace.GetMesh();
|
||||
if (!m_descriptor.isValid()) {
|
||||
throw std::invalid_argument("Prepared domain deformation descriptors are incompatible.");
|
||||
}
|
||||
if (!m_descriptor.supportsExactNewtonLinearization()) {
|
||||
throw std::invalid_argument("Prepared domain deformation requires exact transpose and pullback paths.");
|
||||
}
|
||||
if (physicalMesh == nullptr || surfaceScalarSpace.GetMesh() != physicalMesh) {
|
||||
throw std::invalid_argument("Prepared domain deformation spaces must share one physical mesh.");
|
||||
}
|
||||
if (logicalReferenceMesh.GetNE() != physicalMesh->GetNE() ||
|
||||
logicalReferenceMesh.GetNBE() != physicalMesh->GetNBE()) {
|
||||
throw std::invalid_argument("Prepared domain deformation requires the paired logical reference mesh.");
|
||||
}
|
||||
if (m_surface.surfaceDisplacementSize() != m_interior.surfaceDisplacementSize() ||
|
||||
m_surface.surfaceDisplacementSize() != m_vacuum.surfaceDisplacementSize()) {
|
||||
throw std::invalid_argument("Prepared deformation factors have incompatible surface trace sizes.");
|
||||
}
|
||||
if (m_interior.interiorDisplacementSize() != m_vacuum.vacuumDisplacementSize() ||
|
||||
m_interior.interiorDisplacementSize() != volumeDisplacementSpace.GetTrueVSize()) {
|
||||
throw std::invalid_argument("Prepared deformation factors have incompatible volume vector sizes.");
|
||||
}
|
||||
if (m_interior.scalarTrueDofCount() != m_vacuum.scalarTrueDofCount() ||
|
||||
volumeDisplacementSpace.GetTrueVSize() != spatialDimension() * m_interior.scalarTrueDofCount()) {
|
||||
throw std::invalid_argument("Prepared deformation factors have incompatible scalar volume topology.");
|
||||
}
|
||||
if (volumeDisplacementSpace.GetOrdering() != mfem::Ordering::byNODES) {
|
||||
throw std::invalid_argument("Prepared domain deformation requires MFEM byNODES volume ordering.");
|
||||
}
|
||||
}
|
||||
|
||||
void compileOwnership() {
|
||||
m_volumeOwners.resize(static_cast<std::size_t>(scalarTrueDofCount()));
|
||||
m_compositionReport.scalarTrueDofCount = scalarTrueDofCount();
|
||||
|
||||
for (int scalarTrueDof = 0; scalarTrueDof < scalarTrueDofCount(); ++scalarTrueDof) {
|
||||
const bool hasStellarSupport = m_interior.hasStellarSupport(scalarTrueDof);
|
||||
const bool hasVacuumSupport = m_vacuum.hasVacuumSupport(scalarTrueDof);
|
||||
if (!hasStellarSupport && !hasVacuumSupport) {
|
||||
throw std::invalid_argument("A volume displacement DOF has no deformation-extension owner.");
|
||||
}
|
||||
if (hasStellarSupport) {
|
||||
m_volumeOwners[static_cast<std::size_t>(scalarTrueDof)] = VolumeDeformationOwner::StellarInterior;
|
||||
++m_compositionReport.stellarInteriorOwnedScalarDofCount;
|
||||
if (hasVacuumSupport) {
|
||||
++m_compositionReport.sharedSurfaceScalarDofCount;
|
||||
}
|
||||
} else {
|
||||
m_volumeOwners[static_cast<std::size_t>(scalarTrueDof)] = VolumeDeformationOwner::Vacuum;
|
||||
++m_compositionReport.vacuumOwnedScalarDofCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] int volumeVectorDof(
|
||||
const int scalarTrueDof,
|
||||
const int component
|
||||
) const noexcept {
|
||||
return scalarTrueDof + component * scalarTrueDofCount();
|
||||
}
|
||||
|
||||
void mergeVolumeFields(
|
||||
const mfem::Vector &interiorVolume,
|
||||
const mfem::Vector &vacuumVolume,
|
||||
mfem::Vector &volume
|
||||
) const noexcept {
|
||||
for (int scalarTrueDof = 0; scalarTrueDof < scalarTrueDofCount(); ++scalarTrueDof) {
|
||||
const mfem::Vector &source = volumeOwner(scalarTrueDof) == VolumeDeformationOwner::StellarInterior
|
||||
? interiorVolume
|
||||
: vacuumVolume;
|
||||
for (int component = 0; component < spatialDimension(); ++component) {
|
||||
const int vectorDof = volumeVectorDof(scalarTrueDof, component);
|
||||
volume(vectorDof) = source(vectorDof);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void splitVolumeDual(const mfem::Vector &volumeDual) const noexcept {
|
||||
m_interiorVolumeDualWorkspace = 0.0;
|
||||
m_vacuumVolumeDualWorkspace = 0.0;
|
||||
for (int scalarTrueDof = 0; scalarTrueDof < scalarTrueDofCount(); ++scalarTrueDof) {
|
||||
mfem::Vector &destination = volumeOwner(scalarTrueDof) == VolumeDeformationOwner::StellarInterior
|
||||
? m_interiorVolumeDualWorkspace
|
||||
: m_vacuumVolumeDualWorkspace;
|
||||
for (int component = 0; component < spatialDimension(); ++component) {
|
||||
const int vectorDof = volumeVectorDof(scalarTrueDof, component);
|
||||
destination(vectorDof) = volumeDual(vectorDof);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void applyExtensionTransposes() const {
|
||||
m_interior.applyJacobianTranspose(
|
||||
m_surfaceDisplacementWorkspace, m_interiorVolumeDualWorkspace, m_interiorSurfaceDualWorkspace
|
||||
);
|
||||
m_vacuum.applyJacobianTranspose(
|
||||
m_surfaceDisplacementWorkspace, m_vacuumVolumeDualWorkspace, m_vacuumSurfaceDualWorkspace
|
||||
);
|
||||
addSurfaceFields(m_interiorSurfaceDualWorkspace, m_vacuumSurfaceDualWorkspace, m_surfaceDualWorkspace);
|
||||
}
|
||||
|
||||
static void addSurfaceFields(
|
||||
const mfem::Vector &interior,
|
||||
const mfem::Vector &vacuum,
|
||||
mfem::Vector &sum
|
||||
) {
|
||||
sum = interior;
|
||||
sum += vacuum;
|
||||
}
|
||||
|
||||
void requireCurrentDiscretization() const {
|
||||
if (!matchesCurrentDiscretization()) {
|
||||
throw std::logic_error("Prepared domain deformation discretization dependencies are stale.");
|
||||
}
|
||||
}
|
||||
|
||||
void requireParameterSize(const mfem::Vector ¶meters) const {
|
||||
if (parameters.Size() != parameterCount()) {
|
||||
throw std::invalid_argument("Prepared domain deformation received an incompatible parameter vector.");
|
||||
}
|
||||
}
|
||||
|
||||
void requireVolumeSize(const mfem::Vector &volume) const {
|
||||
if (volume.Size() != volumeDisplacementSize()) {
|
||||
throw std::invalid_argument("Prepared domain deformation received an incompatible volume vector.");
|
||||
}
|
||||
}
|
||||
|
||||
void requireScalarTrueDof(const int scalarTrueDof) const {
|
||||
if (scalarTrueDof < 0 || scalarTrueDof >= scalarTrueDofCount()) {
|
||||
throw std::out_of_range("Scalar true DOF is outside the prepared domain deformation.");
|
||||
}
|
||||
}
|
||||
|
||||
PreparedSurface m_surface;
|
||||
PreparedInterior m_interior;
|
||||
PreparedVacuum m_vacuum;
|
||||
mfem::ParFiniteElementSpace *m_volumeDisplacementSpace;
|
||||
DomainDeformationDescriptor m_descriptor;
|
||||
DomainDeformationCompositionReport m_compositionReport;
|
||||
DomainDeformationDiscretizationDependencies m_discretizationDependencies;
|
||||
std::vector<VolumeDeformationOwner> m_volumeOwners;
|
||||
mutable PreparedDomainDeformationActionStatistics m_actionStatistics;
|
||||
mutable mfem::Vector m_surfaceDisplacementWorkspace;
|
||||
mutable mfem::Vector m_surfaceDirectionWorkspace;
|
||||
mutable mfem::Vector m_interiorVolumeWorkspace;
|
||||
mutable mfem::Vector m_vacuumVolumeWorkspace;
|
||||
mutable mfem::Vector m_interiorVolumeDualWorkspace;
|
||||
mutable mfem::Vector m_vacuumVolumeDualWorkspace;
|
||||
mutable mfem::Vector m_interiorSurfaceDualWorkspace;
|
||||
mutable mfem::Vector m_vacuumSurfaceDualWorkspace;
|
||||
mutable mfem::Vector m_surfaceDualWorkspace;
|
||||
mutable mfem::Vector m_interiorSurfacePullbackWorkspace;
|
||||
mutable mfem::Vector m_vacuumSurfacePullbackWorkspace;
|
||||
mutable mfem::Vector m_surfacePullbackWorkspace;
|
||||
mutable mfem::Vector m_parameterPullbackWorkspace;
|
||||
mutable std::unique_ptr<mfem::ParGridFunction> m_volumeGridFunctionWorkspace;
|
||||
};
|
||||
|
||||
template <
|
||||
PreparedSurfaceDeformationPrescription PreparedSurface,
|
||||
PreparedInteriorDeformationExtension PreparedInterior,
|
||||
PreparedVacuumDeformationExtension PreparedVacuum>
|
||||
[[nodiscard]] auto composePreparedDomainDeformation(
|
||||
PreparedSurface preparedSurface,
|
||||
PreparedInterior preparedInterior,
|
||||
PreparedVacuum preparedVacuum,
|
||||
mfem::ParFiniteElementSpace &surfaceScalarSpace,
|
||||
mfem::ParFiniteElementSpace &volumeDisplacementSpace,
|
||||
mfem::ParMesh &logicalReferenceMesh
|
||||
) {
|
||||
return PreparedDomainDeformation<PreparedSurface, PreparedInterior, PreparedVacuum>{
|
||||
std::move(preparedSurface), std::move(preparedInterior), std::move(preparedVacuum),
|
||||
surfaceScalarSpace, volumeDisplacementSpace, logicalReferenceMesh
|
||||
};
|
||||
}
|
||||
|
||||
class PreparedDomainDeformationRuntime final {
|
||||
public:
|
||||
template <PreparedDomainDeformationOperator PreparedDeformation>
|
||||
requires(!std::same_as<
|
||||
std::remove_cvref_t<PreparedDeformation>,
|
||||
PreparedDomainDeformationRuntime>)
|
||||
explicit PreparedDomainDeformationRuntime(PreparedDeformation &&preparedDeformation)
|
||||
: m_implementation(
|
||||
std::make_unique<Implementation<std::remove_cvref_t<PreparedDeformation>>>(
|
||||
std::forward<PreparedDeformation>(preparedDeformation)
|
||||
)
|
||||
) {
|
||||
}
|
||||
|
||||
PreparedDomainDeformationRuntime(const PreparedDomainDeformationRuntime &) = delete;
|
||||
PreparedDomainDeformationRuntime &operator=(const PreparedDomainDeformationRuntime &) = delete;
|
||||
PreparedDomainDeformationRuntime(PreparedDomainDeformationRuntime &&) noexcept = default;
|
||||
PreparedDomainDeformationRuntime &operator=(PreparedDomainDeformationRuntime &&) noexcept = default;
|
||||
|
||||
[[nodiscard]] DomainDeformationDescriptor descriptor() const noexcept {
|
||||
return m_implementation->descriptor();
|
||||
}
|
||||
|
||||
[[nodiscard]] int parameterCount() const noexcept {
|
||||
return m_implementation->parameterCount();
|
||||
}
|
||||
|
||||
[[nodiscard]] int surfaceDisplacementSize() const noexcept {
|
||||
return m_implementation->surfaceDisplacementSize();
|
||||
}
|
||||
|
||||
[[nodiscard]] int volumeDisplacementSize() const noexcept {
|
||||
return m_implementation->volumeDisplacementSize();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool matchesCurrentDiscretization() const noexcept {
|
||||
return m_implementation->matchesCurrentDiscretization();
|
||||
}
|
||||
|
||||
[[nodiscard]] DomainDeformationCompositionReport compositionReport() const noexcept {
|
||||
return m_implementation->compositionReport();
|
||||
}
|
||||
|
||||
[[nodiscard]] DomainDeformationDiscretizationDependencies discretizationDependencies() const noexcept {
|
||||
return m_implementation->discretizationDependencies();
|
||||
}
|
||||
|
||||
[[nodiscard]] PreparedDomainDeformationActionStatistics actionStatistics() const noexcept {
|
||||
return m_implementation->actionStatistics();
|
||||
}
|
||||
|
||||
void buildVolumeDisplacement(
|
||||
const mfem::Vector ¶meters,
|
||||
mfem::Vector &volumeDisplacement
|
||||
) const {
|
||||
m_implementation->buildVolumeDisplacement(parameters, volumeDisplacement);
|
||||
}
|
||||
|
||||
void applyJacobian(
|
||||
const mfem::Vector ¶meters,
|
||||
const mfem::Vector ¶meterDirection,
|
||||
mfem::Vector &volumeDisplacementDirection
|
||||
) const {
|
||||
m_implementation->applyJacobian(parameters, parameterDirection, volumeDisplacementDirection);
|
||||
}
|
||||
|
||||
void applyJacobianTranspose(
|
||||
const mfem::Vector ¶meters,
|
||||
const mfem::Vector &volumeDisplacementDual,
|
||||
mfem::Vector ¶meterDual
|
||||
) const {
|
||||
m_implementation->applyJacobianTranspose(parameters, volumeDisplacementDual, parameterDual);
|
||||
}
|
||||
|
||||
void applyPullbackDerivative(
|
||||
const mfem::Vector ¶meters,
|
||||
const mfem::Vector ¶meterDirection,
|
||||
const mfem::Vector &volumeDisplacementDual,
|
||||
mfem::Vector ¶meterDualAction
|
||||
) const {
|
||||
m_implementation->applyPullbackDerivative(
|
||||
parameters, parameterDirection, volumeDisplacementDual, parameterDualAction
|
||||
);
|
||||
}
|
||||
|
||||
[[nodiscard]] DomainDeformationGeometryReport
|
||||
inspectMappedGeometry(const mfem::Vector &volumeDisplacement) const {
|
||||
return m_implementation->inspectMappedGeometry(volumeDisplacement);
|
||||
}
|
||||
|
||||
[[nodiscard]] DomainDeformationGeometryReport buildValidatedVolumeDisplacement(
|
||||
const mfem::Vector ¶meters,
|
||||
mfem::Vector &volumeDisplacement,
|
||||
const double determinantFloor = 0.0
|
||||
) const {
|
||||
return m_implementation->buildValidatedVolumeDisplacement(parameters, volumeDisplacement, determinantFloor);
|
||||
}
|
||||
|
||||
private:
|
||||
class Interface {
|
||||
public:
|
||||
virtual ~Interface() = default;
|
||||
|
||||
[[nodiscard]] virtual DomainDeformationDescriptor descriptor() const noexcept = 0;
|
||||
[[nodiscard]] virtual int parameterCount() const noexcept = 0;
|
||||
[[nodiscard]] virtual int surfaceDisplacementSize() const noexcept = 0;
|
||||
[[nodiscard]] virtual int volumeDisplacementSize() const noexcept = 0;
|
||||
[[nodiscard]] virtual bool matchesCurrentDiscretization() const noexcept = 0;
|
||||
[[nodiscard]] virtual DomainDeformationCompositionReport compositionReport() const noexcept = 0;
|
||||
[[nodiscard]] virtual DomainDeformationDiscretizationDependencies
|
||||
discretizationDependencies() const noexcept = 0;
|
||||
[[nodiscard]] virtual PreparedDomainDeformationActionStatistics actionStatistics() const noexcept = 0;
|
||||
virtual void buildVolumeDisplacement(
|
||||
const mfem::Vector &,
|
||||
mfem::Vector &
|
||||
) const = 0;
|
||||
virtual void applyJacobian(
|
||||
const mfem::Vector &,
|
||||
const mfem::Vector &,
|
||||
mfem::Vector &
|
||||
) const = 0;
|
||||
virtual void applyJacobianTranspose(
|
||||
const mfem::Vector &,
|
||||
const mfem::Vector &,
|
||||
mfem::Vector &
|
||||
) const = 0;
|
||||
virtual void applyPullbackDerivative(
|
||||
const mfem::Vector &,
|
||||
const mfem::Vector &,
|
||||
const mfem::Vector &,
|
||||
mfem::Vector &
|
||||
) const = 0;
|
||||
[[nodiscard]] virtual DomainDeformationGeometryReport inspectMappedGeometry(const mfem::Vector &) const = 0;
|
||||
[[nodiscard]] virtual DomainDeformationGeometryReport buildValidatedVolumeDisplacement(
|
||||
const mfem::Vector &,
|
||||
mfem::Vector &,
|
||||
double
|
||||
) const = 0;
|
||||
};
|
||||
|
||||
template <PreparedDomainDeformationOperator PreparedDeformation> class Implementation final : public Interface {
|
||||
public:
|
||||
explicit Implementation(PreparedDeformation preparedDeformation)
|
||||
: m_preparedDeformation(std::move(preparedDeformation)) {
|
||||
}
|
||||
|
||||
[[nodiscard]] DomainDeformationDescriptor descriptor() const noexcept override {
|
||||
return m_preparedDeformation.descriptor();
|
||||
}
|
||||
[[nodiscard]] int parameterCount() const noexcept override {
|
||||
return m_preparedDeformation.parameterCount();
|
||||
}
|
||||
[[nodiscard]] int surfaceDisplacementSize() const noexcept override {
|
||||
return m_preparedDeformation.surfaceDisplacementSize();
|
||||
}
|
||||
[[nodiscard]] int volumeDisplacementSize() const noexcept override {
|
||||
return m_preparedDeformation.volumeDisplacementSize();
|
||||
}
|
||||
[[nodiscard]] bool matchesCurrentDiscretization() const noexcept override {
|
||||
return m_preparedDeformation.matchesCurrentDiscretization();
|
||||
}
|
||||
[[nodiscard]] DomainDeformationCompositionReport compositionReport() const noexcept override {
|
||||
return m_preparedDeformation.compositionReport();
|
||||
}
|
||||
[[nodiscard]] DomainDeformationDiscretizationDependencies
|
||||
discretizationDependencies() const noexcept override {
|
||||
return m_preparedDeformation.discretizationDependencies();
|
||||
}
|
||||
[[nodiscard]] PreparedDomainDeformationActionStatistics actionStatistics() const noexcept override {
|
||||
return m_preparedDeformation.actionStatistics();
|
||||
}
|
||||
void buildVolumeDisplacement(
|
||||
const mfem::Vector ¶meters,
|
||||
mfem::Vector &volumeDisplacement
|
||||
) const override {
|
||||
m_preparedDeformation.buildVolumeDisplacement(parameters, volumeDisplacement);
|
||||
}
|
||||
void applyJacobian(
|
||||
const mfem::Vector ¶meters,
|
||||
const mfem::Vector ¶meterDirection,
|
||||
mfem::Vector &volumeDisplacementDirection
|
||||
) const override {
|
||||
m_preparedDeformation.applyJacobian(parameters, parameterDirection, volumeDisplacementDirection);
|
||||
}
|
||||
void applyJacobianTranspose(
|
||||
const mfem::Vector ¶meters,
|
||||
const mfem::Vector &volumeDisplacementDual,
|
||||
mfem::Vector ¶meterDual
|
||||
) const override {
|
||||
m_preparedDeformation.applyJacobianTranspose(parameters, volumeDisplacementDual, parameterDual);
|
||||
}
|
||||
void applyPullbackDerivative(
|
||||
const mfem::Vector ¶meters,
|
||||
const mfem::Vector ¶meterDirection,
|
||||
const mfem::Vector &volumeDisplacementDual,
|
||||
mfem::Vector ¶meterDualAction
|
||||
) const override {
|
||||
m_preparedDeformation.applyPullbackDerivative(
|
||||
parameters, parameterDirection, volumeDisplacementDual, parameterDualAction
|
||||
);
|
||||
}
|
||||
[[nodiscard]] DomainDeformationGeometryReport
|
||||
inspectMappedGeometry(const mfem::Vector &volumeDisplacement) const override {
|
||||
return m_preparedDeformation.inspectMappedGeometry(volumeDisplacement);
|
||||
}
|
||||
[[nodiscard]] DomainDeformationGeometryReport buildValidatedVolumeDisplacement(
|
||||
const mfem::Vector ¶meters,
|
||||
mfem::Vector &volumeDisplacement,
|
||||
const double determinantFloor
|
||||
) const override {
|
||||
return m_preparedDeformation.buildValidatedVolumeDisplacement(
|
||||
parameters, volumeDisplacement, determinantFloor
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
PreparedDeformation m_preparedDeformation;
|
||||
};
|
||||
|
||||
std::unique_ptr<Interface> m_implementation;
|
||||
};
|
||||
|
||||
template <
|
||||
utils::domain::IsSchema SchemaT = utils::domain::CoreEnvelopeVacuumDomainSchema,
|
||||
SurfaceDeformationPrescription SurfacePrescription,
|
||||
InteriorDeformationExtension InteriorExtension,
|
||||
VacuumDeformationExtension VacuumExtension>
|
||||
requires SurfaceDeformationCompilable<
|
||||
SurfacePrescription,
|
||||
SurfaceDeformationCompilationContext> &&
|
||||
InteriorDeformationExtensionCompilable<
|
||||
InteriorExtension,
|
||||
RadialDeformationExtensionCompilationContext> &&
|
||||
VacuumDeformationExtensionCompilable<
|
||||
VacuumExtension,
|
||||
RadialDeformationExtensionCompilationContext>
|
||||
[[nodiscard]] auto compileDomainDeformation(
|
||||
const SurfacePrescription &surfacePrescription,
|
||||
const InteriorExtension &interiorExtension,
|
||||
const VacuumExtension &vacuumExtension,
|
||||
fem::FEM &finiteElementModel
|
||||
) {
|
||||
if (!finiteElementModel.okay()) {
|
||||
throw std::invalid_argument("Domain deformation compilation requires a complete finite-element model.");
|
||||
}
|
||||
|
||||
const field::ScalarBoundaryDofMap surfaceDofMap =
|
||||
field::make_stellar_surface_scalar_dof_map<SchemaT>(*finiteElementModel.surfaceDeformationFes);
|
||||
const SurfaceDeformationCompilationContext surfaceContext{
|
||||
*finiteElementModel.surfaceDeformationFes, surfaceDofMap
|
||||
};
|
||||
auto preparedSurface = compileSurfaceDeformationPrescription(surfacePrescription, surfaceContext);
|
||||
|
||||
const RadialDeformationExtensionCompilationContext extensionContext =
|
||||
makeRadialDeformationExtensionCompilationContext<SchemaT>(
|
||||
*finiteElementModel.surfaceDeformationFes, *finiteElementModel.displacementFes,
|
||||
*finiteElementModel.logicalReferenceMesh
|
||||
);
|
||||
auto preparedInterior = compileInteriorDeformationExtension(interiorExtension, extensionContext);
|
||||
auto preparedVacuum = compileVacuumDeformationExtension(vacuumExtension, extensionContext);
|
||||
|
||||
return composePreparedDomainDeformation(
|
||||
std::move(preparedSurface), std::move(preparedInterior), std::move(preparedVacuum),
|
||||
*finiteElementModel.surfaceDeformationFes, *finiteElementModel.displacementFes,
|
||||
*finiteElementModel.logicalReferenceMesh
|
||||
);
|
||||
}
|
||||
} // namespace mean_field::deformation
|
||||
63
libmeanfield/interface/deformation/interior_extension.cppm
Normal file
63
libmeanfield/interface/deformation/interior_extension.cppm
Normal file
@@ -0,0 +1,63 @@
|
||||
module;
|
||||
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:deformation.interior_extension;
|
||||
|
||||
export import :deformation.descriptors;
|
||||
|
||||
export namespace mean_field::deformation {
|
||||
template <typename Candidate>
|
||||
concept PreparedInteriorDeformationExtension = requires(
|
||||
const std::remove_cvref_t<Candidate> &preparedExtension,
|
||||
const mfem::Vector &surfaceDisplacement,
|
||||
const mfem::Vector &surfaceDisplacementDirection,
|
||||
const mfem::Vector &interiorDisplacementDual,
|
||||
mfem::Vector &interiorDisplacement,
|
||||
mfem::Vector &surfaceDisplacementDual
|
||||
) {
|
||||
{ preparedExtension.descriptor() } noexcept -> std::same_as<InteriorDeformationExtensionDescriptor>;
|
||||
{ preparedExtension.surfaceDisplacementSize() } noexcept -> std::same_as<int>;
|
||||
{ preparedExtension.interiorDisplacementSize() } noexcept -> std::same_as<int>;
|
||||
{ preparedExtension.scalarTrueDofCount() } noexcept -> std::same_as<int>;
|
||||
{ preparedExtension.hasStellarSupport(0) } -> std::same_as<bool>;
|
||||
{
|
||||
preparedExtension.buildInteriorDisplacement(surfaceDisplacement, interiorDisplacement)
|
||||
} -> std::same_as<void>;
|
||||
{
|
||||
preparedExtension.applyJacobian(surfaceDisplacement, surfaceDisplacementDirection, interiorDisplacement)
|
||||
} -> std::same_as<void>;
|
||||
{
|
||||
preparedExtension.applyJacobianTranspose(
|
||||
surfaceDisplacement, interiorDisplacementDual, surfaceDisplacementDual
|
||||
)
|
||||
} -> std::same_as<void>;
|
||||
{
|
||||
preparedExtension.applyPullbackDerivative(
|
||||
surfaceDisplacement, surfaceDisplacementDirection, interiorDisplacementDual, surfaceDisplacementDual
|
||||
)
|
||||
} -> std::same_as<void>;
|
||||
};
|
||||
|
||||
template <typename Candidate>
|
||||
concept InteriorDeformationExtension = requires(const std::remove_cvref_t<Candidate> &extension) {
|
||||
typename std::remove_cvref_t<Candidate>::PreparedType;
|
||||
requires PreparedInteriorDeformationExtension<typename std::remove_cvref_t<Candidate>::PreparedType>;
|
||||
{ extension.descriptor() } noexcept -> std::same_as<InteriorDeformationExtensionDescriptor>;
|
||||
{ extension.validate() } -> std::same_as<void>;
|
||||
};
|
||||
|
||||
template <typename Extension, typename CompilationContext>
|
||||
concept InteriorDeformationExtensionCompilable =
|
||||
InteriorDeformationExtension<Extension> && requires(
|
||||
const std::remove_cvref_t<Extension> &extension,
|
||||
const std::remove_cvref_t<CompilationContext> &context
|
||||
) {
|
||||
{
|
||||
compileInteriorDeformationExtension(extension, context)
|
||||
} -> std::same_as<typename std::remove_cvref_t<Extension>::PreparedType>;
|
||||
};
|
||||
} // namespace mean_field::deformation
|
||||
138
libmeanfield/interface/deformation/nodal_radial_surface.cppm
Normal file
138
libmeanfield/interface/deformation/nodal_radial_surface.cppm
Normal file
@@ -0,0 +1,138 @@
|
||||
module;
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:deformation.nodal_radial_surface;
|
||||
|
||||
export import :deformation.surface_prescription;
|
||||
export import :field.mfem;
|
||||
|
||||
export namespace mean_field::deformation {
|
||||
class PreparedNodalRadialSurface;
|
||||
|
||||
class SurfaceDeformationCompilationContext final {
|
||||
public:
|
||||
SurfaceDeformationCompilationContext(
|
||||
mfem::ParFiniteElementSpace &scalarFiniteElementSpace,
|
||||
field::ScalarBoundaryDofMap surfaceDofMap
|
||||
);
|
||||
|
||||
[[nodiscard]] mfem::ParFiniteElementSpace &scalarFiniteElementSpace() const noexcept;
|
||||
|
||||
[[nodiscard]] const field::ScalarBoundaryDofMap &surfaceDofMap() const noexcept;
|
||||
|
||||
private:
|
||||
mfem::ParFiniteElementSpace *m_scalarFiniteElementSpace;
|
||||
field::ScalarBoundaryDofMap m_surfaceDofMap;
|
||||
};
|
||||
|
||||
class NodalRadialSurface final {
|
||||
public:
|
||||
using PreparedType = PreparedNodalRadialSurface;
|
||||
|
||||
explicit NodalRadialSurface(mfem::Vector referenceCenter);
|
||||
|
||||
[[nodiscard]] const mfem::Vector &referenceCenter() const noexcept;
|
||||
|
||||
[[nodiscard]] SurfaceDeformationDescriptor descriptor() const noexcept;
|
||||
|
||||
void validate() const;
|
||||
|
||||
private:
|
||||
mfem::Vector m_referenceCenter;
|
||||
};
|
||||
|
||||
class PreparedNodalRadialSurface final {
|
||||
public:
|
||||
[[nodiscard]] SurfaceDeformationDescriptor descriptor() const noexcept;
|
||||
|
||||
[[nodiscard]] int parameterCount() const noexcept;
|
||||
|
||||
[[nodiscard]] long long globalParameterCount() const noexcept;
|
||||
|
||||
[[nodiscard]] long long globalParameterOffset() const noexcept;
|
||||
|
||||
[[nodiscard]] int spatialDimension() const noexcept;
|
||||
|
||||
[[nodiscard]] int surfaceDisplacementSize() const noexcept;
|
||||
|
||||
[[nodiscard]] long long globalSurfaceDisplacementSize() const noexcept;
|
||||
|
||||
[[nodiscard]] long long globalSurfaceDisplacementOffset() const noexcept;
|
||||
|
||||
[[nodiscard]] int surfaceDisplacementDof(
|
||||
int parameterDof,
|
||||
int component
|
||||
) const;
|
||||
|
||||
[[nodiscard]] double radialDirection(
|
||||
int parameterDof,
|
||||
int component
|
||||
) const;
|
||||
|
||||
[[nodiscard]] double referenceRadius(int parameterDof) const;
|
||||
|
||||
[[nodiscard]] const mfem::Vector &referenceCenter() const noexcept;
|
||||
|
||||
[[nodiscard]] const field::ScalarBoundaryDofMap &surfaceDofMap() const noexcept;
|
||||
|
||||
void buildSurfaceDisplacement(
|
||||
const mfem::Vector ¶meters,
|
||||
mfem::Vector &surfaceDisplacement
|
||||
) const;
|
||||
|
||||
void applyJacobian(
|
||||
const mfem::Vector ¶meters,
|
||||
const mfem::Vector ¶meterDirection,
|
||||
mfem::Vector &surfaceDisplacementDirection
|
||||
) const;
|
||||
|
||||
void applyJacobianTranspose(
|
||||
const mfem::Vector ¶meters,
|
||||
const mfem::Vector &surfaceDisplacementDual,
|
||||
mfem::Vector ¶meterDual
|
||||
) const;
|
||||
|
||||
void applyPullbackDerivative(
|
||||
const mfem::Vector ¶meters,
|
||||
const mfem::Vector ¶meterDirection,
|
||||
const mfem::Vector &surfaceDisplacementDual,
|
||||
mfem::Vector ¶meterDualAction
|
||||
) const;
|
||||
|
||||
private:
|
||||
friend PreparedNodalRadialSurface compileSurfaceDeformationPrescription(
|
||||
const NodalRadialSurface &prescription,
|
||||
const SurfaceDeformationCompilationContext &context
|
||||
);
|
||||
|
||||
PreparedNodalRadialSurface(
|
||||
SurfaceDeformationDescriptor descriptor,
|
||||
mfem::Vector referenceCenter,
|
||||
field::ScalarBoundaryDofMap surfaceDofMap,
|
||||
mfem::Vector radialDirections,
|
||||
mfem::Vector referenceRadii
|
||||
);
|
||||
|
||||
void requireParameterSize(const mfem::Vector ¶meters) const;
|
||||
|
||||
void requireSurfaceDisplacementSize(const mfem::Vector &surfaceDisplacement) const;
|
||||
|
||||
SurfaceDeformationDescriptor m_descriptor;
|
||||
mfem::Vector m_referenceCenter;
|
||||
field::ScalarBoundaryDofMap m_surfaceDofMap;
|
||||
mfem::Vector m_radialDirections;
|
||||
mfem::Vector m_referenceRadii;
|
||||
};
|
||||
|
||||
[[nodiscard]] PreparedNodalRadialSurface compileSurfaceDeformationPrescription(
|
||||
const NodalRadialSurface &prescription,
|
||||
const SurfaceDeformationCompilationContext &context
|
||||
);
|
||||
|
||||
static_assert(SurfaceDeformationPrescription<NodalRadialSurface>);
|
||||
static_assert(PreparedSurfaceDeformationPrescription<PreparedNodalRadialSurface>);
|
||||
static_assert(SurfaceDeformationCompilable<
|
||||
NodalRadialSurface,
|
||||
SurfaceDeformationCompilationContext>);
|
||||
} // namespace mean_field::deformation
|
||||
302
libmeanfield/interface/deformation/radial_extensions.cppm
Normal file
302
libmeanfield/interface/deformation/radial_extensions.cppm
Normal file
@@ -0,0 +1,302 @@
|
||||
module;
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <mfem.hpp>
|
||||
#include <mpi.h>
|
||||
|
||||
export module mean_field:deformation.radial_extensions;
|
||||
|
||||
export import :deformation.interior_extension;
|
||||
export import :deformation.vacuum_extension;
|
||||
export import :field.mfem;
|
||||
export import :utils.domain;
|
||||
|
||||
export namespace mean_field::deformation {
|
||||
class RadialDeformationExtensionCompilationContext final {
|
||||
public:
|
||||
RadialDeformationExtensionCompilationContext(
|
||||
mfem::ParFiniteElementSpace &scalarFiniteElementSpace,
|
||||
mfem::ParFiniteElementSpace &vectorFiniteElementSpace,
|
||||
mfem::ParMesh &logicalReferenceMesh,
|
||||
field::ScalarBoundaryDofMap stellarSurfaceDofMap,
|
||||
field::ScalarBoundaryDofMap infinitySurfaceDofMap,
|
||||
mfem::Array<int> stellarMaterialMarker,
|
||||
mfem::Array<int> vacuumMaterialMarker,
|
||||
int stellarSurfaceBoundaryAttribute,
|
||||
int infinitySurfaceBoundaryAttribute
|
||||
);
|
||||
|
||||
[[nodiscard]] int spatialDimension() const noexcept;
|
||||
[[nodiscard]] int surfaceDisplacementSize() const noexcept;
|
||||
[[nodiscard]] int volumeDisplacementSize() const noexcept;
|
||||
[[nodiscard]] int scalarTrueDofCount() const noexcept;
|
||||
[[nodiscard]] double logicalRadius(int scalarTrueDof) const;
|
||||
[[nodiscard]] double stellarSurfaceLogicalRadius() const noexcept;
|
||||
[[nodiscard]] double infinitySurfaceLogicalRadius() const noexcept;
|
||||
[[nodiscard]] int surfaceInterpolationEntryCount(int scalarTrueDof) const;
|
||||
[[nodiscard]] int surfaceGlobalCoordinate(
|
||||
int scalarTrueDof,
|
||||
int interpolationEntry
|
||||
) const;
|
||||
[[nodiscard]] double surfaceInterpolationWeight(
|
||||
int scalarTrueDof,
|
||||
int interpolationEntry
|
||||
) const;
|
||||
|
||||
private:
|
||||
friend class PreparedPowerLawRadialInteriorExtension;
|
||||
friend class PreparedFixedInfinityRadialVacuumExtension;
|
||||
|
||||
int m_spatialDimension{0};
|
||||
int m_scalarTrueDofCount{0};
|
||||
int m_volumeDisplacementSize{0};
|
||||
int m_surfaceDisplacementSize{0};
|
||||
int m_globalSurfaceDisplacementSize{0};
|
||||
int m_globalSurfaceDisplacementOffset{0};
|
||||
MPI_Comm m_communicator{MPI_COMM_NULL};
|
||||
mfem::Array<int> m_stellarSupport;
|
||||
mfem::Array<int> m_vacuumSupport;
|
||||
mfem::Vector m_logicalRadius;
|
||||
double m_stellarSurfaceLogicalRadius{0.0};
|
||||
double m_infinitySurfaceLogicalRadius{0.0};
|
||||
std::vector<int> m_surfaceInterpolationRowOffsets;
|
||||
std::vector<int> m_surfaceInterpolationGlobalCoordinates;
|
||||
std::vector<double> m_surfaceInterpolationWeights;
|
||||
std::vector<int> m_surfaceDisplacementCounts;
|
||||
std::vector<int> m_surfaceDisplacementOffsets;
|
||||
};
|
||||
|
||||
template <utils::domain::IsSchema SchemaT = utils::domain::CoreEnvelopeVacuumDomainSchema>
|
||||
requires(
|
||||
SchemaT::template contains_domain<utils::domain::Stellar>() &&
|
||||
SchemaT::template contains_domain<utils::domain::Vacuum>() &&
|
||||
SchemaT::template contains_boundary<utils::domain::StellarSurface>() &&
|
||||
SchemaT::template contains_boundary<utils::domain::InfinitySurface>()
|
||||
)
|
||||
[[nodiscard]] RadialDeformationExtensionCompilationContext makeRadialDeformationExtensionCompilationContext(
|
||||
mfem::ParFiniteElementSpace &scalarFiniteElementSpace,
|
||||
mfem::ParFiniteElementSpace &vectorFiniteElementSpace,
|
||||
mfem::ParMesh &logicalReferenceMesh
|
||||
) {
|
||||
const mfem::Mesh *mesh = scalarFiniteElementSpace.GetMesh();
|
||||
MFEM_VERIFY(mesh != nullptr, "Radial deformation extension compilation requires an MFEM mesh.");
|
||||
|
||||
return RadialDeformationExtensionCompilationContext(
|
||||
scalarFiniteElementSpace, vectorFiniteElementSpace, logicalReferenceMesh,
|
||||
field::make_scalar_boundary_dof_map<utils::domain::StellarSurface, SchemaT>(scalarFiniteElementSpace),
|
||||
field::make_scalar_boundary_dof_map<utils::domain::InfinitySurface, SchemaT>(scalarFiniteElementSpace),
|
||||
utils::domain::make_attribute_marker<utils::domain::Stellar, SchemaT>(*mesh),
|
||||
utils::domain::make_attribute_marker<utils::domain::Vacuum, SchemaT>(*mesh),
|
||||
SchemaT::template boundary_attribute<utils::domain::StellarSurface>(),
|
||||
SchemaT::template boundary_attribute<utils::domain::InfinitySurface>()
|
||||
);
|
||||
}
|
||||
|
||||
class PreparedPowerLawRadialInteriorExtension;
|
||||
|
||||
class PowerLawRadialInteriorExtension final {
|
||||
public:
|
||||
using PreparedType = PreparedPowerLawRadialInteriorExtension;
|
||||
|
||||
explicit PowerLawRadialInteriorExtension(double radialPower = 2.0);
|
||||
[[nodiscard]] double radialPower() const noexcept;
|
||||
[[nodiscard]] InteriorDeformationExtensionDescriptor descriptor() const noexcept;
|
||||
void validate() const;
|
||||
|
||||
private:
|
||||
double m_radialPower;
|
||||
};
|
||||
|
||||
class PreparedPowerLawRadialInteriorExtension final {
|
||||
public:
|
||||
[[nodiscard]] InteriorDeformationExtensionDescriptor descriptor() const noexcept;
|
||||
[[nodiscard]] int surfaceDisplacementSize() const noexcept;
|
||||
[[nodiscard]] int interiorDisplacementSize() const noexcept;
|
||||
[[nodiscard]] int scalarTrueDofCount() const noexcept;
|
||||
[[nodiscard]] double radialPower() const noexcept;
|
||||
[[nodiscard]] bool hasStellarSupport(int scalarTrueDof) const;
|
||||
[[nodiscard]] double radialWeight(int scalarTrueDof) const;
|
||||
[[nodiscard]] int surfaceInterpolationEntryCount(int scalarTrueDof) const;
|
||||
[[nodiscard]] int surfaceGlobalCoordinate(
|
||||
int scalarTrueDof,
|
||||
int interpolationEntry
|
||||
) const;
|
||||
[[nodiscard]] double surfaceInterpolationWeight(
|
||||
int scalarTrueDof,
|
||||
int interpolationEntry
|
||||
) const;
|
||||
|
||||
void buildInteriorDisplacement(
|
||||
const mfem::Vector &surfaceDisplacement,
|
||||
mfem::Vector &interiorDisplacement
|
||||
) const;
|
||||
void applyJacobian(
|
||||
const mfem::Vector &surfaceDisplacement,
|
||||
const mfem::Vector &surfaceDisplacementDirection,
|
||||
mfem::Vector &interiorDisplacementDirection
|
||||
) const;
|
||||
void applyJacobianTranspose(
|
||||
const mfem::Vector &surfaceDisplacement,
|
||||
const mfem::Vector &interiorDisplacementDual,
|
||||
mfem::Vector &surfaceDisplacementDual
|
||||
) const;
|
||||
void applyPullbackDerivative(
|
||||
const mfem::Vector &surfaceDisplacement,
|
||||
const mfem::Vector &surfaceDisplacementDirection,
|
||||
const mfem::Vector &interiorDisplacementDual,
|
||||
mfem::Vector &surfaceDisplacementDualAction
|
||||
) const;
|
||||
|
||||
private:
|
||||
friend PreparedPowerLawRadialInteriorExtension compileInteriorDeformationExtension(
|
||||
const PowerLawRadialInteriorExtension &extension,
|
||||
const RadialDeformationExtensionCompilationContext &context
|
||||
);
|
||||
|
||||
PreparedPowerLawRadialInteriorExtension(
|
||||
const PowerLawRadialInteriorExtension &extension,
|
||||
const RadialDeformationExtensionCompilationContext &context
|
||||
);
|
||||
void requireSurfaceSize(const mfem::Vector &surfaceDisplacement) const;
|
||||
void requireInteriorSize(const mfem::Vector &interiorDisplacement) const;
|
||||
void applyForward(
|
||||
const mfem::Vector &surfaceDisplacement,
|
||||
mfem::Vector &interiorDisplacement
|
||||
) const;
|
||||
void applyTranspose(
|
||||
const mfem::Vector &interiorDisplacementDual,
|
||||
mfem::Vector &surfaceDisplacementDual
|
||||
) const;
|
||||
|
||||
InteriorDeformationExtensionDescriptor m_descriptor;
|
||||
double m_radialPower{2.0};
|
||||
int m_surfaceDisplacementSize{0};
|
||||
int m_interiorDisplacementSize{0};
|
||||
int m_spatialDimension{0};
|
||||
int m_globalSurfaceDisplacementSize{0};
|
||||
int m_globalSurfaceDisplacementOffset{0};
|
||||
MPI_Comm m_communicator{MPI_COMM_NULL};
|
||||
mfem::Array<int> m_stellarSupport;
|
||||
mfem::Vector m_radialWeights;
|
||||
std::vector<int> m_surfaceInterpolationRowOffsets;
|
||||
std::vector<int> m_surfaceInterpolationGlobalCoordinates;
|
||||
std::vector<double> m_surfaceInterpolationWeights;
|
||||
std::vector<int> m_surfaceDisplacementCounts;
|
||||
std::vector<int> m_surfaceDisplacementOffsets;
|
||||
mutable mfem::Vector m_globalSurfaceDisplacementWorkspace;
|
||||
mutable mfem::Vector m_localGlobalSurfaceDualWorkspace;
|
||||
mutable mfem::Vector m_globalSurfaceDualWorkspace;
|
||||
};
|
||||
|
||||
[[nodiscard]] PreparedPowerLawRadialInteriorExtension compileInteriorDeformationExtension(
|
||||
const PowerLawRadialInteriorExtension &extension,
|
||||
const RadialDeformationExtensionCompilationContext &context
|
||||
);
|
||||
|
||||
class PreparedFixedInfinityRadialVacuumExtension;
|
||||
|
||||
class FixedInfinityRadialVacuumExtension final {
|
||||
public:
|
||||
using PreparedType = PreparedFixedInfinityRadialVacuumExtension;
|
||||
|
||||
[[nodiscard]] VacuumDeformationExtensionDescriptor descriptor() const noexcept;
|
||||
void validate() const;
|
||||
};
|
||||
|
||||
class PreparedFixedInfinityRadialVacuumExtension final {
|
||||
public:
|
||||
[[nodiscard]] VacuumDeformationExtensionDescriptor descriptor() const noexcept;
|
||||
[[nodiscard]] int surfaceDisplacementSize() const noexcept;
|
||||
[[nodiscard]] int vacuumDisplacementSize() const noexcept;
|
||||
[[nodiscard]] int scalarTrueDofCount() const noexcept;
|
||||
[[nodiscard]] bool hasVacuumSupport(int scalarTrueDof) const;
|
||||
[[nodiscard]] double radialWeight(int scalarTrueDof) const;
|
||||
[[nodiscard]] int surfaceInterpolationEntryCount(int scalarTrueDof) const;
|
||||
[[nodiscard]] int surfaceGlobalCoordinate(
|
||||
int scalarTrueDof,
|
||||
int interpolationEntry
|
||||
) const;
|
||||
[[nodiscard]] double surfaceInterpolationWeight(
|
||||
int scalarTrueDof,
|
||||
int interpolationEntry
|
||||
) const;
|
||||
|
||||
void buildVacuumDisplacement(
|
||||
const mfem::Vector &surfaceDisplacement,
|
||||
mfem::Vector &vacuumDisplacement
|
||||
) const;
|
||||
void applyJacobian(
|
||||
const mfem::Vector &surfaceDisplacement,
|
||||
const mfem::Vector &surfaceDisplacementDirection,
|
||||
mfem::Vector &vacuumDisplacementDirection
|
||||
) const;
|
||||
void applyJacobianTranspose(
|
||||
const mfem::Vector &surfaceDisplacement,
|
||||
const mfem::Vector &vacuumDisplacementDual,
|
||||
mfem::Vector &surfaceDisplacementDual
|
||||
) const;
|
||||
void applyPullbackDerivative(
|
||||
const mfem::Vector &surfaceDisplacement,
|
||||
const mfem::Vector &surfaceDisplacementDirection,
|
||||
const mfem::Vector &vacuumDisplacementDual,
|
||||
mfem::Vector &surfaceDisplacementDualAction
|
||||
) const;
|
||||
|
||||
private:
|
||||
friend PreparedFixedInfinityRadialVacuumExtension compileVacuumDeformationExtension(
|
||||
const FixedInfinityRadialVacuumExtension &extension,
|
||||
const RadialDeformationExtensionCompilationContext &context
|
||||
);
|
||||
|
||||
PreparedFixedInfinityRadialVacuumExtension(
|
||||
const FixedInfinityRadialVacuumExtension &extension,
|
||||
const RadialDeformationExtensionCompilationContext &context
|
||||
);
|
||||
void requireSurfaceSize(const mfem::Vector &surfaceDisplacement) const;
|
||||
void requireVacuumSize(const mfem::Vector &vacuumDisplacement) const;
|
||||
void applyForward(
|
||||
const mfem::Vector &surfaceDisplacement,
|
||||
mfem::Vector &vacuumDisplacement
|
||||
) const;
|
||||
void applyTranspose(
|
||||
const mfem::Vector &vacuumDisplacementDual,
|
||||
mfem::Vector &surfaceDisplacementDual
|
||||
) const;
|
||||
|
||||
VacuumDeformationExtensionDescriptor m_descriptor;
|
||||
int m_surfaceDisplacementSize{0};
|
||||
int m_vacuumDisplacementSize{0};
|
||||
int m_spatialDimension{0};
|
||||
int m_globalSurfaceDisplacementSize{0};
|
||||
int m_globalSurfaceDisplacementOffset{0};
|
||||
MPI_Comm m_communicator{MPI_COMM_NULL};
|
||||
mfem::Array<int> m_vacuumSupport;
|
||||
mfem::Vector m_radialWeights;
|
||||
std::vector<int> m_surfaceInterpolationRowOffsets;
|
||||
std::vector<int> m_surfaceInterpolationGlobalCoordinates;
|
||||
std::vector<double> m_surfaceInterpolationWeights;
|
||||
std::vector<int> m_surfaceDisplacementCounts;
|
||||
std::vector<int> m_surfaceDisplacementOffsets;
|
||||
mutable mfem::Vector m_globalSurfaceDisplacementWorkspace;
|
||||
mutable mfem::Vector m_localGlobalSurfaceDualWorkspace;
|
||||
mutable mfem::Vector m_globalSurfaceDualWorkspace;
|
||||
};
|
||||
|
||||
[[nodiscard]] PreparedFixedInfinityRadialVacuumExtension compileVacuumDeformationExtension(
|
||||
const FixedInfinityRadialVacuumExtension &extension,
|
||||
const RadialDeformationExtensionCompilationContext &context
|
||||
);
|
||||
|
||||
static_assert(InteriorDeformationExtension<PowerLawRadialInteriorExtension>);
|
||||
static_assert(PreparedInteriorDeformationExtension<PreparedPowerLawRadialInteriorExtension>);
|
||||
static_assert(InteriorDeformationExtensionCompilable<
|
||||
PowerLawRadialInteriorExtension,
|
||||
RadialDeformationExtensionCompilationContext>);
|
||||
static_assert(VacuumDeformationExtension<FixedInfinityRadialVacuumExtension>);
|
||||
static_assert(PreparedVacuumDeformationExtension<PreparedFixedInfinityRadialVacuumExtension>);
|
||||
static_assert(VacuumDeformationExtensionCompilable<
|
||||
FixedInfinityRadialVacuumExtension,
|
||||
RadialDeformationExtensionCompilationContext>);
|
||||
} // namespace mean_field::deformation
|
||||
57
libmeanfield/interface/deformation/surface_prescription.cppm
Normal file
57
libmeanfield/interface/deformation/surface_prescription.cppm
Normal file
@@ -0,0 +1,57 @@
|
||||
module;
|
||||
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:deformation.surface_prescription;
|
||||
|
||||
export import :deformation.descriptors;
|
||||
|
||||
export namespace mean_field::deformation {
|
||||
template <typename Candidate>
|
||||
concept PreparedSurfaceDeformationPrescription = requires(
|
||||
const std::remove_cvref_t<Candidate> &preparedPrescription,
|
||||
const mfem::Vector ¶meters,
|
||||
const mfem::Vector ¶meterDirection,
|
||||
const mfem::Vector &surfaceDisplacementDual,
|
||||
mfem::Vector &surfaceDisplacement,
|
||||
mfem::Vector ¶meterDual
|
||||
) {
|
||||
{ preparedPrescription.descriptor() } noexcept -> std::same_as<SurfaceDeformationDescriptor>;
|
||||
{ preparedPrescription.parameterCount() } noexcept -> std::same_as<int>;
|
||||
{ preparedPrescription.surfaceDisplacementSize() } noexcept -> std::same_as<int>;
|
||||
{ preparedPrescription.buildSurfaceDisplacement(parameters, surfaceDisplacement) } -> std::same_as<void>;
|
||||
{
|
||||
preparedPrescription.applyJacobian(parameters, parameterDirection, surfaceDisplacement)
|
||||
} -> std::same_as<void>;
|
||||
{
|
||||
preparedPrescription.applyJacobianTranspose(parameters, surfaceDisplacementDual, parameterDual)
|
||||
} -> std::same_as<void>;
|
||||
{
|
||||
preparedPrescription.applyPullbackDerivative(
|
||||
parameters, parameterDirection, surfaceDisplacementDual, parameterDual
|
||||
)
|
||||
} -> std::same_as<void>;
|
||||
};
|
||||
|
||||
template <typename Candidate>
|
||||
concept SurfaceDeformationPrescription = requires(const std::remove_cvref_t<Candidate> &prescription) {
|
||||
typename std::remove_cvref_t<Candidate>::PreparedType;
|
||||
requires PreparedSurfaceDeformationPrescription<typename std::remove_cvref_t<Candidate>::PreparedType>;
|
||||
{ prescription.descriptor() } noexcept -> std::same_as<SurfaceDeformationDescriptor>;
|
||||
{ prescription.validate() } -> std::same_as<void>;
|
||||
};
|
||||
|
||||
template <typename Prescription, typename CompilationContext>
|
||||
concept SurfaceDeformationCompilable =
|
||||
SurfaceDeformationPrescription<Prescription> && requires(
|
||||
const std::remove_cvref_t<Prescription> &prescription,
|
||||
const std::remove_cvref_t<CompilationContext> &context
|
||||
) {
|
||||
{
|
||||
compileSurfaceDeformationPrescription(prescription, context)
|
||||
} -> std::same_as<typename std::remove_cvref_t<Prescription>::PreparedType>;
|
||||
};
|
||||
} // namespace mean_field::deformation
|
||||
61
libmeanfield/interface/deformation/vacuum_extension.cppm
Normal file
61
libmeanfield/interface/deformation/vacuum_extension.cppm
Normal file
@@ -0,0 +1,61 @@
|
||||
module;
|
||||
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:deformation.vacuum_extension;
|
||||
|
||||
export import :deformation.descriptors;
|
||||
|
||||
export namespace mean_field::deformation {
|
||||
template <typename Candidate>
|
||||
concept PreparedVacuumDeformationExtension = requires(
|
||||
const std::remove_cvref_t<Candidate> &preparedExtension,
|
||||
const mfem::Vector &surfaceDisplacement,
|
||||
const mfem::Vector &surfaceDisplacementDirection,
|
||||
const mfem::Vector &vacuumDisplacementDual,
|
||||
mfem::Vector &vacuumDisplacement,
|
||||
mfem::Vector &surfaceDisplacementDual
|
||||
) {
|
||||
{ preparedExtension.descriptor() } noexcept -> std::same_as<VacuumDeformationExtensionDescriptor>;
|
||||
{ preparedExtension.surfaceDisplacementSize() } noexcept -> std::same_as<int>;
|
||||
{ preparedExtension.vacuumDisplacementSize() } noexcept -> std::same_as<int>;
|
||||
{ preparedExtension.scalarTrueDofCount() } noexcept -> std::same_as<int>;
|
||||
{ preparedExtension.hasVacuumSupport(0) } -> std::same_as<bool>;
|
||||
{ preparedExtension.buildVacuumDisplacement(surfaceDisplacement, vacuumDisplacement) } -> std::same_as<void>;
|
||||
{
|
||||
preparedExtension.applyJacobian(surfaceDisplacement, surfaceDisplacementDirection, vacuumDisplacement)
|
||||
} -> std::same_as<void>;
|
||||
{
|
||||
preparedExtension.applyJacobianTranspose(
|
||||
surfaceDisplacement, vacuumDisplacementDual, surfaceDisplacementDual
|
||||
)
|
||||
} -> std::same_as<void>;
|
||||
{
|
||||
preparedExtension.applyPullbackDerivative(
|
||||
surfaceDisplacement, surfaceDisplacementDirection, vacuumDisplacementDual, surfaceDisplacementDual
|
||||
)
|
||||
} -> std::same_as<void>;
|
||||
};
|
||||
|
||||
template <typename Candidate>
|
||||
concept VacuumDeformationExtension = requires(const std::remove_cvref_t<Candidate> &extension) {
|
||||
typename std::remove_cvref_t<Candidate>::PreparedType;
|
||||
requires PreparedVacuumDeformationExtension<typename std::remove_cvref_t<Candidate>::PreparedType>;
|
||||
{ extension.descriptor() } noexcept -> std::same_as<VacuumDeformationExtensionDescriptor>;
|
||||
{ extension.validate() } -> std::same_as<void>;
|
||||
};
|
||||
|
||||
template <typename Extension, typename CompilationContext>
|
||||
concept VacuumDeformationExtensionCompilable =
|
||||
VacuumDeformationExtension<Extension> && requires(
|
||||
const std::remove_cvref_t<Extension> &extension,
|
||||
const std::remove_cvref_t<CompilationContext> &context
|
||||
) {
|
||||
{
|
||||
compileVacuumDeformationExtension(extension, context)
|
||||
} -> std::same_as<typename std::remove_cvref_t<Extension>::PreparedType>;
|
||||
};
|
||||
} // namespace mean_field::deformation
|
||||
Reference in New Issue
Block a user