feat(field-support): added field support system, mid migration
currently the barotope and the pressure force operator are migrated to the new support system
This commit is contained in:
@@ -1,135 +1,190 @@
|
||||
module;
|
||||
|
||||
#include <cstdint>
|
||||
#include <cmath>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
module mean_field;
|
||||
|
||||
import :operators.context.barotropic_closure_linearization;
|
||||
|
||||
namespace {
|
||||
void validate_finite_vector(
|
||||
const mfem::Vector &vector,
|
||||
const char *message
|
||||
) {
|
||||
for (int i = 0; i < vector.Size(); ++i) {
|
||||
MFEM_VERIFY(std::isfinite(vector(i)), message);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Stamp>
|
||||
void validate_dependency_transition(
|
||||
const Stamp &prepared,
|
||||
const Stamp &requested,
|
||||
const char *message
|
||||
) {
|
||||
MFEM_VERIFY(requested.CanFollow(prepared), message);
|
||||
MFEM_VERIFY(
|
||||
prepared.identity == requested.identity || prepared.revision != requested.revision,
|
||||
"A new barotropic-closure dependency identity must also carry a visibly different revision."
|
||||
);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace mean_field::operators::context::barotropic {
|
||||
BarotropicClosureLinearizationContext::
|
||||
BarotropicClosureLinearizationContext(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope
|
||||
)
|
||||
BarotropicClosureLinearizationContext::BarotropicClosureLinearizationContext(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const field::FieldDofMap &densityMap,
|
||||
const field::FieldDofMap &enthalpyMap,
|
||||
const field::FieldDofMap &displacementMap
|
||||
)
|
||||
: m_f(f),
|
||||
m_operator(
|
||||
f,
|
||||
domainMapper,
|
||||
barotrope
|
||||
) {
|
||||
m_domainMapper(domainMapper),
|
||||
m_densitySize(densityMap.reduced_size()),
|
||||
m_enthalpySize(enthalpyMap.reduced_size()),
|
||||
m_displacementSize(displacementMap.reduced_size()) {
|
||||
MFEM_VERIFY(m_f.mesh != nullptr, "BarotropicClosureLinearizationContext requires a mesh.");
|
||||
MFEM_VERIFY(m_f.densityFes != nullptr, "BarotropicClosureLinearizationContext requires the density FE space.");
|
||||
MFEM_VERIFY(
|
||||
m_f.densityFes != nullptr,
|
||||
"The closure linearization context requires the "
|
||||
"density finite-element space."
|
||||
m_f.enthalpyFes != nullptr, "BarotropicClosureLinearizationContext requires the enthalpy FE space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_f.enthalpyFes != nullptr,
|
||||
"The closure linearization context requires the "
|
||||
"enthalpy finite-element space."
|
||||
m_f.displacementFes != nullptr, "BarotropicClosureLinearizationContext requires the displacement FE space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_f.displacementFes != nullptr,
|
||||
"The closure linearization context requires the "
|
||||
"displacement finite-element space."
|
||||
m_domainMapper.GetDimension() == m_f.mesh->Dimension(),
|
||||
"The barotropic-closure context domain-mapper dimension does not match the mesh dimension."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
densityMap.full_size() == m_f.densityFes->GetTrueVSize(),
|
||||
"The density FieldDofMap does not match the density FE space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
enthalpyMap.full_size() == m_f.enthalpyFes->GetTrueVSize(),
|
||||
"The enthalpy FieldDofMap does not match the enthalpy FE space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
displacementMap.full_size() == m_f.displacementFes->GetTrueVSize(),
|
||||
"The displacement FieldDofMap does not match the displacement FE space."
|
||||
);
|
||||
}
|
||||
|
||||
void BarotropicClosureLinearizationContext::Prepare(
|
||||
const mfem::Vector &baseDensityTrue,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
const BarotropicClosureRevisions &revisions
|
||||
BarotropicClosurePreparationReport BarotropicClosureLinearizationContext::Prepare(
|
||||
const BarotropicClosureStateView &state,
|
||||
const BarotropicClosureDependencies &dependencies
|
||||
) {
|
||||
MFEM_VERIFY(state.density.Size() == m_densitySize, "The supported closure density vector has the wrong size.");
|
||||
MFEM_VERIFY(
|
||||
baseDensityTrue.Size() == m_f.densityFes->GetTrueVSize(),
|
||||
"The closure base-density vector has the wrong size."
|
||||
state.enthalpy.Size() == m_enthalpySize, "The supported closure enthalpy vector has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
state.displacement.Size() == m_displacementSize,
|
||||
"The supported closure displacement vector has the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
baseEnthalpyTrue.Size() == m_f.enthalpyFes->GetTrueVSize(),
|
||||
"The closure base-enthalpy vector has the wrong size."
|
||||
);
|
||||
validate_finite_vector(state.density, "The closure density state contains a non-finite value.");
|
||||
validate_finite_vector(state.enthalpy, "The closure enthalpy state contains a non-finite value.");
|
||||
validate_finite_vector(state.displacement, "The closure displacement state contains a non-finite value.");
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementTrue.Size() == m_f.displacementFes->GetTrueVSize(),
|
||||
"The closure displacement vector has the wrong size."
|
||||
);
|
||||
|
||||
if (m_isPrepared && revisions == m_revisions) {
|
||||
return;
|
||||
if (m_isPrepared) {
|
||||
validate_dependency_transition(
|
||||
m_dependencies.discretization, dependencies.discretization,
|
||||
"BarotropicClosureLinearizationContext received an older discretization revision for the same identity."
|
||||
);
|
||||
validate_dependency_transition(
|
||||
m_dependencies.density, dependencies.density,
|
||||
"BarotropicClosureLinearizationContext received an older density revision for the same identity."
|
||||
);
|
||||
validate_dependency_transition(
|
||||
m_dependencies.enthalpy, dependencies.enthalpy,
|
||||
"BarotropicClosureLinearizationContext received an older enthalpy revision for the same identity."
|
||||
);
|
||||
validate_dependency_transition(
|
||||
m_dependencies.displacement, dependencies.displacement,
|
||||
"BarotropicClosureLinearizationContext received an older displacement revision for the same identity."
|
||||
);
|
||||
}
|
||||
|
||||
m_operator.Prepare(baseDensityTrue, baseEnthalpyTrue, displacementTrue);
|
||||
const bool staticChanged = !m_isPrepared || dependencies.discretization != m_dependencies.discretization;
|
||||
const bool densityChanged = !m_isPrepared || dependencies.density != m_dependencies.density;
|
||||
const bool enthalpyChanged = !m_isPrepared || dependencies.enthalpy != m_dependencies.enthalpy;
|
||||
const bool displacementChanged = !m_isPrepared || dependencies.displacement != m_dependencies.displacement;
|
||||
|
||||
m_baseDensityTrue = baseDensityTrue;
|
||||
m_baseEnthalpyTrue = baseEnthalpyTrue;
|
||||
m_displacementTrue = displacementTrue;
|
||||
const bool geometryPreparationRequired = staticChanged || displacementChanged;
|
||||
const bool baseStatePreparationRequired =
|
||||
staticChanged || geometryPreparationRequired || densityChanged || enthalpyChanged;
|
||||
|
||||
m_revisions = revisions;
|
||||
m_isPrepared = true;
|
||||
++m_preparationCount;
|
||||
BarotropicClosurePreparationReport report;
|
||||
report.preparedStaticDependencies = staticChanged;
|
||||
report.preparedGeometryState = geometryPreparationRequired;
|
||||
report.preparedBaseState = baseStatePreparationRequired;
|
||||
|
||||
if (staticChanged || densityChanged) {
|
||||
m_baseDensity = state.density;
|
||||
report.updatedDensity = true;
|
||||
}
|
||||
if (staticChanged || enthalpyChanged) {
|
||||
m_baseEnthalpy = state.enthalpy;
|
||||
report.updatedEnthalpy = true;
|
||||
}
|
||||
if (geometryPreparationRequired) {
|
||||
m_displacement = state.displacement;
|
||||
report.updatedDisplacement = true;
|
||||
}
|
||||
|
||||
if (report.preparedStaticDependencies) {
|
||||
++m_statistics.staticPreparations;
|
||||
}
|
||||
if (report.preparedGeometryState) {
|
||||
++m_statistics.geometryPreparations;
|
||||
}
|
||||
if (report.preparedBaseState) {
|
||||
++m_statistics.baseStatePreparations;
|
||||
}
|
||||
|
||||
m_dependencies = dependencies;
|
||||
m_isPrepared = true;
|
||||
return report;
|
||||
}
|
||||
|
||||
bool BarotropicClosureLinearizationContext::IsPrepared() const noexcept {
|
||||
return m_isPrepared;
|
||||
}
|
||||
|
||||
bool BarotropicClosureLinearizationContext::MatchesRevisions(
|
||||
const BarotropicClosureRevisions &revisions
|
||||
bool BarotropicClosureLinearizationContext::MatchesDependencies(
|
||||
const BarotropicClosureDependencies &dependencies
|
||||
) const noexcept {
|
||||
return m_isPrepared && revisions == m_revisions;
|
||||
return m_isPrepared && dependencies == m_dependencies;
|
||||
}
|
||||
|
||||
std::uint64_t BarotropicClosureLinearizationContext::
|
||||
GetPreparationCount() const noexcept {
|
||||
return m_preparationCount;
|
||||
}
|
||||
|
||||
const BarotropicClosureRevisions &
|
||||
BarotropicClosureLinearizationContext::GetRevisions() const {
|
||||
const BarotropicClosureDependencies &BarotropicClosureLinearizationContext::GetDependencies() const {
|
||||
VerifyPrepared();
|
||||
return m_revisions;
|
||||
return m_dependencies;
|
||||
}
|
||||
|
||||
const mfem::Vector &
|
||||
BarotropicClosureLinearizationContext::GetBaseDensityTrue() const {
|
||||
const BarotropicClosurePreparationStatistics &
|
||||
BarotropicClosureLinearizationContext::GetPreparationStatistics() const noexcept {
|
||||
return m_statistics;
|
||||
}
|
||||
|
||||
const mfem::Vector &BarotropicClosureLinearizationContext::GetBaseDensity() const {
|
||||
VerifyPrepared();
|
||||
return m_baseDensityTrue;
|
||||
return m_baseDensity;
|
||||
}
|
||||
|
||||
const mfem::Vector &
|
||||
BarotropicClosureLinearizationContext::GetBaseEnthalpyTrue() const {
|
||||
const mfem::Vector &BarotropicClosureLinearizationContext::GetBaseEnthalpy() const {
|
||||
VerifyPrepared();
|
||||
return m_baseEnthalpyTrue;
|
||||
return m_baseEnthalpy;
|
||||
}
|
||||
|
||||
const mfem::Vector &
|
||||
BarotropicClosureLinearizationContext::GetDisplacementTrue() const {
|
||||
const mfem::Vector &BarotropicClosureLinearizationContext::GetDisplacement() const {
|
||||
VerifyPrepared();
|
||||
return m_displacementTrue;
|
||||
}
|
||||
|
||||
const PreparedBarotropicClosureOperator &
|
||||
BarotropicClosureLinearizationContext::GetOperator() const noexcept {
|
||||
return m_operator;
|
||||
}
|
||||
|
||||
void BarotropicClosureLinearizationContext::BuildResidual(
|
||||
mfem::Vector &residual
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
m_operator.BuildResidual(residual);
|
||||
return m_displacement;
|
||||
}
|
||||
|
||||
void BarotropicClosureLinearizationContext::VerifyPrepared() const {
|
||||
MFEM_VERIFY(
|
||||
m_isPrepared, "The barotropic-closure linearization context "
|
||||
"has not been prepared."
|
||||
);
|
||||
MFEM_VERIFY(m_isPrepared, "BarotropicClosureLinearizationContext has not been prepared.");
|
||||
}
|
||||
} // namespace mean_field::operators::context::barotropic
|
||||
} // namespace mean_field::operators::context::barotropic
|
||||
|
||||
@@ -12,9 +12,8 @@ namespace {
|
||||
const mfem::Vector &displacement_true
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr,
|
||||
"GravityFieldGeometryContext requires the "
|
||||
"displacement finite-element space."
|
||||
f.displacementFes != nullptr, "GravityFieldGeometryContext requires the "
|
||||
"displacement finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
displacement_true.Size() == f.displacementFes->GetTrueVSize(),
|
||||
@@ -25,18 +24,16 @@ namespace {
|
||||
|
||||
for (int i = 0; i < displacement_true.Size(); ++i) {
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(displacement_true(i)),
|
||||
"GravityFieldGeometryContext received a non-finite "
|
||||
"displacement "
|
||||
"value."
|
||||
std::isfinite(displacement_true(i)), "GravityFieldGeometryContext received a non-finite "
|
||||
"displacement "
|
||||
"value."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void validate_linearization_state(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::operators::context::gravity_field::
|
||||
GravityFieldStateView &state
|
||||
const mean_field::operators::context::gravity_field::GravityFieldStateView &state
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr, "GravityFieldLinearizationContext "
|
||||
@@ -44,19 +41,16 @@ namespace {
|
||||
"space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.gravityPotentialFes != nullptr,
|
||||
"GravityFieldLinearizationContext requires the gravity-potential "
|
||||
"finite-element space."
|
||||
f.gravityPotentialFes != nullptr, "GravityFieldLinearizationContext requires the gravity-potential "
|
||||
"finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.gravityFluxFes != nullptr,
|
||||
"GravityFieldLinearizationContext requires the "
|
||||
"gravity-gradient finite-element space."
|
||||
f.gravityFluxFes != nullptr, "GravityFieldLinearizationContext requires the "
|
||||
"gravity-gradient finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr,
|
||||
"GravityFieldLinearizationContext requires "
|
||||
"the displacement finite-element space."
|
||||
f.displacementFes != nullptr, "GravityFieldLinearizationContext requires "
|
||||
"the displacement finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
@@ -78,8 +72,7 @@ namespace {
|
||||
"with the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
state.gravity_potential.Size() ==
|
||||
f.gravityPotentialFes->GetTrueVSize(),
|
||||
state.gravity_potential.Size() == f.gravityPotentialFes->GetTrueVSize(),
|
||||
"GravityFieldLinearizationContext received a gravity-potential "
|
||||
"vector "
|
||||
"with the wrong size."
|
||||
@@ -87,35 +80,31 @@ namespace {
|
||||
|
||||
for (int i = 0; i < state.density.Size(); ++i) {
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(state.density(i)),
|
||||
"GravityFieldLinearizationContext received a non-finite "
|
||||
"density "
|
||||
"value."
|
||||
std::isfinite(state.density(i)), "GravityFieldLinearizationContext received a non-finite "
|
||||
"density "
|
||||
"value."
|
||||
);
|
||||
}
|
||||
|
||||
for (int i = 0; i < state.displacement.Size(); ++i) {
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(state.displacement(i)),
|
||||
"GravityFieldLinearizationContext received a non-finite "
|
||||
"displacement "
|
||||
"value."
|
||||
std::isfinite(state.displacement(i)), "GravityFieldLinearizationContext received a non-finite "
|
||||
"displacement "
|
||||
"value."
|
||||
);
|
||||
}
|
||||
|
||||
for (int i = 0; i < state.gravity_gradient.Size(); ++i) {
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(state.gravity_gradient(i)),
|
||||
"GravityFieldLinearizationContext received a non-finite "
|
||||
"gravity-gradient value."
|
||||
std::isfinite(state.gravity_gradient(i)), "GravityFieldLinearizationContext received a non-finite "
|
||||
"gravity-gradient value."
|
||||
);
|
||||
}
|
||||
|
||||
for (int i = 0; i < state.gravity_potential.Size(); ++i) {
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(state.gravity_potential(i)),
|
||||
"GravityFieldLinearizationContext received a non-finite "
|
||||
"gravity-potential value."
|
||||
std::isfinite(state.gravity_potential(i)), "GravityFieldLinearizationContext received a non-finite "
|
||||
"gravity-potential value."
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -128,42 +117,33 @@ namespace mean_field::operators::context::gravity_field {
|
||||
)
|
||||
: m_fem(f),
|
||||
m_domain_mapper(domain_mapper) {
|
||||
MFEM_VERIFY(f.mesh != nullptr, "GravityFieldGeometryContext requires a mesh.");
|
||||
MFEM_VERIFY(
|
||||
f.mesh != nullptr, "GravityFieldGeometryContext requires a mesh."
|
||||
f.gravityFluxFes != nullptr, "GravityFieldGeometryContext requires the "
|
||||
"gravity-gradient finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.gravityFluxFes != nullptr,
|
||||
"GravityFieldGeometryContext requires the "
|
||||
"gravity-gradient finite-element space."
|
||||
f.densityFes != nullptr, "GravityFieldGeometryContext requires the density finite-element "
|
||||
"space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr,
|
||||
"GravityFieldGeometryContext requires the density finite-element "
|
||||
"space."
|
||||
f.gravityPotentialFes != nullptr, "GravityFieldGeometryContext requires the gravity-potential "
|
||||
"finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.gravityPotentialFes != nullptr,
|
||||
"GravityFieldGeometryContext requires the gravity-potential "
|
||||
"finite-element space."
|
||||
f.displacementFes != nullptr, "GravityFieldGeometryContext requires the "
|
||||
"displacement finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr,
|
||||
"GravityFieldGeometryContext requires the "
|
||||
"displacement finite-element space."
|
||||
f.compactificationFes != nullptr, "GravityFieldGeometryContext requires the compactification "
|
||||
"finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.compactificationFes != nullptr,
|
||||
"GravityFieldGeometryContext requires the compactification "
|
||||
"finite-element space."
|
||||
f.compactificationCoordinate != nullptr, "GravityFieldGeometryContext requires the compactification "
|
||||
"coordinate."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.compactificationCoordinate != nullptr,
|
||||
"GravityFieldGeometryContext requires the compactification "
|
||||
"coordinate."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr,
|
||||
"GravityFieldGeometryContext requires the quadrature-rule factory."
|
||||
f.quadratureFactory != nullptr, "GravityFieldGeometryContext requires the quadrature-rule factory."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
domain_mapper.GetDimension() == f.mesh->Dimension(),
|
||||
@@ -192,11 +172,8 @@ namespace mean_field::operators::context::gravity_field {
|
||||
);
|
||||
}
|
||||
|
||||
const bool discretization_changed =
|
||||
!m_is_prepared ||
|
||||
discretization_revision != m_discretization_revision;
|
||||
const bool displacement_changed =
|
||||
!m_is_prepared || displacement_revision != m_displacement_revision;
|
||||
const bool discretization_changed = !m_is_prepared || discretization_revision != m_discretization_revision;
|
||||
const bool displacement_changed = !m_is_prepared || displacement_revision != m_displacement_revision;
|
||||
|
||||
GravityFieldGeometryPreparation preparation;
|
||||
|
||||
@@ -205,14 +182,8 @@ namespace mean_field::operators::context::gravity_field {
|
||||
}
|
||||
|
||||
if (discretization_changed) {
|
||||
auto mass_operator =
|
||||
std::make_unique<PreparedMappedHDivMassOperator>(
|
||||
m_fem, m_domain_mapper
|
||||
);
|
||||
auto source_operator =
|
||||
std::make_unique<PreparedMappedGravitySourceOperator>(
|
||||
m_fem, m_domain_mapper
|
||||
);
|
||||
auto mass_operator = std::make_unique<PreparedMappedHDivMassOperator>(m_fem, m_domain_mapper);
|
||||
auto source_operator = std::make_unique<PreparedMappedGravitySourceOperator>(m_fem, m_domain_mapper);
|
||||
|
||||
mass_operator->Prepare(displacement_true);
|
||||
source_operator->Prepare(displacement_true);
|
||||
@@ -229,9 +200,8 @@ namespace mean_field::operators::context::gravity_field {
|
||||
"no prepared H(div) mass operator."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
m_source_operator != nullptr,
|
||||
"GravityFieldGeometryContext has no prepared gravity source "
|
||||
"operator."
|
||||
m_source_operator != nullptr, "GravityFieldGeometryContext has no prepared gravity source "
|
||||
"operator."
|
||||
);
|
||||
|
||||
m_mass_operator->Prepare(displacement_true);
|
||||
@@ -251,26 +221,19 @@ namespace mean_field::operators::context::gravity_field {
|
||||
return preparation;
|
||||
}
|
||||
|
||||
const PreparedMappedHDivMassOperator &
|
||||
GravityFieldGeometryContext::GetMassOperator() const {
|
||||
const PreparedMappedHDivMassOperator &GravityFieldGeometryContext::GetMassOperator() const {
|
||||
MFEM_VERIFY(
|
||||
m_is_prepared,
|
||||
"GravityFieldGeometryContext must be prepared before "
|
||||
"accessing its mass operator."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
m_mass_operator != nullptr,
|
||||
"GravityFieldGeometryContext has no prepared H(div) mass operator."
|
||||
m_is_prepared, "GravityFieldGeometryContext must be prepared before "
|
||||
"accessing its mass operator."
|
||||
);
|
||||
MFEM_VERIFY(m_mass_operator != nullptr, "GravityFieldGeometryContext has no prepared H(div) mass operator.");
|
||||
return *m_mass_operator;
|
||||
}
|
||||
|
||||
const PreparedMappedGravitySourceOperator &
|
||||
GravityFieldGeometryContext::GetSourceOperator() const {
|
||||
const PreparedMappedGravitySourceOperator &GravityFieldGeometryContext::GetSourceOperator() const {
|
||||
MFEM_VERIFY(
|
||||
m_is_prepared,
|
||||
"GravityFieldGeometryContext must be prepared before "
|
||||
"accessing its source operator."
|
||||
m_is_prepared, "GravityFieldGeometryContext must be prepared before "
|
||||
"accessing its source operator."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
m_source_operator != nullptr, "GravityFieldGeometryContext has no "
|
||||
@@ -281,20 +244,17 @@ namespace mean_field::operators::context::gravity_field {
|
||||
|
||||
const mfem::Vector &GravityFieldGeometryContext::GetDisplacement() const {
|
||||
MFEM_VERIFY(
|
||||
m_is_prepared,
|
||||
"GravityFieldGeometryContext must be prepared before "
|
||||
"accessing its displacement."
|
||||
m_is_prepared, "GravityFieldGeometryContext must be prepared before "
|
||||
"accessing its displacement."
|
||||
);
|
||||
return m_displacement_true;
|
||||
}
|
||||
|
||||
DiscretizationRevision
|
||||
GravityFieldGeometryContext::GetDiscretizationRevision() const noexcept {
|
||||
DiscretizationRevision GravityFieldGeometryContext::GetDiscretizationRevision() const noexcept {
|
||||
return m_discretization_revision;
|
||||
}
|
||||
|
||||
DisplacementRevision
|
||||
GravityFieldGeometryContext::GetDisplacementRevision() const noexcept {
|
||||
DisplacementRevision GravityFieldGeometryContext::GetDisplacementRevision() const noexcept {
|
||||
return m_displacement_revision;
|
||||
}
|
||||
|
||||
@@ -317,19 +277,16 @@ namespace mean_field::operators::context::gravity_field {
|
||||
"space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.gravityPotentialFes != nullptr,
|
||||
"GravityFieldLinearizationContext requires the gravity-potential "
|
||||
"finite-element space."
|
||||
f.gravityPotentialFes != nullptr, "GravityFieldLinearizationContext requires the gravity-potential "
|
||||
"finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.gravityFluxFes != nullptr,
|
||||
"GravityFieldLinearizationContext requires the "
|
||||
"gravity-gradient finite-element space."
|
||||
f.gravityFluxFes != nullptr, "GravityFieldLinearizationContext requires the "
|
||||
"gravity-gradient finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr,
|
||||
"GravityFieldLinearizationContext requires "
|
||||
"the displacement finite-element space."
|
||||
f.displacementFes != nullptr, "GravityFieldLinearizationContext requires "
|
||||
"the displacement finite-element space."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -353,9 +310,8 @@ namespace mean_field::operators::context::gravity_field {
|
||||
"revision."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
revisions.density >= m_revisions.density,
|
||||
"GravityFieldLinearizationContext received an older density "
|
||||
"revision."
|
||||
revisions.density >= m_revisions.density, "GravityFieldLinearizationContext received an older density "
|
||||
"revision."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
revisions.gravity_gradient >= m_revisions.gravity_gradient,
|
||||
@@ -370,20 +326,16 @@ namespace mean_field::operators::context::gravity_field {
|
||||
);
|
||||
}
|
||||
|
||||
const bool discretization_changed =
|
||||
!m_is_prepared ||
|
||||
revisions.discretization != m_revisions.discretization;
|
||||
const bool density_changed = !m_is_prepared || discretization_changed ||
|
||||
revisions.density != m_revisions.density;
|
||||
const bool discretization_changed = !m_is_prepared || revisions.discretization != m_revisions.discretization;
|
||||
const bool density_changed =
|
||||
!m_is_prepared || discretization_changed || revisions.density != m_revisions.density;
|
||||
const bool gravity_gradient_changed =
|
||||
!m_is_prepared || discretization_changed ||
|
||||
revisions.gravity_gradient != m_revisions.gravity_gradient;
|
||||
!m_is_prepared || discretization_changed || revisions.gravity_gradient != m_revisions.gravity_gradient;
|
||||
|
||||
GravityFieldPreparationReport report;
|
||||
|
||||
report.geometry = m_geometry_context.Prepare(
|
||||
state.displacement, revisions.discretization, revisions.displacement
|
||||
);
|
||||
report.geometry =
|
||||
m_geometry_context.Prepare(state.displacement, revisions.discretization, revisions.displacement);
|
||||
|
||||
if (density_changed) {
|
||||
m_density_true = state.density;
|
||||
@@ -401,8 +353,7 @@ namespace mean_field::operators::context::gravity_field {
|
||||
return report;
|
||||
}
|
||||
|
||||
const GravityFieldGeometryContext &
|
||||
GravityFieldLinearizationContext::GetGeometryContext() const {
|
||||
const GravityFieldGeometryContext &GravityFieldLinearizationContext::GetGeometryContext() const {
|
||||
MFEM_VERIFY(
|
||||
m_is_prepared, "GravityFieldLinearizationContext must be prepared "
|
||||
"before accessing its geometry context."
|
||||
@@ -418,8 +369,7 @@ namespace mean_field::operators::context::gravity_field {
|
||||
return m_density_true;
|
||||
}
|
||||
|
||||
const mfem::Vector &
|
||||
GravityFieldLinearizationContext::GetGravityGradient() const {
|
||||
const mfem::Vector &GravityFieldLinearizationContext::GetGravityGradient() const {
|
||||
MFEM_VERIFY(
|
||||
m_is_prepared, "GravityFieldLinearizationContext must be prepared "
|
||||
"before accessing its gravity gradient."
|
||||
@@ -427,8 +377,7 @@ namespace mean_field::operators::context::gravity_field {
|
||||
return m_gravity_gradient_true;
|
||||
}
|
||||
|
||||
const GravityFieldRevisions &
|
||||
GravityFieldLinearizationContext::GetRevisions() const {
|
||||
const GravityFieldRevisions &GravityFieldLinearizationContext::GetRevisions() const {
|
||||
MFEM_VERIFY(
|
||||
m_is_prepared, "GravityFieldLinearizationContext must be prepared "
|
||||
"before accessing its revisions."
|
||||
|
||||
@@ -20,44 +20,37 @@ namespace {
|
||||
|
||||
void validate_state(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::operators::context::hydrostatic::
|
||||
HydrostaticEquilibriumStateView &state
|
||||
const mean_field::operators::context::hydrostatic::HydrostaticEquilibriumStateView &state
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
f.enthalpyFes != nullptr,
|
||||
"HydrostaticEquilibriumContext requires the "
|
||||
"enthalpy finite-element space."
|
||||
f.enthalpyFes != nullptr, "HydrostaticEquilibriumContext requires the "
|
||||
"enthalpy finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.gravityPotentialFes != nullptr,
|
||||
"HydrostaticEquilibriumContext requires the "
|
||||
"gravity-potential finite-element space."
|
||||
f.gravityPotentialFes != nullptr, "HydrostaticEquilibriumContext requires the "
|
||||
"gravity-potential finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr,
|
||||
"HydrostaticEquilibriumContext requires the "
|
||||
"displacement finite-element space."
|
||||
f.displacementFes != nullptr, "HydrostaticEquilibriumContext requires the "
|
||||
"displacement finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
state.enthalpy.Size() == f.enthalpyFes->GetTrueVSize(),
|
||||
"HydrostaticEquilibriumContext received an "
|
||||
"enthalpy vector with the wrong size."
|
||||
state.enthalpy.Size() == f.enthalpyFes->GetTrueVSize(), "HydrostaticEquilibriumContext received an "
|
||||
"enthalpy vector with the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
state.gravityPotential.Size() ==
|
||||
f.gravityPotentialFes->GetTrueVSize(),
|
||||
state.gravityPotential.Size() == f.gravityPotentialFes->GetTrueVSize(),
|
||||
"HydrostaticEquilibriumContext received a "
|
||||
"gravity-potential vector with the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
state.displacement.Size() == f.displacementFes->GetTrueVSize(),
|
||||
"HydrostaticEquilibriumContext received a "
|
||||
"displacement vector with the wrong size."
|
||||
state.displacement.Size() == f.displacementFes->GetTrueVSize(), "HydrostaticEquilibriumContext received a "
|
||||
"displacement vector with the wrong size."
|
||||
);
|
||||
|
||||
validate_finite_vector(
|
||||
@@ -76,9 +69,8 @@ namespace {
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(state.bernoulliConstant),
|
||||
"HydrostaticEquilibriumContext received a "
|
||||
"non-finite Bernoulli constant."
|
||||
std::isfinite(state.bernoulliConstant), "HydrostaticEquilibriumContext received a "
|
||||
"non-finite Bernoulli constant."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -99,34 +91,27 @@ namespace mean_field::operators::context::hydrostatic {
|
||||
)
|
||||
: m_f(f),
|
||||
m_domainMapper(domainMapper) {
|
||||
MFEM_VERIFY(m_f.mesh != nullptr, "HydrostaticEquilibriumContext requires a mesh.");
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_f.mesh != nullptr,
|
||||
"HydrostaticEquilibriumContext requires a mesh."
|
||||
m_f.enthalpyFes != nullptr, "HydrostaticEquilibriumContext requires the "
|
||||
"enthalpy finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_f.enthalpyFes != nullptr,
|
||||
"HydrostaticEquilibriumContext requires the "
|
||||
"enthalpy finite-element space."
|
||||
m_f.gravityPotentialFes != nullptr, "HydrostaticEquilibriumContext requires the "
|
||||
"gravity-potential finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_f.gravityPotentialFes != nullptr,
|
||||
"HydrostaticEquilibriumContext requires the "
|
||||
"gravity-potential finite-element space."
|
||||
m_f.displacementFes != nullptr, "HydrostaticEquilibriumContext requires the "
|
||||
"displacement finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_f.displacementFes != nullptr,
|
||||
"HydrostaticEquilibriumContext requires the "
|
||||
"displacement finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_domainMapper.GetDimension() == m_f.mesh->Dimension(),
|
||||
"The hydrostatic context's stateless "
|
||||
"domain-mapper dimension does not match the mesh "
|
||||
"dimension."
|
||||
m_domainMapper.GetDimension() == m_f.mesh->Dimension(), "The hydrostatic context's stateless "
|
||||
"domain-mapper dimension does not match the mesh "
|
||||
"dimension."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -168,44 +153,32 @@ namespace mean_field::operators::context::hydrostatic {
|
||||
);
|
||||
|
||||
validate_dependency_transition(
|
||||
m_dependencies.bernoulliConstant,
|
||||
dependencies.bernoulliConstant,
|
||||
m_dependencies.bernoulliConstant, dependencies.bernoulliConstant,
|
||||
"HydrostaticEquilibriumContext received an older "
|
||||
"Bernoulli-constant revision for the same identity."
|
||||
);
|
||||
}
|
||||
|
||||
const bool staticChanged =
|
||||
!m_isPrepared ||
|
||||
dependencies.discretization != m_dependencies.discretization;
|
||||
const bool staticChanged = !m_isPrepared || dependencies.discretization != m_dependencies.discretization;
|
||||
|
||||
const bool enthalpyChanged =
|
||||
!m_isPrepared || dependencies.enthalpy != m_dependencies.enthalpy;
|
||||
const bool enthalpyChanged = !m_isPrepared || dependencies.enthalpy != m_dependencies.enthalpy;
|
||||
|
||||
const bool gravityPotentialChanged =
|
||||
!m_isPrepared ||
|
||||
dependencies.gravityPotential != m_dependencies.gravityPotential;
|
||||
!m_isPrepared || dependencies.gravityPotential != m_dependencies.gravityPotential;
|
||||
|
||||
const bool displacementChanged =
|
||||
!m_isPrepared ||
|
||||
dependencies.displacement != m_dependencies.displacement;
|
||||
const bool displacementChanged = !m_isPrepared || dependencies.displacement != m_dependencies.displacement;
|
||||
|
||||
const bool rotationChanged =
|
||||
!m_isPrepared || dependencies.rotation != m_dependencies.rotation;
|
||||
const bool rotationChanged = !m_isPrepared || dependencies.rotation != m_dependencies.rotation;
|
||||
|
||||
const bool bernoulliConstantChanged =
|
||||
!m_isPrepared ||
|
||||
dependencies.bernoulliConstant != m_dependencies.bernoulliConstant;
|
||||
!m_isPrepared || dependencies.bernoulliConstant != m_dependencies.bernoulliConstant;
|
||||
|
||||
const bool geometryPreparationRequired =
|
||||
staticChanged || displacementChanged;
|
||||
const bool geometryPreparationRequired = staticChanged || displacementChanged;
|
||||
|
||||
const bool rotationPreparationRequired =
|
||||
geometryPreparationRequired || rotationChanged;
|
||||
const bool rotationPreparationRequired = geometryPreparationRequired || rotationChanged;
|
||||
|
||||
const bool baseStatePreparationRequired =
|
||||
rotationPreparationRequired || enthalpyChanged ||
|
||||
gravityPotentialChanged || bernoulliConstantChanged;
|
||||
rotationPreparationRequired || enthalpyChanged || gravityPotentialChanged || bernoulliConstantChanged;
|
||||
|
||||
HydrostaticPreparationReport report;
|
||||
|
||||
@@ -267,31 +240,26 @@ namespace mean_field::operators::context::hydrostatic {
|
||||
return m_isPrepared && dependencies == m_dependencies;
|
||||
}
|
||||
|
||||
const HydrostaticEquilibriumDependencies &
|
||||
HydrostaticEquilibriumContext::GetDependencies() const {
|
||||
const HydrostaticEquilibriumDependencies &HydrostaticEquilibriumContext::GetDependencies() const {
|
||||
VerifyPrepared();
|
||||
return m_dependencies;
|
||||
}
|
||||
|
||||
const HydrostaticPreparationStatistics &
|
||||
HydrostaticEquilibriumContext::GetPreparationStatistics() const noexcept {
|
||||
const HydrostaticPreparationStatistics &HydrostaticEquilibriumContext::GetPreparationStatistics() const noexcept {
|
||||
return m_statistics;
|
||||
}
|
||||
|
||||
const mfem::Vector &
|
||||
HydrostaticEquilibriumContext::GetBaseEnthalpyTrue() const {
|
||||
const mfem::Vector &HydrostaticEquilibriumContext::GetBaseEnthalpyTrue() const {
|
||||
VerifyPrepared();
|
||||
return m_baseEnthalpyTrue;
|
||||
}
|
||||
|
||||
const mfem::Vector &
|
||||
HydrostaticEquilibriumContext::GetBaseGravityPotentialTrue() const {
|
||||
const mfem::Vector &HydrostaticEquilibriumContext::GetBaseGravityPotentialTrue() const {
|
||||
VerifyPrepared();
|
||||
return m_baseGravityPotentialTrue;
|
||||
}
|
||||
|
||||
const mfem::Vector &
|
||||
HydrostaticEquilibriumContext::GetDisplacementTrue() const {
|
||||
const mfem::Vector &HydrostaticEquilibriumContext::GetDisplacementTrue() const {
|
||||
VerifyPrepared();
|
||||
return m_displacementTrue;
|
||||
}
|
||||
@@ -302,8 +270,6 @@ namespace mean_field::operators::context::hydrostatic {
|
||||
}
|
||||
|
||||
void HydrostaticEquilibriumContext::VerifyPrepared() const {
|
||||
MFEM_VERIFY(
|
||||
m_isPrepared, "HydrostaticEquilibriumContext has not been prepared."
|
||||
);
|
||||
MFEM_VERIFY(m_isPrepared, "HydrostaticEquilibriumContext has not been prepared.");
|
||||
}
|
||||
} // namespace mean_field::operators::context::hydrostatic
|
||||
|
||||
219
libmeanfield/impl/operators/contexts/pressure_force_context.cpp
Normal file
219
libmeanfield/impl/operators/contexts/pressure_force_context.cpp
Normal file
@@ -0,0 +1,219 @@
|
||||
module;
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
module mean_field;
|
||||
|
||||
import :operators.context.pressure_force;
|
||||
|
||||
namespace {
|
||||
void validate_finite_vector(
|
||||
const mfem::Vector &vector,
|
||||
const char *message
|
||||
) {
|
||||
for (int index = 0; index < vector.Size(); ++index) {
|
||||
MFEM_VERIFY(std::isfinite(vector(index)), message);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Dependency>
|
||||
void validate_dependency_transition(
|
||||
const Dependency &prepared,
|
||||
const Dependency &requested,
|
||||
const char *message
|
||||
) {
|
||||
MFEM_VERIFY(requested.CanFollow(prepared), message);
|
||||
|
||||
MFEM_VERIFY(
|
||||
prepared.identity == requested.identity || prepared.revision != requested.revision,
|
||||
"A new pressure-force dependency identity must also carry "
|
||||
"a visibly different revision."
|
||||
);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace mean_field::operators::context::pressure_force {
|
||||
PressureForceLinearizationContext::PressureForceLinearizationContext(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const field::FieldDofMap &enthalpyMap,
|
||||
const field::FieldDofMap &displacementMap
|
||||
)
|
||||
: m_enthalpySize(enthalpyMap.reduced_size()),
|
||||
m_displacementSize(displacementMap.reduced_size()) {
|
||||
MFEM_VERIFY(f.mesh != nullptr, "PressureForceLinearizationContext requires a mesh.");
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.enthalpyFes != nullptr, "PressureForceLinearizationContext requires the enthalpy "
|
||||
"finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr, "PressureForceLinearizationContext requires the displacement "
|
||||
"finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
domainMapper.GetDimension() == f.mesh->Dimension(), "The pressure-force context's stateless domain-mapper "
|
||||
"dimension does not match the mesh dimension."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
enthalpyMap.full_size() == f.enthalpyFes->GetTrueVSize(),
|
||||
"The pressure-force enthalpy FieldDofMap does not match the "
|
||||
"enthalpy finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementMap.full_size() == f.displacementFes->GetTrueVSize(),
|
||||
"The pressure-force displacement FieldDofMap does not match "
|
||||
"the displacement finite-element space."
|
||||
);
|
||||
}
|
||||
|
||||
PressureForcePreparationReport PressureForceLinearizationContext::Prepare(
|
||||
const PressureForceStateView &state,
|
||||
const PressureForceDependencies &dependencies
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
state.enthalpy.Size() == m_enthalpySize, "PressureForceLinearizationContext received a supported "
|
||||
"enthalpy vector with the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
state.displacement.Size() == m_displacementSize, "PressureForceLinearizationContext received a supported "
|
||||
"displacement vector with the wrong size."
|
||||
);
|
||||
|
||||
validate_finite_vector(
|
||||
state.enthalpy, "PressureForceLinearizationContext received a non-finite "
|
||||
"enthalpy value."
|
||||
);
|
||||
|
||||
validate_finite_vector(
|
||||
state.displacement, "PressureForceLinearizationContext received a non-finite "
|
||||
"displacement value."
|
||||
);
|
||||
|
||||
if (m_isPrepared) {
|
||||
validate_dependency_transition(
|
||||
m_dependencies.discretization, dependencies.discretization,
|
||||
"PressureForceLinearizationContext received an older "
|
||||
"discretization revision for the same identity."
|
||||
);
|
||||
|
||||
validate_dependency_transition(
|
||||
m_dependencies.enthalpy, dependencies.enthalpy,
|
||||
"PressureForceLinearizationContext received an older "
|
||||
"enthalpy revision for the same identity."
|
||||
);
|
||||
|
||||
validate_dependency_transition(
|
||||
m_dependencies.displacement, dependencies.displacement,
|
||||
"PressureForceLinearizationContext received an older "
|
||||
"displacement revision for the same identity."
|
||||
);
|
||||
}
|
||||
|
||||
const bool discretizationChanged =
|
||||
!m_isPrepared || dependencies.discretization != m_dependencies.discretization;
|
||||
|
||||
const bool enthalpyChanged = !m_isPrepared || dependencies.enthalpy != m_dependencies.enthalpy;
|
||||
|
||||
const bool displacementChanged = !m_isPrepared || dependencies.displacement != m_dependencies.displacement;
|
||||
|
||||
/*
|
||||
* Static data depend only on discretization.
|
||||
*
|
||||
* Geometry data depend on discretization and displacement.
|
||||
*
|
||||
* Material data depend on both geometry and enthalpy because
|
||||
* pressure and its enthalpy derivative are evaluated on the frozen
|
||||
* mapped state.
|
||||
*/
|
||||
const bool geometryPreparationRequired = discretizationChanged || displacementChanged;
|
||||
|
||||
const bool materialPreparationRequired = geometryPreparationRequired || enthalpyChanged;
|
||||
|
||||
PressureForcePreparationReport report;
|
||||
|
||||
report.preparedStaticDependencies = discretizationChanged;
|
||||
|
||||
report.preparedGeometryState = geometryPreparationRequired;
|
||||
|
||||
report.preparedMaterialState = materialPreparationRequired;
|
||||
|
||||
/*
|
||||
* A discretization change invalidates every frozen field because
|
||||
* their coordinate interpretation may have changed.
|
||||
*/
|
||||
if (discretizationChanged || enthalpyChanged) {
|
||||
m_baseEnthalpy = state.enthalpy;
|
||||
|
||||
report.updatedEnthalpy = true;
|
||||
}
|
||||
|
||||
if (geometryPreparationRequired) {
|
||||
m_displacement = state.displacement;
|
||||
|
||||
report.updatedDisplacement = true;
|
||||
}
|
||||
|
||||
if (report.preparedStaticDependencies) {
|
||||
++m_statistics.staticPreparations;
|
||||
}
|
||||
|
||||
if (report.preparedGeometryState) {
|
||||
++m_statistics.geometryPreparations;
|
||||
}
|
||||
|
||||
if (report.preparedMaterialState) {
|
||||
++m_statistics.materialPreparations;
|
||||
}
|
||||
|
||||
m_dependencies = dependencies;
|
||||
|
||||
m_isPrepared = true;
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
const PressureForcePreparationStatistics &
|
||||
PressureForceLinearizationContext::GetPreparationStatistics() const noexcept {
|
||||
return m_statistics;
|
||||
}
|
||||
|
||||
bool PressureForceLinearizationContext::IsPrepared() const noexcept {
|
||||
return m_isPrepared;
|
||||
}
|
||||
|
||||
bool PressureForceLinearizationContext::MatchesDependencies(
|
||||
const PressureForceDependencies &dependencies
|
||||
) const noexcept {
|
||||
return m_isPrepared && dependencies == m_dependencies;
|
||||
}
|
||||
|
||||
const PressureForceDependencies &PressureForceLinearizationContext::GetDependencies() const {
|
||||
VerifyPrepared();
|
||||
|
||||
return m_dependencies;
|
||||
}
|
||||
|
||||
const mfem::Vector &PressureForceLinearizationContext::GetBaseEnthalpy() const {
|
||||
VerifyPrepared();
|
||||
|
||||
return m_baseEnthalpy;
|
||||
}
|
||||
|
||||
const mfem::Vector &PressureForceLinearizationContext::GetDisplacement() const {
|
||||
VerifyPrepared();
|
||||
|
||||
return m_displacement;
|
||||
}
|
||||
|
||||
void PressureForceLinearizationContext::VerifyPrepared() const {
|
||||
MFEM_VERIFY(m_isPrepared, "PressureForceLinearizationContext has not been prepared.");
|
||||
}
|
||||
} // namespace mean_field::operators::context::pressure_force
|
||||
@@ -0,0 +1,203 @@
|
||||
module;
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
module mean_field;
|
||||
|
||||
import :operators.context.rotational_displacement_force;
|
||||
|
||||
namespace {
|
||||
void validate_finite_vector(
|
||||
const mfem::Vector &vector,
|
||||
const char *message
|
||||
) {
|
||||
for (int index = 0; index < vector.Size(); ++index) {
|
||||
MFEM_VERIFY(std::isfinite(vector(index)), message);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Dependency>
|
||||
void validate_dependency_transition(
|
||||
const Dependency &prepared,
|
||||
const Dependency &requested,
|
||||
const char *message
|
||||
) {
|
||||
MFEM_VERIFY(requested.CanFollow(prepared), message);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace mean_field::operators::context::rotational_displacement_force {
|
||||
RotationalDisplacementForceLinearizationContext::RotationalDisplacementForceLinearizationContext(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper
|
||||
)
|
||||
: m_f(f) {
|
||||
MFEM_VERIFY(
|
||||
m_f.mesh != nullptr, "RotationalDisplacementForceLinearizationContext requires a "
|
||||
"mesh."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_f.densityFes != nullptr, "RotationalDisplacementForceLinearizationContext requires the "
|
||||
"density finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_f.displacementFes != nullptr, "RotationalDisplacementForceLinearizationContext requires the "
|
||||
"displacement finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
domainMapper.GetDimension() == m_f.mesh->Dimension(),
|
||||
"The rotational-displacement-force context's stateless "
|
||||
"domain-mapper dimension does not match the mesh dimension."
|
||||
);
|
||||
}
|
||||
|
||||
RotationalDisplacementForcePreparationReport RotationalDisplacementForceLinearizationContext::Prepare(
|
||||
const RotationalDisplacementForceStateView &state,
|
||||
const RotationalDisplacementForceDependencies &dependencies
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
state.density.Size() == m_f.densityFes->GetTrueVSize(),
|
||||
"RotationalDisplacementForceLinearizationContext received a "
|
||||
"density vector with the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
state.displacement.Size() == m_f.displacementFes->GetTrueVSize(),
|
||||
"RotationalDisplacementForceLinearizationContext received a "
|
||||
"displacement vector with the wrong size."
|
||||
);
|
||||
|
||||
validate_finite_vector(
|
||||
state.density, "RotationalDisplacementForceLinearizationContext received a "
|
||||
"non-finite density value."
|
||||
);
|
||||
|
||||
validate_finite_vector(
|
||||
state.displacement, "RotationalDisplacementForceLinearizationContext received a "
|
||||
"non-finite displacement value."
|
||||
);
|
||||
|
||||
if (m_isPrepared) {
|
||||
validate_dependency_transition(
|
||||
m_dependencies.discretization, dependencies.discretization,
|
||||
"RotationalDisplacementForceLinearizationContext received "
|
||||
"an older discretization revision for the same identity."
|
||||
);
|
||||
|
||||
validate_dependency_transition(
|
||||
m_dependencies.density, dependencies.density,
|
||||
"RotationalDisplacementForceLinearizationContext received "
|
||||
"an older density revision for the same identity."
|
||||
);
|
||||
|
||||
validate_dependency_transition(
|
||||
m_dependencies.displacement, dependencies.displacement,
|
||||
"RotationalDisplacementForceLinearizationContext received "
|
||||
"an older displacement revision for the same identity."
|
||||
);
|
||||
|
||||
validate_dependency_transition(
|
||||
m_dependencies.rotation, dependencies.rotation,
|
||||
"RotationalDisplacementForceLinearizationContext received "
|
||||
"an older rotation revision for the same identity."
|
||||
);
|
||||
}
|
||||
|
||||
const bool discretizationChanged =
|
||||
!m_isPrepared || dependencies.discretization != m_dependencies.discretization;
|
||||
|
||||
const bool densityChanged = !m_isPrepared || dependencies.density != m_dependencies.density;
|
||||
|
||||
const bool displacementChanged = !m_isPrepared || dependencies.displacement != m_dependencies.displacement;
|
||||
|
||||
const bool rotationChanged = !m_isPrepared || dependencies.rotation != m_dependencies.rotation;
|
||||
|
||||
const bool geometryPreparationRequired = discretizationChanged || displacementChanged;
|
||||
|
||||
const bool rotationPreparationRequired = discretizationChanged || rotationChanged;
|
||||
|
||||
const bool baseStatePreparationRequired =
|
||||
geometryPreparationRequired || rotationPreparationRequired || densityChanged;
|
||||
|
||||
RotationalDisplacementForcePreparationReport report;
|
||||
|
||||
report.preparedStaticDependencies = discretizationChanged;
|
||||
report.preparedGeometryState = geometryPreparationRequired;
|
||||
report.preparedRotationDependencies = rotationPreparationRequired;
|
||||
report.preparedBaseState = baseStatePreparationRequired;
|
||||
|
||||
if (discretizationChanged || densityChanged) {
|
||||
m_baseDensityTrue = state.density;
|
||||
report.updatedDensity = true;
|
||||
}
|
||||
|
||||
if (geometryPreparationRequired) {
|
||||
m_displacementTrue = state.displacement;
|
||||
report.updatedDisplacement = true;
|
||||
}
|
||||
|
||||
if (report.preparedStaticDependencies) {
|
||||
++m_statistics.staticPreparations;
|
||||
}
|
||||
|
||||
if (report.preparedGeometryState) {
|
||||
++m_statistics.geometryPreparations;
|
||||
}
|
||||
|
||||
if (report.preparedRotationDependencies) {
|
||||
++m_statistics.rotationPreparations;
|
||||
}
|
||||
|
||||
if (report.preparedBaseState) {
|
||||
++m_statistics.baseStatePreparations;
|
||||
}
|
||||
|
||||
m_dependencies = dependencies;
|
||||
m_isPrepared = true;
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
bool RotationalDisplacementForceLinearizationContext::IsPrepared() const noexcept {
|
||||
return m_isPrepared;
|
||||
}
|
||||
|
||||
bool RotationalDisplacementForceLinearizationContext::MatchesDependencies(
|
||||
const RotationalDisplacementForceDependencies &dependencies
|
||||
) const noexcept {
|
||||
return m_isPrepared && dependencies == m_dependencies;
|
||||
}
|
||||
|
||||
const RotationalDisplacementForceDependencies &
|
||||
RotationalDisplacementForceLinearizationContext::GetDependencies() const {
|
||||
VerifyPrepared();
|
||||
return m_dependencies;
|
||||
}
|
||||
|
||||
const RotationalDisplacementForcePreparationStatistics &
|
||||
RotationalDisplacementForceLinearizationContext::GetPreparationStatistics() const noexcept {
|
||||
return m_statistics;
|
||||
}
|
||||
|
||||
const mfem::Vector &RotationalDisplacementForceLinearizationContext::GetBaseDensityTrue() const {
|
||||
VerifyPrepared();
|
||||
return m_baseDensityTrue;
|
||||
}
|
||||
|
||||
const mfem::Vector &RotationalDisplacementForceLinearizationContext::GetDisplacementTrue() const {
|
||||
VerifyPrepared();
|
||||
return m_displacementTrue;
|
||||
}
|
||||
|
||||
void RotationalDisplacementForceLinearizationContext::VerifyPrepared() const {
|
||||
MFEM_VERIFY(
|
||||
m_isPrepared, "RotationalDisplacementForceLinearizationContext has not been "
|
||||
"prepared."
|
||||
);
|
||||
}
|
||||
} // namespace mean_field::operators::context::rotational_displacement_force
|
||||
@@ -13,43 +13,31 @@ import :operators.kernels.gravity_field;
|
||||
namespace {
|
||||
using namespace mean_field;
|
||||
int get_state_width(const mfem::Array<int> &state_true_offsets) {
|
||||
MFEM_VERIFY(
|
||||
state_true_offsets.Size() >= 2,
|
||||
"The coupled state requires at least one block."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
state_true_offsets[0] == 0,
|
||||
"The coupled state offsets must begin at zero."
|
||||
);
|
||||
MFEM_VERIFY(state_true_offsets.Size() >= 2, "The coupled state requires at least one block.");
|
||||
MFEM_VERIFY(state_true_offsets[0] == 0, "The coupled state offsets must begin at zero.");
|
||||
|
||||
for (int i = 0; i < state_true_offsets.Size() - 1; ++i) {
|
||||
MFEM_VERIFY(
|
||||
state_true_offsets[i + 1] >= state_true_offsets[i],
|
||||
"The coupled state offsets must be nondecreasing."
|
||||
state_true_offsets[i + 1] >= state_true_offsets[i], "The coupled state offsets must be nondecreasing."
|
||||
);
|
||||
}
|
||||
|
||||
MFEM_VERIFY(
|
||||
state_true_offsets.Last() > 0, "The coupled state cannot be empty."
|
||||
);
|
||||
MFEM_VERIFY(state_true_offsets.Last() > 0, "The coupled state cannot be empty.");
|
||||
return state_true_offsets.Last();
|
||||
}
|
||||
|
||||
int get_gravity_residual_height(const fem::FEM &f) {
|
||||
MFEM_VERIFY(
|
||||
f.gravityFluxFes != nullptr,
|
||||
"GravityFieldOperator requires the gravity-gradient finite-element "
|
||||
"space (RT: Raviart-Thomas)."
|
||||
f.gravityFluxFes != nullptr, "GravityFieldOperator requires the gravity-gradient finite-element "
|
||||
"space (RT: Raviart-Thomas)."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.gravityPotentialFes != nullptr,
|
||||
"GravityFieldOperator requires the gravity-potential "
|
||||
"finite-element "
|
||||
"space (L2: Lebesgue "
|
||||
"space of square-integrable functions)."
|
||||
f.gravityPotentialFes != nullptr, "GravityFieldOperator requires the gravity-potential "
|
||||
"finite-element "
|
||||
"space (L2: Lebesgue "
|
||||
"space of square-integrable functions)."
|
||||
);
|
||||
return f.gravityFluxFes->GetTrueVSize() +
|
||||
f.gravityPotentialFes->GetTrueVSize();
|
||||
return f.gravityFluxFes->GetTrueVSize() + f.gravityPotentialFes->GetTrueVSize();
|
||||
}
|
||||
|
||||
mfem::Array<int> make_gravity_residual_offsets(const fem::FEM &f) {
|
||||
@@ -65,10 +53,7 @@ namespace {
|
||||
const mfem::Array<int> &state_true_offsets,
|
||||
const utils::blocks::value_block<index>
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
index + 1 < state_true_offsets.Size(),
|
||||
"Value block is not present in the state offsets."
|
||||
);
|
||||
MFEM_VERIFY(index + 1 < state_true_offsets.Size(), "Value block is not present in the state offsets.");
|
||||
return state_true_offsets[index + 1] - state_true_offsets[index];
|
||||
}
|
||||
|
||||
@@ -76,10 +61,7 @@ namespace {
|
||||
const fem::FEM &f,
|
||||
const mfem::Array<int> &state_true_offsets
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr,
|
||||
"GravityFieldOperator requires the density finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(f.densityFes != nullptr, "GravityFieldOperator requires the density finite-element space.");
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr, "GravityFieldOperator requires the "
|
||||
"displacement finite-element space."
|
||||
@@ -87,65 +69,44 @@ namespace {
|
||||
|
||||
using form = utils::blocks::gravity_field_form;
|
||||
|
||||
constexpr auto density_block = utils::blocks::get_value_block<form>(
|
||||
utils::blocks::density_field.mass_term
|
||||
);
|
||||
constexpr auto density_block = utils::blocks::get_value_block<form>(utils::blocks::density_field.mass_term);
|
||||
constexpr auto displacement_block =
|
||||
utils::blocks::get_value_block<form>(
|
||||
utils::blocks::displacement_field.geometry_term
|
||||
);
|
||||
utils::blocks::get_value_block<form>(utils::blocks::displacement_field.geometry_term);
|
||||
constexpr auto gravity_gradient_block =
|
||||
utils::blocks::get_value_block<form>(
|
||||
utils::blocks::gravity_field.gradient_term
|
||||
);
|
||||
utils::blocks::get_value_block<form>(utils::blocks::gravity_field.gradient_term);
|
||||
constexpr auto gravity_potential_block =
|
||||
utils::blocks::get_value_block<form>(
|
||||
utils::blocks::gravity_field.poisson_term
|
||||
);
|
||||
utils::blocks::get_value_block<form>(utils::blocks::gravity_field.poisson_term);
|
||||
|
||||
MFEM_VERIFY(
|
||||
state_true_offsets.Size() == form::value_block_count + 1,
|
||||
"The gravity state offsets do not match gravity_field_form."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
get_state_block_size(state_true_offsets, density_block) ==
|
||||
f.densityFes->GetTrueVSize(),
|
||||
get_state_block_size(state_true_offsets, density_block) == f.densityFes->GetTrueVSize(),
|
||||
"The density block does not match the density finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
get_state_block_size(state_true_offsets, displacement_block) ==
|
||||
f.displacementFes->GetTrueVSize(),
|
||||
get_state_block_size(state_true_offsets, displacement_block) == f.displacementFes->GetTrueVSize(),
|
||||
"The displacement block does not match the displacement "
|
||||
"finite-element "
|
||||
"space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
get_state_block_size(state_true_offsets, gravity_gradient_block) ==
|
||||
f.gravityFluxFes->GetTrueVSize(),
|
||||
get_state_block_size(state_true_offsets, gravity_gradient_block) == f.gravityFluxFes->GetTrueVSize(),
|
||||
"The gravity-gradient block does not match the RT finite-element "
|
||||
"space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
get_state_block_size(state_true_offsets, gravity_potential_block) ==
|
||||
f.gravityPotentialFes->GetTrueVSize(),
|
||||
get_state_block_size(state_true_offsets, gravity_potential_block) == f.gravityPotentialFes->GetTrueVSize(),
|
||||
"The gravity-potential block does not match the potential "
|
||||
"finite-element space."
|
||||
);
|
||||
}
|
||||
|
||||
void validate_gravity_context(const fem::FEM &f) {
|
||||
MFEM_VERIFY(
|
||||
f.gravityContext.b_form != nullptr,
|
||||
"GravityFieldOperator requires the divergence operator."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.gravityContext.BT != nullptr,
|
||||
"GravityFieldOperator requires the transpose divergence operator."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr,
|
||||
"GravityFieldOperator requires the quadrature-rule factory."
|
||||
);
|
||||
MFEM_VERIFY(f.gravityContext.b_form != nullptr, "GravityFieldOperator requires the divergence operator.");
|
||||
MFEM_VERIFY(f.gravityContext.BT != nullptr, "GravityFieldOperator requires the transpose divergence operator.");
|
||||
MFEM_VERIFY(f.quadratureFactory != nullptr, "GravityFieldOperator requires the quadrature-rule factory.");
|
||||
}
|
||||
|
||||
template <int index>
|
||||
@@ -154,21 +115,13 @@ namespace {
|
||||
const mfem::Array<int> &offsets,
|
||||
const utils::blocks::value_block<index>
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
index + 1 < offsets.Size(),
|
||||
"Value block is not present in the supplied offset array."
|
||||
);
|
||||
MFEM_VERIFY(index + 1 < offsets.Size(), "Value block is not present in the supplied offset array.");
|
||||
|
||||
const int begin = offsets[index];
|
||||
const int size = offsets[index + 1] - begin;
|
||||
|
||||
MFEM_VERIFY(
|
||||
vector.Size() == offsets.Last(),
|
||||
"Vector size does not match the value-block offsets."
|
||||
);
|
||||
return mfem::Vector(
|
||||
const_cast<mfem::real_t *>(vector.GetData()) + begin, size
|
||||
);
|
||||
MFEM_VERIFY(vector.Size() == offsets.Last(), "Vector size does not match the value-block offsets.");
|
||||
return mfem::Vector(const_cast<mfem::real_t *>(vector.GetData()) + begin, size);
|
||||
}
|
||||
|
||||
template <int index>
|
||||
@@ -181,10 +134,7 @@ namespace {
|
||||
const int begin = offsets[block_id];
|
||||
const int size = offsets[block_id + 1] - begin;
|
||||
|
||||
MFEM_VERIFY(
|
||||
vector.Size() == offsets.Last(),
|
||||
"The vector does not match the residual-block layout."
|
||||
);
|
||||
MFEM_VERIFY(vector.Size() == offsets.Last(), "The vector does not match the residual-block layout.");
|
||||
|
||||
mfem::Vector view;
|
||||
view.MakeRef(const_cast<mfem::Vector &>(vector), begin, size);
|
||||
@@ -197,18 +147,12 @@ namespace {
|
||||
const mfem::Array<int> &offsets,
|
||||
const utils::blocks::residual_block<index>
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
index + 1 < offsets.Size(),
|
||||
"Residual block is not present in the supplied offset array."
|
||||
);
|
||||
MFEM_VERIFY(index + 1 < offsets.Size(), "Residual block is not present in the supplied offset array.");
|
||||
|
||||
const int begin = offsets[index];
|
||||
const int size = offsets[index + 1] - begin;
|
||||
|
||||
MFEM_VERIFY(
|
||||
vector.Size() == offsets.Last(),
|
||||
"Vector size does not match the residual-block offsets."
|
||||
);
|
||||
MFEM_VERIFY(vector.Size() == offsets.Last(), "Vector size does not match the residual-block offsets.");
|
||||
return mfem::Vector(vector.GetData() + begin, size);
|
||||
}
|
||||
} // namespace
|
||||
@@ -217,8 +161,7 @@ namespace mean_field::operators {
|
||||
GravityFieldOperator::GravityFieldOperator(
|
||||
fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domain_mapper,
|
||||
context::gravity_field::GravityFieldLinearizationContext
|
||||
&linearization_context,
|
||||
context::gravity_field::GravityFieldLinearizationContext &linearization_context,
|
||||
const mfem::Array<int> &state_true_offsets,
|
||||
GravityFieldJacobianOperator &jacobian
|
||||
)
|
||||
@@ -238,14 +181,12 @@ namespace mean_field::operators {
|
||||
"displacement finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.smesh.exterior_coordinate != nullptr,
|
||||
"GravityFieldOperator requires the STROID exterior coordinate."
|
||||
f.smesh.exterior_coordinate != nullptr, "GravityFieldOperator requires the STROID exterior coordinate."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.smesh.exterior_coordinate->space != nullptr,
|
||||
"GravityFieldOperator requires the exterior-coordinate "
|
||||
"finite-element "
|
||||
"space."
|
||||
f.smesh.exterior_coordinate->space != nullptr, "GravityFieldOperator requires the exterior-coordinate "
|
||||
"finite-element "
|
||||
"space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.smesh.exterior_coordinate->values != nullptr,
|
||||
@@ -263,67 +204,46 @@ namespace mean_field::operators {
|
||||
bool has_vacuum_domain = false;
|
||||
|
||||
for (int i = 0; i < f.mesh->attributes.Size(); ++i) {
|
||||
if (f.mesh->attributes[i] ==
|
||||
domain_mapper.GetVacuumElementAttribute()) {
|
||||
if (f.mesh->attributes[i] == domain_mapper.GetVacuumElementAttribute()) {
|
||||
has_vacuum_domain = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_VERIFY(has_vacuum_domain, "GravityFieldOperator requires a compactified vacuum domain.");
|
||||
MFEM_VERIFY(
|
||||
has_vacuum_domain,
|
||||
"GravityFieldOperator requires a compactified vacuum domain."
|
||||
m_residual_true_offsets.Last() == Height(), "The gravity residual offsets do not match the operator height."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
m_residual_true_offsets.Last() == Height(),
|
||||
"The gravity residual offsets do not match the operator height."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
m_state_true_offsets.Last() == Width(),
|
||||
"The coupled state offsets do not match the operator width."
|
||||
m_state_true_offsets.Last() == Width(), "The coupled state offsets do not match the operator width."
|
||||
);
|
||||
}
|
||||
|
||||
context::gravity_field::GravityFieldPreparationReport
|
||||
GravityFieldOperator::Prepare(
|
||||
context::gravity_field::GravityFieldPreparationReport GravityFieldOperator::Prepare(
|
||||
const mfem::Vector &state,
|
||||
const context::gravity_field::GravityFieldRevisions &revisions
|
||||
) {
|
||||
using form = utils::blocks::gravity_field_form;
|
||||
|
||||
constexpr auto density_block = utils::blocks::get_value_block<form>(
|
||||
utils::blocks::density_field.mass_term
|
||||
);
|
||||
constexpr auto density_block = utils::blocks::get_value_block<form>(utils::blocks::density_field.mass_term);
|
||||
constexpr auto displacement_block =
|
||||
utils::blocks::get_value_block<form>(
|
||||
utils::blocks::displacement_field.geometry_term
|
||||
);
|
||||
utils::blocks::get_value_block<form>(utils::blocks::displacement_field.geometry_term);
|
||||
constexpr auto gravity_gradient_block =
|
||||
utils::blocks::get_value_block<form>(
|
||||
utils::blocks::gravity_field.gradient_term
|
||||
);
|
||||
utils::blocks::get_value_block<form>(utils::blocks::gravity_field.gradient_term);
|
||||
constexpr auto gravity_potential_block =
|
||||
utils::blocks::get_value_block<form>(
|
||||
utils::blocks::gravity_field.poisson_term
|
||||
);
|
||||
utils::blocks::get_value_block<form>(utils::blocks::gravity_field.poisson_term);
|
||||
|
||||
MFEM_VERIFY(
|
||||
state.Size() == Width(), "GravityFieldOperator received a "
|
||||
"preparation state with the wrong size."
|
||||
);
|
||||
|
||||
const mfem::Vector density = make_read_only_value_view(
|
||||
state, m_state_true_offsets, density_block
|
||||
);
|
||||
const mfem::Vector displacement = make_read_only_value_view(
|
||||
state, m_state_true_offsets, displacement_block
|
||||
);
|
||||
const mfem::Vector gravity_gradient = make_read_only_value_view(
|
||||
state, m_state_true_offsets, gravity_gradient_block
|
||||
);
|
||||
const mfem::Vector gravity_potential = make_read_only_value_view(
|
||||
state, m_state_true_offsets, gravity_potential_block
|
||||
);
|
||||
const mfem::Vector density = make_read_only_value_view(state, m_state_true_offsets, density_block);
|
||||
const mfem::Vector displacement = make_read_only_value_view(state, m_state_true_offsets, displacement_block);
|
||||
const mfem::Vector gravity_gradient =
|
||||
make_read_only_value_view(state, m_state_true_offsets, gravity_gradient_block);
|
||||
const mfem::Vector gravity_potential =
|
||||
make_read_only_value_view(state, m_state_true_offsets, gravity_potential_block);
|
||||
|
||||
return m_linearization_context.Prepare(
|
||||
{.density = density,
|
||||
@@ -334,92 +254,65 @@ namespace mean_field::operators {
|
||||
);
|
||||
}
|
||||
|
||||
const mfem::Array<int> &
|
||||
GravityFieldOperator::GetStateTrueOffsets() const noexcept {
|
||||
const mfem::Array<int> &GravityFieldOperator::GetStateTrueOffsets() const noexcept {
|
||||
return m_state_true_offsets;
|
||||
}
|
||||
|
||||
const mfem::Array<int> &
|
||||
GravityFieldOperator::GetResidualTrueOffsets() const noexcept {
|
||||
const mfem::Array<int> &GravityFieldOperator::GetResidualTrueOffsets() const noexcept {
|
||||
return m_residual_true_offsets;
|
||||
}
|
||||
|
||||
void GravityFieldOperator::ApplyGravityUnknowns(
|
||||
const mfem::Vector &gravity_gradient,
|
||||
const mfem::Vector &gravity_potential,
|
||||
const context::gravity_field::GravityFieldGeometryContext
|
||||
&geometry_context,
|
||||
const context::gravity_field::GravityFieldGeometryContext &geometry_context,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
using form = utils::blocks::gravity_field_form;
|
||||
|
||||
constexpr auto gravity_gradient_residual_block =
|
||||
utils::blocks::get_residual_block<form>(
|
||||
utils::blocks::gravity_field.gradient_term
|
||||
);
|
||||
utils::blocks::get_residual_block<form>(utils::blocks::gravity_field.gradient_term);
|
||||
constexpr auto gravity_poisson_residual_block =
|
||||
utils::blocks::get_residual_block<form>(
|
||||
utils::blocks::gravity_field.poisson_term
|
||||
);
|
||||
utils::blocks::get_residual_block<form>(utils::blocks::gravity_field.poisson_term);
|
||||
|
||||
MFEM_VERIFY(
|
||||
geometry_context.IsPrepared(),
|
||||
"GravityFieldOperator received an unprepared geometry context."
|
||||
);
|
||||
MFEM_VERIFY(geometry_context.IsPrepared(), "GravityFieldOperator received an unprepared geometry context.");
|
||||
MFEM_VERIFY(
|
||||
gravity_gradient.Size() == m_fem.gravityFluxFes->GetTrueVSize(),
|
||||
"GravityFieldOperator received a gravity-gradient vector with the "
|
||||
"wrong size."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
gravity_potential.Size() ==
|
||||
m_fem.gravityPotentialFes->GetTrueVSize(),
|
||||
gravity_potential.Size() == m_fem.gravityPotentialFes->GetTrueVSize(),
|
||||
"GravityFieldOperator received a gravity-potential vector with the "
|
||||
"wrong size."
|
||||
);
|
||||
|
||||
action.SetSize(Height());
|
||||
action = 0.0;
|
||||
action = 0.0;
|
||||
|
||||
mfem::Vector gravity_gradient_action = make_residual_view(
|
||||
action, m_residual_true_offsets, gravity_gradient_residual_block
|
||||
);
|
||||
mfem::Vector gravity_poisson_action = make_residual_view(
|
||||
action, m_residual_true_offsets, gravity_poisson_residual_block
|
||||
);
|
||||
mfem::Vector transpose_divergence_action(
|
||||
gravity_gradient_action.Size()
|
||||
);
|
||||
mfem::Vector gravity_gradient_action =
|
||||
make_residual_view(action, m_residual_true_offsets, gravity_gradient_residual_block);
|
||||
mfem::Vector gravity_poisson_action =
|
||||
make_residual_view(action, m_residual_true_offsets, gravity_poisson_residual_block);
|
||||
mfem::Vector transpose_divergence_action(gravity_gradient_action.Size());
|
||||
|
||||
geometry_context.GetMassOperator().Mult(
|
||||
gravity_gradient, gravity_gradient_action
|
||||
);
|
||||
m_fem.gravityContext.BT->Mult(
|
||||
gravity_potential, transpose_divergence_action
|
||||
);
|
||||
geometry_context.GetMassOperator().Mult(gravity_gradient, gravity_gradient_action);
|
||||
m_fem.gravityContext.BT->Mult(gravity_potential, transpose_divergence_action);
|
||||
gravity_gradient_action += transpose_divergence_action;
|
||||
m_fem.gravityContext.b_form->Mult(
|
||||
gravity_gradient, gravity_poisson_action
|
||||
);
|
||||
m_fem.gravityContext.b_form->Mult(gravity_gradient, gravity_poisson_action);
|
||||
}
|
||||
|
||||
void GravityFieldOperator::ApplyDensitySource(
|
||||
const mfem::Vector &density,
|
||||
const context::gravity_field::GravityFieldGeometryContext
|
||||
&geometry_context,
|
||||
const context::gravity_field::GravityFieldGeometryContext &geometry_context,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
using form = utils::blocks::gravity_field_form;
|
||||
|
||||
constexpr auto gravity_poisson_residual_block =
|
||||
utils::blocks::get_residual_block<form>(
|
||||
utils::blocks::gravity_field.poisson_term
|
||||
);
|
||||
utils::blocks::get_residual_block<form>(utils::blocks::gravity_field.poisson_term);
|
||||
|
||||
MFEM_VERIFY(
|
||||
geometry_context.IsPrepared(),
|
||||
"GravityFieldOperator received an unprepared geometry context."
|
||||
);
|
||||
MFEM_VERIFY(geometry_context.IsPrepared(), "GravityFieldOperator received an unprepared geometry context.");
|
||||
MFEM_VERIFY(
|
||||
density.Size() == m_fem.densityFes->GetTrueVSize(),
|
||||
"GravityFieldOperator received a density vector with the wrong "
|
||||
@@ -427,14 +320,11 @@ namespace mean_field::operators {
|
||||
);
|
||||
|
||||
action.SetSize(Height());
|
||||
action = 0.0;
|
||||
action = 0.0;
|
||||
|
||||
mfem::Vector gravity_poisson_action = make_residual_view(
|
||||
action, m_residual_true_offsets, gravity_poisson_residual_block
|
||||
);
|
||||
geometry_context.GetSourceOperator().Mult(
|
||||
density, gravity_poisson_action
|
||||
);
|
||||
mfem::Vector gravity_poisson_action =
|
||||
make_residual_view(action, m_residual_true_offsets, gravity_poisson_residual_block);
|
||||
geometry_context.GetSourceOperator().Mult(density, gravity_poisson_action);
|
||||
}
|
||||
|
||||
void GravityFieldOperator::Mult(
|
||||
@@ -445,51 +335,34 @@ namespace mean_field::operators {
|
||||
|
||||
using form = utils::blocks::gravity_field_form;
|
||||
|
||||
constexpr auto density_block = utils::blocks::get_value_block<form>(
|
||||
utils::blocks::density_field.mass_term
|
||||
);
|
||||
constexpr auto density_block = utils::blocks::get_value_block<form>(utils::blocks::density_field.mass_term);
|
||||
constexpr auto gravity_gradient_block =
|
||||
utils::blocks::get_value_block<form>(
|
||||
utils::blocks::gravity_field.gradient_term
|
||||
);
|
||||
utils::blocks::get_value_block<form>(utils::blocks::gravity_field.gradient_term);
|
||||
constexpr auto gravity_potential_block =
|
||||
utils::blocks::get_value_block<form>(
|
||||
utils::blocks::gravity_field.poisson_term
|
||||
);
|
||||
utils::blocks::get_value_block<form>(utils::blocks::gravity_field.poisson_term);
|
||||
|
||||
MFEM_VERIFY(state.Size() == Width(), "GravityFieldOperator received a state with the wrong size.");
|
||||
MFEM_VERIFY(
|
||||
state.Size() == Width(),
|
||||
"GravityFieldOperator received a state with the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
m_linearization_context.IsPrepared(),
|
||||
"GravityFieldOperator must be prepared before Mult is called."
|
||||
m_linearization_context.IsPrepared(), "GravityFieldOperator must be prepared before Mult is called."
|
||||
);
|
||||
|
||||
const mfem::Vector density = make_read_only_value_view(
|
||||
state, m_state_true_offsets, density_block
|
||||
);
|
||||
const mfem::Vector gravity_gradient = make_read_only_value_view(
|
||||
state, m_state_true_offsets, gravity_gradient_block
|
||||
);
|
||||
const mfem::Vector gravity_potential = make_read_only_value_view(
|
||||
state, m_state_true_offsets, gravity_potential_block
|
||||
);
|
||||
const context::gravity_field::GravityFieldGeometryContext
|
||||
&geometry_context = m_linearization_context.GetGeometryContext();
|
||||
const mfem::Vector density = make_read_only_value_view(state, m_state_true_offsets, density_block);
|
||||
const mfem::Vector gravity_gradient =
|
||||
make_read_only_value_view(state, m_state_true_offsets, gravity_gradient_block);
|
||||
const mfem::Vector gravity_potential =
|
||||
make_read_only_value_view(state, m_state_true_offsets, gravity_potential_block);
|
||||
const context::gravity_field::GravityFieldGeometryContext &geometry_context =
|
||||
m_linearization_context.GetGeometryContext();
|
||||
|
||||
mfem::Vector source;
|
||||
|
||||
ApplyGravityUnknowns(
|
||||
gravity_gradient, gravity_potential, geometry_context, residual
|
||||
);
|
||||
ApplyGravityUnknowns(gravity_gradient, gravity_potential, geometry_context, residual);
|
||||
ApplyDensitySource(density, geometry_context, source);
|
||||
|
||||
residual -= source;
|
||||
}
|
||||
|
||||
context::gravity_field::GravityFieldLinearizationContext &
|
||||
GravityFieldOperator::GetLinearizationContext() noexcept {
|
||||
context::gravity_field::GravityFieldLinearizationContext &GravityFieldOperator::GetLinearizationContext() noexcept {
|
||||
return m_linearization_context;
|
||||
}
|
||||
|
||||
@@ -498,24 +371,21 @@ namespace mean_field::operators {
|
||||
return m_linearization_context;
|
||||
}
|
||||
|
||||
mfem::Operator &
|
||||
GravityFieldOperator::GetGradient(const mfem::Vector &state) const {
|
||||
mfem::Operator &GravityFieldOperator::GetGradient(const mfem::Vector &state) const {
|
||||
MFEM_VERIFY(
|
||||
state.Size() == Width(), "GravityFieldOperator received a "
|
||||
"linearization state with the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
m_linearization_context.IsPrepared(),
|
||||
"GravityFieldOperator must be prepared before GetGradient is "
|
||||
"called."
|
||||
m_linearization_context.IsPrepared(), "GravityFieldOperator must be prepared before GetGradient is "
|
||||
"called."
|
||||
);
|
||||
|
||||
return m_jacobian;
|
||||
}
|
||||
ReducedGravityFieldOperator::ReducedGravityFieldOperator(
|
||||
GravityFieldOperator &gravity_field_operator,
|
||||
context::gravity_field::GravityFieldGeometryContext
|
||||
&gravity_field_geometry_context,
|
||||
context::gravity_field::GravityFieldGeometryContext &gravity_field_geometry_context,
|
||||
const mfem::Vector &displacement
|
||||
)
|
||||
: Operator(
|
||||
@@ -523,31 +393,20 @@ namespace mean_field::operators {
|
||||
gravity_field_operator.Height()
|
||||
),
|
||||
m_gravity_field_operator(gravity_field_operator),
|
||||
m_gravity_true_offsets(
|
||||
gravity_field_operator.GetResidualTrueOffsets()
|
||||
),
|
||||
m_gravity_true_offsets(gravity_field_operator.GetResidualTrueOffsets()),
|
||||
m_gravity_field_geometry_context(gravity_field_geometry_context) {
|
||||
using form = utils::blocks::gravity_field_form;
|
||||
|
||||
constexpr auto gravity_gradient_block =
|
||||
utils::blocks::get_value_block<form>(
|
||||
utils::blocks::gravity_field.gradient_term
|
||||
);
|
||||
utils::blocks::get_value_block<form>(utils::blocks::gravity_field.gradient_term);
|
||||
constexpr auto gravity_potential_block =
|
||||
utils::blocks::get_value_block<form>(
|
||||
utils::blocks::gravity_field.poisson_term
|
||||
);
|
||||
utils::blocks::get_value_block<form>(utils::blocks::gravity_field.poisson_term);
|
||||
constexpr auto gravity_gradient_residual_block =
|
||||
utils::blocks::get_residual_block<form>(
|
||||
utils::blocks::gravity_field.gradient_term
|
||||
);
|
||||
utils::blocks::get_residual_block<form>(utils::blocks::gravity_field.gradient_term);
|
||||
constexpr auto gravity_poisson_residual_block =
|
||||
utils::blocks::get_residual_block<form>(
|
||||
utils::blocks::gravity_field.poisson_term
|
||||
);
|
||||
utils::blocks::get_residual_block<form>(utils::blocks::gravity_field.poisson_term);
|
||||
|
||||
const mfem::Array<int> &state_offsets =
|
||||
m_gravity_field_operator.GetStateTrueOffsets();
|
||||
const mfem::Array<int> &state_offsets = m_gravity_field_operator.GetStateTrueOffsets();
|
||||
|
||||
MFEM_VERIFY(
|
||||
state_offsets.Size() == form::value_block_count + 1,
|
||||
@@ -558,13 +417,8 @@ namespace mean_field::operators {
|
||||
"ReducedGravityFieldOperator received an invalid gravity-residual "
|
||||
"layout."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
state_offsets[0] == 0, "The full-state offsets must begin at zero."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
m_gravity_true_offsets[0] == 0,
|
||||
"The reduced gravity offsets must begin at zero."
|
||||
);
|
||||
MFEM_VERIFY(state_offsets[0] == 0, "The full-state offsets must begin at zero.");
|
||||
MFEM_VERIFY(m_gravity_true_offsets[0] == 0, "The reduced gravity offsets must begin at zero.");
|
||||
MFEM_VERIFY(
|
||||
state_offsets.Last() == m_gravity_field_operator.Width(),
|
||||
"The full-state offsets do not match the gravity-field operator "
|
||||
@@ -576,23 +430,17 @@ namespace mean_field::operators {
|
||||
"operator "
|
||||
"height."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
Width() == Height(), "ReducedGravityFieldOperator must be square."
|
||||
);
|
||||
MFEM_VERIFY(Width() == Height(), "ReducedGravityFieldOperator must be square.");
|
||||
|
||||
const int full_gradient_size =
|
||||
state_offsets[static_cast<int>(gravity_gradient_block) + 1] -
|
||||
state_offsets[gravity_gradient_block];
|
||||
state_offsets[static_cast<int>(gravity_gradient_block) + 1] - state_offsets[gravity_gradient_block];
|
||||
const int full_potential_size =
|
||||
state_offsets[static_cast<int>(gravity_potential_block) + 1] -
|
||||
state_offsets[gravity_potential_block];
|
||||
state_offsets[static_cast<int>(gravity_potential_block) + 1] - state_offsets[gravity_potential_block];
|
||||
const int reduced_gradient_size =
|
||||
m_gravity_true_offsets
|
||||
[static_cast<int>(gravity_gradient_residual_block) + 1] -
|
||||
m_gravity_true_offsets[static_cast<int>(gravity_gradient_residual_block) + 1] -
|
||||
m_gravity_true_offsets[gravity_gradient_residual_block];
|
||||
const int reduced_potential_size =
|
||||
m_gravity_true_offsets
|
||||
[static_cast<int>(gravity_poisson_residual_block) + 1] -
|
||||
m_gravity_true_offsets[static_cast<int>(gravity_poisson_residual_block) + 1] -
|
||||
m_gravity_true_offsets[gravity_poisson_residual_block];
|
||||
|
||||
MFEM_VERIFY(
|
||||
@@ -609,31 +457,24 @@ namespace mean_field::operators {
|
||||
SetDisplacement(displacement);
|
||||
}
|
||||
|
||||
void ReducedGravityFieldOperator::SetDisplacement(
|
||||
const mfem::Vector &displacement
|
||||
) {
|
||||
void ReducedGravityFieldOperator::SetDisplacement(const mfem::Vector &displacement) {
|
||||
ValidateDisplacement(displacement);
|
||||
|
||||
context::gravity_field::DiscretizationRevision discretization_revision;
|
||||
context::gravity_field::DisplacementRevision displacement_revision;
|
||||
|
||||
if (m_gravity_field_geometry_context.IsPrepared()) {
|
||||
discretization_revision =
|
||||
m_gravity_field_geometry_context.GetDiscretizationRevision();
|
||||
displacement_revision =
|
||||
m_gravity_field_geometry_context.GetDisplacementRevision();
|
||||
discretization_revision = m_gravity_field_geometry_context.GetDiscretizationRevision();
|
||||
displacement_revision = m_gravity_field_geometry_context.GetDisplacementRevision();
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacement_revision.value <
|
||||
std::numeric_limits<std::uint64_t>::max(),
|
||||
displacement_revision.value < std::numeric_limits<std::uint64_t>::max(),
|
||||
"The reduced gravity displacement revision has overflowed."
|
||||
);
|
||||
++displacement_revision.value;
|
||||
}
|
||||
|
||||
m_gravity_field_geometry_context.Prepare(
|
||||
displacement, discretization_revision, displacement_revision
|
||||
);
|
||||
m_gravity_field_geometry_context.Prepare(displacement, discretization_revision, displacement_revision);
|
||||
}
|
||||
|
||||
const mfem::Vector &ReducedGravityFieldOperator::GetDisplacement() const {
|
||||
@@ -646,15 +487,12 @@ namespace mean_field::operators {
|
||||
) const {
|
||||
ValidateDensity(density);
|
||||
|
||||
m_gravity_field_operator.ApplyDensitySource(
|
||||
density, m_gravity_field_geometry_context, right_hand_side
|
||||
);
|
||||
m_gravity_field_operator.ApplyDensitySource(density, m_gravity_field_geometry_context, right_hand_side);
|
||||
|
||||
MFEM_VERIFY(
|
||||
right_hand_side.Size() == Height(),
|
||||
"ReducedGravityFieldOperator produced a right-hand side with the "
|
||||
"wrong "
|
||||
"size."
|
||||
right_hand_side.Size() == Height(), "ReducedGravityFieldOperator produced a right-hand side with the "
|
||||
"wrong "
|
||||
"size."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -667,29 +505,19 @@ namespace mean_field::operators {
|
||||
using form = utils::blocks::gravity_field_form;
|
||||
|
||||
constexpr auto gravity_gradient_residual_block =
|
||||
utils::blocks::get_residual_block<form>(
|
||||
utils::blocks::gravity_field.gradient_term
|
||||
);
|
||||
utils::blocks::get_residual_block<form>(utils::blocks::gravity_field.gradient_term);
|
||||
constexpr auto gravity_poisson_residual_block =
|
||||
utils::blocks::get_residual_block<form>(
|
||||
utils::blocks::gravity_field.poisson_term
|
||||
);
|
||||
utils::blocks::get_residual_block<form>(utils::blocks::gravity_field.poisson_term);
|
||||
|
||||
ValidateGravityState(gravity_state);
|
||||
|
||||
const mfem::Vector gravity_gradient_true = make_read_only_residual_view(
|
||||
gravity_state, m_gravity_true_offsets,
|
||||
gravity_gradient_residual_block
|
||||
);
|
||||
const mfem::Vector gravity_gradient_true =
|
||||
make_read_only_residual_view(gravity_state, m_gravity_true_offsets, gravity_gradient_residual_block);
|
||||
const mfem::Vector gravity_potential_true =
|
||||
make_read_only_residual_view(
|
||||
gravity_state, m_gravity_true_offsets,
|
||||
gravity_poisson_residual_block
|
||||
);
|
||||
make_read_only_residual_view(gravity_state, m_gravity_true_offsets, gravity_poisson_residual_block);
|
||||
|
||||
m_gravity_field_operator.ApplyGravityUnknowns(
|
||||
gravity_gradient_true, gravity_potential_true,
|
||||
m_gravity_field_geometry_context, action
|
||||
gravity_gradient_true, gravity_potential_true, m_gravity_field_geometry_context, action
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
@@ -698,18 +526,15 @@ namespace mean_field::operators {
|
||||
);
|
||||
}
|
||||
|
||||
GravityFieldOperator &
|
||||
ReducedGravityFieldOperator::GetGravityFieldOperator() noexcept {
|
||||
GravityFieldOperator &ReducedGravityFieldOperator::GetGravityFieldOperator() noexcept {
|
||||
return m_gravity_field_operator;
|
||||
}
|
||||
|
||||
const GravityFieldOperator &
|
||||
ReducedGravityFieldOperator::GetGravityFieldOperator() const noexcept {
|
||||
const GravityFieldOperator &ReducedGravityFieldOperator::GetGravityFieldOperator() const noexcept {
|
||||
return m_gravity_field_operator;
|
||||
}
|
||||
|
||||
context::gravity_field::GravityFieldGeometryContext &
|
||||
ReducedGravityFieldOperator::GetGeometryContext() noexcept {
|
||||
context::gravity_field::GravityFieldGeometryContext &ReducedGravityFieldOperator::GetGeometryContext() noexcept {
|
||||
return m_gravity_field_geometry_context;
|
||||
}
|
||||
|
||||
@@ -718,73 +543,53 @@ namespace mean_field::operators {
|
||||
return m_gravity_field_geometry_context;
|
||||
}
|
||||
|
||||
const mfem::Array<int> &
|
||||
ReducedGravityFieldOperator::GetGravityTrueOffsets() const noexcept {
|
||||
const mfem::Array<int> &ReducedGravityFieldOperator::GetGravityTrueOffsets() const noexcept {
|
||||
return m_gravity_true_offsets;
|
||||
}
|
||||
|
||||
void ReducedGravityFieldOperator::ValidateDisplacement(
|
||||
const mfem::Vector &displacement
|
||||
) const {
|
||||
void ReducedGravityFieldOperator::ValidateDisplacement(const mfem::Vector &displacement) const {
|
||||
using form = utils::blocks::gravity_field_form;
|
||||
|
||||
constexpr auto displacement_block =
|
||||
utils::blocks::get_value_block<form>(
|
||||
utils::blocks::displacement_field.geometry_term
|
||||
);
|
||||
utils::blocks::get_value_block<form>(utils::blocks::displacement_field.geometry_term);
|
||||
|
||||
const mfem::Array<int> &state_offsets =
|
||||
m_gravity_field_operator.GetStateTrueOffsets();
|
||||
const mfem::Array<int> &state_offsets = m_gravity_field_operator.GetStateTrueOffsets();
|
||||
const int expected_size =
|
||||
state_offsets[static_cast<int>(displacement_block) + 1] -
|
||||
state_offsets[displacement_block];
|
||||
state_offsets[static_cast<int>(displacement_block) + 1] - state_offsets[displacement_block];
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacement.Size() == expected_size,
|
||||
"ReducedGravityFieldOperator received a displacement with the "
|
||||
"wrong "
|
||||
"size."
|
||||
displacement.Size() == expected_size, "ReducedGravityFieldOperator received a displacement with the "
|
||||
"wrong "
|
||||
"size."
|
||||
);
|
||||
|
||||
for (int i = 0; i < displacement.Size(); ++i) {
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(displacement(i)),
|
||||
"ReducedGravityFieldOperator received a non-finite "
|
||||
"displacement "
|
||||
"value."
|
||||
std::isfinite(displacement(i)), "ReducedGravityFieldOperator received a non-finite "
|
||||
"displacement "
|
||||
"value."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void ReducedGravityFieldOperator::ValidateDensity(
|
||||
const mfem::Vector &density
|
||||
) const {
|
||||
void ReducedGravityFieldOperator::ValidateDensity(const mfem::Vector &density) const {
|
||||
using form = utils::blocks::gravity_field_form;
|
||||
|
||||
constexpr auto density_block = utils::blocks::get_value_block<form>(
|
||||
utils::blocks::density_field.mass_term
|
||||
);
|
||||
constexpr auto density_block = utils::blocks::get_value_block<form>(utils::blocks::density_field.mass_term);
|
||||
|
||||
const mfem::Array<int> &state_offsets =
|
||||
m_gravity_field_operator.GetStateTrueOffsets();
|
||||
const int expected_size =
|
||||
state_offsets[static_cast<int>(density_block) + 1] -
|
||||
state_offsets[density_block];
|
||||
const mfem::Array<int> &state_offsets = m_gravity_field_operator.GetStateTrueOffsets();
|
||||
const int expected_size = state_offsets[static_cast<int>(density_block) + 1] - state_offsets[density_block];
|
||||
|
||||
MFEM_VERIFY(
|
||||
density.Size() == expected_size,
|
||||
"ReducedGravityFieldOperator received a density with the wrong "
|
||||
"size."
|
||||
density.Size() == expected_size, "ReducedGravityFieldOperator received a density with the wrong "
|
||||
"size."
|
||||
);
|
||||
}
|
||||
|
||||
void ReducedGravityFieldOperator::ValidateGravityState(
|
||||
const mfem::Vector &gravity_state
|
||||
) const {
|
||||
void ReducedGravityFieldOperator::ValidateGravityState(const mfem::Vector &gravity_state) const {
|
||||
MFEM_VERIFY(
|
||||
gravity_state.Size() == Width(),
|
||||
"ReducedGravityFieldOperator received "
|
||||
"a gravity state with the wrong size."
|
||||
gravity_state.Size() == Width(), "ReducedGravityFieldOperator received "
|
||||
"a gravity state with the wrong size."
|
||||
);
|
||||
}
|
||||
} // namespace mean_field::operators
|
||||
|
||||
@@ -15,9 +15,7 @@ namespace {
|
||||
) {
|
||||
const int offset = offsets[index];
|
||||
const int size = offsets[index + 1] - offset;
|
||||
return mfem::Vector(
|
||||
const_cast<mfem::real_t *>(vector.GetData()) + offset, size
|
||||
);
|
||||
return mfem::Vector(const_cast<mfem::real_t *>(vector.GetData()) + offset, size);
|
||||
}
|
||||
|
||||
template <int index>
|
||||
@@ -56,10 +54,7 @@ namespace {
|
||||
MFEM_VERIFY(offsets[0] == 0, "Block offsets must begin at zero.");
|
||||
|
||||
for (int i = 0; i < block_count; ++i)
|
||||
MFEM_VERIFY(
|
||||
offsets[i + 1] >= offsets[i],
|
||||
"Block offsets must be nondecreasing."
|
||||
);
|
||||
MFEM_VERIFY(offsets[i + 1] >= offsets[i], "Block offsets must be nondecreasing.");
|
||||
}
|
||||
|
||||
void validate_layout(
|
||||
@@ -70,29 +65,18 @@ namespace {
|
||||
using form = mean_field::utils::blocks::gravity_field_form;
|
||||
|
||||
constexpr auto density_block =
|
||||
mean_field::utils::blocks::get_value_block<form>(
|
||||
mean_field::utils::blocks::density_field.mass_term
|
||||
);
|
||||
constexpr auto displacement_block =
|
||||
mean_field::utils::blocks::get_value_block<form>(
|
||||
mean_field::utils::blocks::displacement_field.geometry_term
|
||||
);
|
||||
mean_field::utils::blocks::get_value_block<form>(mean_field::utils::blocks::density_field.mass_term);
|
||||
constexpr auto displacement_block = mean_field::utils::blocks::get_value_block<form>(
|
||||
mean_field::utils::blocks::displacement_field.geometry_term
|
||||
);
|
||||
constexpr auto gravity_gradient_block =
|
||||
mean_field::utils::blocks::get_value_block<form>(
|
||||
mean_field::utils::blocks::gravity_field.gradient_term
|
||||
);
|
||||
mean_field::utils::blocks::get_value_block<form>(mean_field::utils::blocks::gravity_field.gradient_term);
|
||||
constexpr auto gravity_potential_block =
|
||||
mean_field::utils::blocks::get_value_block<form>(
|
||||
mean_field::utils::blocks::gravity_field.poisson_term
|
||||
);
|
||||
mean_field::utils::blocks::get_value_block<form>(mean_field::utils::blocks::gravity_field.poisson_term);
|
||||
constexpr auto gravity_gradient_residual_block =
|
||||
mean_field::utils::blocks::get_residual_block<form>(
|
||||
mean_field::utils::blocks::gravity_field.gradient_term
|
||||
);
|
||||
mean_field::utils::blocks::get_residual_block<form>(mean_field::utils::blocks::gravity_field.gradient_term);
|
||||
constexpr auto gravity_poisson_residual_block =
|
||||
mean_field::utils::blocks::get_residual_block<form>(
|
||||
mean_field::utils::blocks::gravity_field.poisson_term
|
||||
);
|
||||
mean_field::utils::blocks::get_residual_block<form>(mean_field::utils::blocks::gravity_field.poisson_term);
|
||||
|
||||
validate_offsets(
|
||||
state_offsets, form::value_block_count,
|
||||
@@ -106,33 +90,27 @@ namespace {
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
get_block_size(state_offsets, density_block) ==
|
||||
f.densityFes->GetTrueVSize(),
|
||||
get_block_size(state_offsets, density_block) == f.densityFes->GetTrueVSize(),
|
||||
"The Jacobian density block has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
get_block_size(state_offsets, displacement_block) ==
|
||||
f.displacementFes->GetTrueVSize(),
|
||||
get_block_size(state_offsets, displacement_block) == f.displacementFes->GetTrueVSize(),
|
||||
"The Jacobian displacement block has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
get_block_size(state_offsets, gravity_gradient_block) ==
|
||||
f.gravityFluxFes->GetTrueVSize(),
|
||||
get_block_size(state_offsets, gravity_gradient_block) == f.gravityFluxFes->GetTrueVSize(),
|
||||
"The Jacobian gravity-gradient block has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
get_block_size(state_offsets, gravity_potential_block) ==
|
||||
f.gravityPotentialFes->GetTrueVSize(),
|
||||
get_block_size(state_offsets, gravity_potential_block) == f.gravityPotentialFes->GetTrueVSize(),
|
||||
"The Jacobian gravity-potential block has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
get_block_size(residual_offsets, gravity_gradient_residual_block) ==
|
||||
f.gravityFluxFes->GetTrueVSize(),
|
||||
get_block_size(residual_offsets, gravity_gradient_residual_block) == f.gravityFluxFes->GetTrueVSize(),
|
||||
"The Jacobian gradient-residual block has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
get_block_size(residual_offsets, gravity_poisson_residual_block) ==
|
||||
f.gravityPotentialFes->GetTrueVSize(),
|
||||
get_block_size(residual_offsets, gravity_poisson_residual_block) == f.gravityPotentialFes->GetTrueVSize(),
|
||||
"The Jacobian Poisson-residual block has the wrong size."
|
||||
);
|
||||
}
|
||||
@@ -142,8 +120,7 @@ namespace mean_field::operators {
|
||||
GravityFieldJacobianOperator::GravityFieldJacobianOperator(
|
||||
fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domain_mapper,
|
||||
const context::gravity_field::GravityFieldLinearizationContext
|
||||
&linearization_context,
|
||||
const context::gravity_field::GravityFieldLinearizationContext &linearization_context,
|
||||
const mfem::Array<int> &state_true_offsets,
|
||||
const mfem::Array<int> &residual_true_offsets
|
||||
)
|
||||
@@ -157,37 +134,30 @@ namespace mean_field::operators {
|
||||
m_state_true_offsets(state_true_offsets),
|
||||
m_residual_true_offsets(residual_true_offsets) {
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr,
|
||||
"GravityFieldJacobianOperator requires the density finite-element "
|
||||
"space."
|
||||
f.densityFes != nullptr, "GravityFieldJacobianOperator requires the density finite-element "
|
||||
"space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.gravityPotentialFes != nullptr,
|
||||
"GravityFieldJacobianOperator requires the gravity-potential "
|
||||
"finite-element space."
|
||||
f.gravityPotentialFes != nullptr, "GravityFieldJacobianOperator requires the gravity-potential "
|
||||
"finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.gravityFluxFes != nullptr,
|
||||
"GravityFieldJacobianOperator requires the "
|
||||
"gravity-gradient finite-element space."
|
||||
f.gravityFluxFes != nullptr, "GravityFieldJacobianOperator requires the "
|
||||
"gravity-gradient finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr,
|
||||
"GravityFieldJacobianOperator requires the "
|
||||
"displacement finite-element space."
|
||||
f.displacementFes != nullptr, "GravityFieldJacobianOperator requires the "
|
||||
"displacement finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.gravityContext.b_form != nullptr,
|
||||
"GravityFieldJacobianOperator requires the divergence operator."
|
||||
f.gravityContext.b_form != nullptr, "GravityFieldJacobianOperator requires the divergence operator."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.gravityContext.BT != nullptr,
|
||||
"GravityFieldJacobianOperator requires the transpose divergence "
|
||||
"operator."
|
||||
f.gravityContext.BT != nullptr, "GravityFieldJacobianOperator requires the transpose divergence "
|
||||
"operator."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr,
|
||||
"GravityFieldJacobianOperator requires the quadrature-rule factory."
|
||||
f.quadratureFactory != nullptr, "GravityFieldJacobianOperator requires the quadrature-rule factory."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
domain_mapper.GetDimension() == f.mesh->Dimension(),
|
||||
@@ -204,107 +174,74 @@ namespace mean_field::operators {
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
MFEM_VERIFY(
|
||||
m_linearization_context.IsPrepared(),
|
||||
"GravityFieldJacobianOperator requires a prepared linearization "
|
||||
"context."
|
||||
m_linearization_context.IsPrepared(), "GravityFieldJacobianOperator requires a prepared linearization "
|
||||
"context."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
direction.Size() == Width(),
|
||||
"GravityFieldJacobianOperator received a direction with the wrong "
|
||||
"size."
|
||||
direction.Size() == Width(), "GravityFieldJacobianOperator received a direction with the wrong "
|
||||
"size."
|
||||
);
|
||||
|
||||
using form = utils::blocks::gravity_field_form;
|
||||
|
||||
constexpr auto density_block = utils::blocks::get_value_block<form>(
|
||||
utils::blocks::density_field.mass_term
|
||||
);
|
||||
constexpr auto density_block = utils::blocks::get_value_block<form>(utils::blocks::density_field.mass_term);
|
||||
constexpr auto displacement_block =
|
||||
utils::blocks::get_value_block<form>(
|
||||
utils::blocks::displacement_field.geometry_term
|
||||
);
|
||||
utils::blocks::get_value_block<form>(utils::blocks::displacement_field.geometry_term);
|
||||
constexpr auto gravity_gradient_block =
|
||||
utils::blocks::get_value_block<form>(
|
||||
utils::blocks::gravity_field.gradient_term
|
||||
);
|
||||
utils::blocks::get_value_block<form>(utils::blocks::gravity_field.gradient_term);
|
||||
constexpr auto gravity_potential_block =
|
||||
utils::blocks::get_value_block<form>(
|
||||
utils::blocks::gravity_field.poisson_term
|
||||
);
|
||||
utils::blocks::get_value_block<form>(utils::blocks::gravity_field.poisson_term);
|
||||
constexpr auto gravity_gradient_residual_block =
|
||||
utils::blocks::get_residual_block<form>(
|
||||
utils::blocks::gravity_field.gradient_term
|
||||
);
|
||||
utils::blocks::get_residual_block<form>(utils::blocks::gravity_field.gradient_term);
|
||||
constexpr auto gravity_poisson_residual_block =
|
||||
utils::blocks::get_residual_block<form>(
|
||||
utils::blocks::gravity_field.poisson_term
|
||||
);
|
||||
utils::blocks::get_residual_block<form>(utils::blocks::gravity_field.poisson_term);
|
||||
|
||||
const context::gravity_field::GravityFieldGeometryContext
|
||||
&geometry_context = m_linearization_context.GetGeometryContext();
|
||||
const mfem::Vector &density = m_linearization_context.GetDensity();
|
||||
const mfem::Vector &displacement = geometry_context.GetDisplacement();
|
||||
const mfem::Vector &gravity_gradient =
|
||||
m_linearization_context.GetGravityGradient();
|
||||
const context::gravity_field::GravityFieldGeometryContext &geometry_context =
|
||||
m_linearization_context.GetGeometryContext();
|
||||
const mfem::Vector &density = m_linearization_context.GetDensity();
|
||||
const mfem::Vector &displacement = geometry_context.GetDisplacement();
|
||||
const mfem::Vector &gravity_gradient = m_linearization_context.GetGravityGradient();
|
||||
|
||||
const mfem::Vector density_direction = make_read_only_value_view(
|
||||
direction, m_state_true_offsets, density_block
|
||||
);
|
||||
const mfem::Vector displacement_direction = make_read_only_value_view(
|
||||
direction, m_state_true_offsets, displacement_block
|
||||
);
|
||||
const mfem::Vector density_direction =
|
||||
make_read_only_value_view(direction, m_state_true_offsets, density_block);
|
||||
const mfem::Vector displacement_direction =
|
||||
make_read_only_value_view(direction, m_state_true_offsets, displacement_block);
|
||||
const mfem::Vector gravity_gradient_direction =
|
||||
make_read_only_value_view(
|
||||
direction, m_state_true_offsets, gravity_gradient_block
|
||||
);
|
||||
make_read_only_value_view(direction, m_state_true_offsets, gravity_gradient_block);
|
||||
const mfem::Vector gravity_potential_direction =
|
||||
make_read_only_value_view(
|
||||
direction, m_state_true_offsets, gravity_potential_block
|
||||
);
|
||||
make_read_only_value_view(direction, m_state_true_offsets, gravity_potential_block);
|
||||
|
||||
action.SetSize(Height());
|
||||
action = 0.0;
|
||||
action = 0.0;
|
||||
|
||||
mfem::Vector gravity_gradient_action = make_residual_view(
|
||||
action, m_residual_true_offsets, gravity_gradient_residual_block
|
||||
);
|
||||
mfem::Vector gravity_poisson_action = make_residual_view(
|
||||
action, m_residual_true_offsets, gravity_poisson_residual_block
|
||||
);
|
||||
mfem::Vector gravity_gradient_action =
|
||||
make_residual_view(action, m_residual_true_offsets, gravity_gradient_residual_block);
|
||||
mfem::Vector gravity_poisson_action =
|
||||
make_residual_view(action, m_residual_true_offsets, gravity_poisson_residual_block);
|
||||
|
||||
mfem::Vector transpose_divergence_action;
|
||||
mfem::Vector source_action;
|
||||
mfem::Vector mass_variation_action;
|
||||
mfem::Vector source_variation_action;
|
||||
|
||||
geometry_context.GetMassOperator().Mult(
|
||||
gravity_gradient_direction, gravity_gradient_action
|
||||
);
|
||||
geometry_context.GetSourceOperator().Mult(
|
||||
density_direction, source_action
|
||||
);
|
||||
geometry_context.GetMassOperator().Mult(gravity_gradient_direction, gravity_gradient_action);
|
||||
geometry_context.GetSourceOperator().Mult(density_direction, source_action);
|
||||
|
||||
kernels::apply_mapped_hdiv_mass_variation(
|
||||
m_fem, m_domain_mapper, gravity_gradient, displacement,
|
||||
displacement_direction, mass_variation_action
|
||||
m_fem, m_domain_mapper, gravity_gradient, displacement, displacement_direction, mass_variation_action
|
||||
);
|
||||
|
||||
kernels::apply_mapped_source_variation(
|
||||
m_fem, m_domain_mapper, density, displacement,
|
||||
displacement_direction, source_variation_action
|
||||
m_fem, m_domain_mapper, density, displacement, displacement_direction, source_variation_action
|
||||
);
|
||||
|
||||
transpose_divergence_action.SetSize(gravity_gradient_action.Size());
|
||||
m_fem.gravityContext.BT->Mult(
|
||||
gravity_potential_direction, transpose_divergence_action
|
||||
);
|
||||
m_fem.gravityContext.BT->Mult(gravity_potential_direction, transpose_divergence_action);
|
||||
|
||||
gravity_gradient_action += transpose_divergence_action;
|
||||
gravity_gradient_action += mass_variation_action;
|
||||
|
||||
m_fem.gravityContext.b_form->Mult(
|
||||
gravity_gradient_direction, gravity_poisson_action
|
||||
);
|
||||
m_fem.gravityContext.b_form->Mult(gravity_gradient_direction, gravity_poisson_action);
|
||||
|
||||
gravity_poisson_action -= source_action;
|
||||
gravity_poisson_action -= source_variation_action;
|
||||
|
||||
@@ -8,24 +8,29 @@ module;
|
||||
module mean_field;
|
||||
|
||||
import :operators.kernels.barotropic_closure;
|
||||
import :field.registry;
|
||||
import :utils.domain;
|
||||
|
||||
namespace {
|
||||
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||
using ClosureDomain = mean_field::field::FieldDomainT<mean_field::field::Density>;
|
||||
|
||||
enum class ClosureAction { residual, density, enthalpy };
|
||||
|
||||
[[nodiscard]] bool element_is_in_closure_support(const int attribute) {
|
||||
return DomainSchema::template attribute_belongs_to<ClosureDomain>(attribute);
|
||||
}
|
||||
|
||||
void true_to_local(
|
||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||
const mfem::Vector &trueVector,
|
||||
mfem::Vector &localVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
trueVector.Size() == finiteElementSpace.GetTrueVSize(),
|
||||
"True vector has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(trueVector.Size() == finiteElementSpace.GetTrueVSize(), "True vector has the wrong size.");
|
||||
|
||||
localVector.SetSize(finiteElementSpace.GetVSize());
|
||||
|
||||
const mfem::Operator *prolongation =
|
||||
finiteElementSpace.GetProlongationMatrix();
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->Mult(trueVector, localVector);
|
||||
@@ -39,16 +44,12 @@ namespace {
|
||||
const mfem::Vector &localVector,
|
||||
mfem::Vector &trueVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
localVector.Size() == finiteElementSpace.GetVSize(),
|
||||
"Local vector has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(localVector.Size() == finiteElementSpace.GetVSize(), "Local vector has the wrong size.");
|
||||
|
||||
trueVector.SetSize(finiteElementSpace.GetTrueVSize());
|
||||
trueVector = 0.0;
|
||||
trueVector = 0.0;
|
||||
|
||||
const mfem::Operator *prolongation =
|
||||
finiteElementSpace.GetProlongationMatrix();
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->MultTranspose(localVector, trueVector);
|
||||
@@ -57,19 +58,13 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
int get_eos_extra_order(
|
||||
const mean_field::physics::PolytropicBarotrope &barotrope
|
||||
) {
|
||||
const double extraOrder =
|
||||
(barotrope.polytropic_index() - 1.0) *
|
||||
static_cast<double>(
|
||||
mean_field::field::Enthalpy::Scalar::familyOrder
|
||||
);
|
||||
int get_eos_extra_order(const mean_field::eos::Polytrope &barotrope) {
|
||||
const double extraOrder = (barotrope.polytropic_index() - 1.0) *
|
||||
static_cast<double>(mean_field::field::Enthalpy::Scalar::familyOrder);
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(extraOrder) && extraOrder >= 0.0 &&
|
||||
extraOrder <=
|
||||
static_cast<double>(std::numeric_limits<int>::max()),
|
||||
extraOrder <= static_cast<double>(std::numeric_limits<int>::max()),
|
||||
"The EOS effective polynomial order is invalid."
|
||||
);
|
||||
|
||||
@@ -78,44 +73,37 @@ namespace {
|
||||
|
||||
const mfem::IntegrationRule &get_eos_rule(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::physics::PolytropicBarotrope &barotrope,
|
||||
const mean_field::eos::Polytrope &barotrope,
|
||||
const mfem::FiniteElement &densityElement,
|
||||
const mfem::FiniteElement &enthalpyElement,
|
||||
const mfem::ElementTransformation &transformation
|
||||
) {
|
||||
using EnthalpyField =
|
||||
mean_field::field::Field<mean_field::field::Enthalpy>;
|
||||
using EnthalpyField = mean_field::field::Field<mean_field::field::Enthalpy>;
|
||||
|
||||
MFEM_VERIFY(
|
||||
densityElement.GetOrder() ==
|
||||
mean_field::field::Density::Scalar::familyOrder,
|
||||
densityElement.GetOrder() == mean_field::field::Density::Scalar::familyOrder,
|
||||
"The EOS test element does not match the "
|
||||
"registered density field."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
enthalpyElement.GetOrder() ==
|
||||
mean_field::field::Enthalpy::Scalar::familyOrder,
|
||||
enthalpyElement.GetOrder() == mean_field::field::Enthalpy::Scalar::familyOrder,
|
||||
"The EOS trial element does not match the "
|
||||
"registered enthalpy field."
|
||||
);
|
||||
|
||||
const mean_field::quadrature::Query query = EnthalpyField::make_query<
|
||||
mean_field::field::Enthalpy::Form::EosClosureSource>(
|
||||
mean_field::quadrature::QuadratureRole::discretization,
|
||||
transformation.OrderW(),
|
||||
std::array<int, 1>{get_eos_extra_order(barotrope)},
|
||||
mean_field::utils::DOMAINS::STELLAR,
|
||||
mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
const mean_field::quadrature::Query query =
|
||||
EnthalpyField::make_query<mean_field::field::Enthalpy::Form::EosClosureSource>(
|
||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(),
|
||||
std::array<int, 1>{get_eos_extra_order(barotrope)}, mean_field::utils::DOMAINS::STELLAR,
|
||||
mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
|
||||
const auto resolution =
|
||||
f.quadratureFactory->get(query, transformation.GetGeometryType());
|
||||
const auto resolution = f.quadratureFactory->get(query, transformation.GetGeometryType());
|
||||
|
||||
MFEM_VERIFY(
|
||||
resolution.integration_rule != nullptr,
|
||||
"The quadrature policy did not return an "
|
||||
"EOS-closure integration rule."
|
||||
resolution.integration_rule != nullptr, "The quadrature policy did not return an "
|
||||
"EOS-closure integration rule."
|
||||
);
|
||||
|
||||
return *resolution.integration_rule;
|
||||
@@ -126,54 +114,44 @@ namespace {
|
||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
||||
const mfem::Vector &displacementTrue
|
||||
) {
|
||||
MFEM_VERIFY(f.mesh != nullptr, "The EOS closure kernel requires a mesh.");
|
||||
MFEM_VERIFY(
|
||||
f.mesh != nullptr, "The EOS closure kernel requires a mesh."
|
||||
f.densityFes != nullptr, "The EOS closure kernel requires the density "
|
||||
"finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr,
|
||||
"The EOS closure kernel requires the density "
|
||||
"finite-element space."
|
||||
f.enthalpyFes != nullptr, "The EOS closure kernel requires the enthalpy "
|
||||
"finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.enthalpyFes != nullptr,
|
||||
"The EOS closure kernel requires the enthalpy "
|
||||
"finite-element space."
|
||||
f.displacementFes != nullptr, "The EOS closure kernel requires the displacement "
|
||||
"finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr,
|
||||
"The EOS closure kernel requires the displacement "
|
||||
"finite-element space."
|
||||
f.compactificationFes != nullptr, "The EOS closure kernel requires the "
|
||||
"compactification finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.compactificationFes != nullptr,
|
||||
"The EOS closure kernel requires the "
|
||||
"compactification finite-element space."
|
||||
f.compactificationCoordinate != nullptr, "The EOS closure kernel requires the "
|
||||
"compactification coordinate."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.compactificationCoordinate != nullptr,
|
||||
"The EOS closure kernel requires the "
|
||||
"compactification coordinate."
|
||||
f.quadratureFactory != nullptr, "The EOS closure kernel requires the quadrature "
|
||||
"rule factory."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr,
|
||||
"The EOS closure kernel requires the quadrature "
|
||||
"rule factory."
|
||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(), "The displacement vector has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The displacement vector has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
domainMapper.GetDimension() == f.mesh->Dimension(),
|
||||
"The domain-mapper dimension does not match "
|
||||
"the mesh dimension."
|
||||
domainMapper.GetDimension() == f.mesh->Dimension(), "The domain-mapper dimension does not match "
|
||||
"the mesh dimension."
|
||||
);
|
||||
}
|
||||
|
||||
void apply_closure_action(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
||||
const mean_field::physics::PolytropicBarotrope &barotrope,
|
||||
const mean_field::eos::Polytrope &barotrope,
|
||||
const ClosureAction closureAction,
|
||||
const mfem::Vector *densityInputTrue,
|
||||
const mfem::Vector *baseEnthalpyTrue,
|
||||
@@ -183,29 +161,23 @@ namespace {
|
||||
) {
|
||||
validate_common_inputs(f, domainMapper, displacementTrue);
|
||||
|
||||
if (closureAction == ClosureAction::residual ||
|
||||
closureAction == ClosureAction::density) {
|
||||
if (closureAction == ClosureAction::residual || closureAction == ClosureAction::density) {
|
||||
MFEM_VERIFY(
|
||||
densityInputTrue != nullptr &&
|
||||
densityInputTrue->Size() == f.densityFes->GetTrueVSize(),
|
||||
densityInputTrue != nullptr && densityInputTrue->Size() == f.densityFes->GetTrueVSize(),
|
||||
"The density input has the wrong size."
|
||||
);
|
||||
}
|
||||
|
||||
if (closureAction == ClosureAction::residual ||
|
||||
closureAction == ClosureAction::enthalpy) {
|
||||
if (closureAction == ClosureAction::residual || closureAction == ClosureAction::enthalpy) {
|
||||
MFEM_VERIFY(
|
||||
baseEnthalpyTrue != nullptr &&
|
||||
baseEnthalpyTrue->Size() == f.enthalpyFes->GetTrueVSize(),
|
||||
baseEnthalpyTrue != nullptr && baseEnthalpyTrue->Size() == f.enthalpyFes->GetTrueVSize(),
|
||||
"The base enthalpy has the wrong size."
|
||||
);
|
||||
}
|
||||
|
||||
if (closureAction == ClosureAction::enthalpy) {
|
||||
MFEM_VERIFY(
|
||||
enthalpyVariationTrue != nullptr &&
|
||||
enthalpyVariationTrue->Size() ==
|
||||
f.enthalpyFes->GetTrueVSize(),
|
||||
enthalpyVariationTrue != nullptr && enthalpyVariationTrue->Size() == f.enthalpyFes->GetTrueVSize(),
|
||||
"The enthalpy variation has the wrong size."
|
||||
);
|
||||
}
|
||||
@@ -224,9 +196,7 @@ namespace {
|
||||
}
|
||||
|
||||
if (enthalpyVariationTrue != nullptr) {
|
||||
true_to_local(
|
||||
*f.enthalpyFes, *enthalpyVariationTrue, enthalpyVariationLocal
|
||||
);
|
||||
true_to_local(*f.enthalpyFes, *enthalpyVariationTrue, enthalpyVariationLocal);
|
||||
}
|
||||
|
||||
true_to_local(*f.displacementFes, displacementTrue, displacementLocal);
|
||||
@@ -234,9 +204,7 @@ namespace {
|
||||
mfem::Vector localAction(f.densityFes->GetVSize());
|
||||
localAction = 0.0;
|
||||
|
||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(
|
||||
f.mesh->Dimension()
|
||||
);
|
||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
||||
|
||||
mfem::Array<int> densityDofs;
|
||||
mfem::Array<int> enthalpyDofs;
|
||||
@@ -253,150 +221,105 @@ namespace {
|
||||
mfem::Vector densityShape;
|
||||
mfem::Vector enthalpyShape;
|
||||
|
||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
||||
|
||||
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
||||
mfem::ElementTransformation *transformation =
|
||||
f.mesh->GetElementTransformation(elementId);
|
||||
mfem::ElementTransformation *transformation = f.mesh->GetElementTransformation(elementId);
|
||||
|
||||
MFEM_VERIFY(
|
||||
transformation != nullptr,
|
||||
"The EOS closure kernel received a null "
|
||||
"element transformation."
|
||||
transformation != nullptr, "The EOS closure kernel received a null "
|
||||
"element transformation."
|
||||
);
|
||||
|
||||
if (transformation->Attribute == vacuumAttribute) {
|
||||
if (!element_is_in_closure_support(transformation->Attribute)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &densityElement =
|
||||
*f.densityFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &enthalpyElement =
|
||||
*f.enthalpyFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &displacementElement =
|
||||
*f.displacementFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &compactificationElement =
|
||||
*f.compactificationFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &densityElement = *f.densityFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &enthalpyElement = *f.enthalpyFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &displacementElement = *f.displacementFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &compactificationElement = *f.compactificationFes->GetFE(elementId);
|
||||
|
||||
mfem::DofTransformation *densityDofTransformation =
|
||||
f.densityFes->GetElementDofs(elementId, densityDofs);
|
||||
mfem::DofTransformation *densityDofTransformation = f.densityFes->GetElementDofs(elementId, densityDofs);
|
||||
|
||||
mfem::DofTransformation *enthalpyDofTransformation =
|
||||
f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
||||
mfem::DofTransformation *enthalpyDofTransformation = f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
||||
|
||||
mfem::DofTransformation *displacementDofTransformation =
|
||||
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
||||
|
||||
mfem::DofTransformation *compactificationDofTransformation =
|
||||
f.compactificationFes->GetElementDofs(
|
||||
elementId, compactificationDofs
|
||||
);
|
||||
f.compactificationFes->GetElementDofs(elementId, compactificationDofs);
|
||||
|
||||
if (densityInputTrue != nullptr) {
|
||||
densityInputLocal.GetSubVector(
|
||||
densityDofs, elementDensityInput
|
||||
);
|
||||
densityInputLocal.GetSubVector(densityDofs, elementDensityInput);
|
||||
|
||||
if (densityDofTransformation != nullptr) {
|
||||
densityDofTransformation->InvTransformPrimal(
|
||||
elementDensityInput
|
||||
);
|
||||
densityDofTransformation->InvTransformPrimal(elementDensityInput);
|
||||
}
|
||||
}
|
||||
|
||||
if (baseEnthalpyTrue != nullptr) {
|
||||
baseEnthalpyLocal.GetSubVector(
|
||||
enthalpyDofs, elementBaseEnthalpy
|
||||
);
|
||||
baseEnthalpyLocal.GetSubVector(enthalpyDofs, elementBaseEnthalpy);
|
||||
|
||||
if (enthalpyDofTransformation != nullptr) {
|
||||
enthalpyDofTransformation->InvTransformPrimal(
|
||||
elementBaseEnthalpy
|
||||
);
|
||||
enthalpyDofTransformation->InvTransformPrimal(elementBaseEnthalpy);
|
||||
}
|
||||
}
|
||||
|
||||
if (enthalpyVariationTrue != nullptr) {
|
||||
enthalpyVariationLocal.GetSubVector(
|
||||
enthalpyDofs, elementEnthalpyVariation
|
||||
);
|
||||
enthalpyVariationLocal.GetSubVector(enthalpyDofs, elementEnthalpyVariation);
|
||||
|
||||
if (enthalpyDofTransformation != nullptr) {
|
||||
enthalpyDofTransformation->InvTransformPrimal(
|
||||
elementEnthalpyVariation
|
||||
);
|
||||
enthalpyDofTransformation->InvTransformPrimal(elementEnthalpyVariation);
|
||||
}
|
||||
}
|
||||
|
||||
displacementLocal.GetSubVector(
|
||||
displacementDofs, elementDisplacement
|
||||
);
|
||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||
|
||||
f.compactificationCoordinate->GetSubVector(
|
||||
compactificationDofs, elementCompactification
|
||||
);
|
||||
f.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->InvTransformPrimal(
|
||||
elementDisplacement
|
||||
);
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
||||
}
|
||||
|
||||
if (compactificationDofTransformation != nullptr) {
|
||||
compactificationDofTransformation->InvTransformPrimal(
|
||||
elementCompactification
|
||||
);
|
||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
||||
}
|
||||
|
||||
const mean_field::mapping::ElementDisplacementData
|
||||
displacementData = mean_field::mapping::
|
||||
ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacement
|
||||
);
|
||||
const mean_field::mapping::ElementDisplacementData displacementData =
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
||||
|
||||
const mean_field::mapping::ElementCompactificationData
|
||||
compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
const mean_field::mapping::ElementCompactificationData compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
|
||||
const mean_field::mapping::ElementMappingData mappingData{
|
||||
.displacement = displacementData,
|
||||
.compactification = compactificationData
|
||||
.displacement = displacementData, .compactification = compactificationData
|
||||
};
|
||||
|
||||
densityShape.SetSize(densityElement.GetDof());
|
||||
enthalpyShape.SetSize(enthalpyElement.GetDof());
|
||||
elementAction.SetSize(densityElement.GetDof());
|
||||
elementAction = 0.0;
|
||||
elementAction = 0.0;
|
||||
|
||||
const mfem::IntegrationRule &integrationRule = get_eos_rule(
|
||||
f, barotrope, densityElement, enthalpyElement, *transformation
|
||||
);
|
||||
const mfem::IntegrationRule &integrationRule =
|
||||
get_eos_rule(f, barotrope, densityElement, enthalpyElement, *transformation);
|
||||
|
||||
for (int quadratureIndex = 0;
|
||||
quadratureIndex < integrationRule.GetNPoints();
|
||||
++quadratureIndex) {
|
||||
const mfem::IntegrationPoint &integrationPoint =
|
||||
integrationRule.IntPoint(quadratureIndex);
|
||||
for (int quadratureIndex = 0; quadratureIndex < integrationRule.GetNPoints(); ++quadratureIndex) {
|
||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadratureIndex);
|
||||
|
||||
transformation->SetIntPoint(&integrationPoint);
|
||||
|
||||
mean_field::mapping::VolumeMappingContext mappingContext;
|
||||
|
||||
const mean_field::mapping::MappingStatus mappingStatus =
|
||||
domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint,
|
||||
workspace, mappingContext
|
||||
);
|
||||
const mean_field::mapping::MappingStatus mappingStatus = domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
mappingStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"Stateless mapping failed in the EOS "
|
||||
"closure kernel. Element: "
|
||||
<< elementId
|
||||
<< ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadratureIndex
|
||||
<< ", status: " << static_cast<int>(mappingStatus)
|
||||
<< elementId << ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadratureIndex << ", status: " << static_cast<int>(mappingStatus)
|
||||
);
|
||||
|
||||
densityElement.CalcShape(integrationPoint, densityShape);
|
||||
@@ -408,34 +331,23 @@ namespace {
|
||||
} else {
|
||||
enthalpyElement.CalcShape(integrationPoint, enthalpyShape);
|
||||
|
||||
const double baseEnthalpy =
|
||||
elementBaseEnthalpy * enthalpyShape;
|
||||
const double baseEnthalpy = elementBaseEnthalpy * enthalpyShape;
|
||||
|
||||
if (closureAction == ClosureAction::residual) {
|
||||
const double density =
|
||||
elementDensityInput * densityShape;
|
||||
const double density = elementDensityInput * densityShape;
|
||||
|
||||
integrand =
|
||||
density -
|
||||
barotrope.density_from_enthalpy(baseEnthalpy);
|
||||
integrand = density - barotrope.density_from_enthalpy(baseEnthalpy);
|
||||
} else {
|
||||
const double enthalpyVariation =
|
||||
elementEnthalpyVariation * enthalpyShape;
|
||||
const double enthalpyVariation = elementEnthalpyVariation * enthalpyShape;
|
||||
|
||||
integrand = -barotrope.density_derivative_from_enthalpy(
|
||||
baseEnthalpy
|
||||
) *
|
||||
enthalpyVariation;
|
||||
integrand = -barotrope.density_derivative_from_enthalpy(baseEnthalpy) * enthalpyVariation;
|
||||
}
|
||||
}
|
||||
|
||||
const double weightedIntegrand =
|
||||
mappingContext.quadrature.weight * integrand;
|
||||
const double weightedIntegrand = mappingContext.quadrature.weight * integrand;
|
||||
|
||||
for (int densityDof = 0; densityDof < densityElement.GetDof();
|
||||
++densityDof) {
|
||||
elementAction(densityDof) +=
|
||||
weightedIntegrand * densityShape(densityDof);
|
||||
for (int densityDof = 0; densityDof < densityElement.GetDof(); ++densityDof) {
|
||||
elementAction(densityDof) += weightedIntegrand * densityShape(densityDof);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,51 +366,51 @@ namespace mean_field::operators::kernels {
|
||||
void apply_barotropic_closure(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope,
|
||||
const eos::Polytrope &barotrope,
|
||||
const mfem::Vector &densityTrue,
|
||||
const mfem::Vector &enthalpyTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &residual
|
||||
) {
|
||||
apply_closure_action(
|
||||
f, domainMapper, barotrope, ClosureAction::residual, &densityTrue,
|
||||
&enthalpyTrue, nullptr, displacementTrue, residual
|
||||
f, domainMapper, barotrope, ClosureAction::residual, &densityTrue, &enthalpyTrue, nullptr, displacementTrue,
|
||||
residual
|
||||
);
|
||||
}
|
||||
|
||||
void apply_barotropic_closure_density_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope,
|
||||
const eos::Polytrope &barotrope,
|
||||
const mfem::Vector &densityVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &action
|
||||
) {
|
||||
apply_closure_action(
|
||||
f, domainMapper, barotrope, ClosureAction::density,
|
||||
&densityVariationTrue, nullptr, nullptr, displacementTrue, action
|
||||
f, domainMapper, barotrope, ClosureAction::density, &densityVariationTrue, nullptr, nullptr,
|
||||
displacementTrue, action
|
||||
);
|
||||
}
|
||||
|
||||
void apply_barotropic_closure_enthalpy_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope,
|
||||
const eos::Polytrope &barotrope,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector &enthalpyVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &action
|
||||
) {
|
||||
apply_closure_action(
|
||||
f, domainMapper, barotrope, ClosureAction::enthalpy, nullptr,
|
||||
&baseEnthalpyTrue, &enthalpyVariationTrue, displacementTrue, action
|
||||
f, domainMapper, barotrope, ClosureAction::enthalpy, nullptr, &baseEnthalpyTrue, &enthalpyVariationTrue,
|
||||
displacementTrue, action
|
||||
);
|
||||
}
|
||||
|
||||
void apply_barotropic_closure_displacement_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope,
|
||||
const eos::Polytrope &barotrope,
|
||||
const mfem::Vector &baseDensityTrue,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
@@ -511,66 +423,55 @@ namespace mean_field::operators::kernels {
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr,
|
||||
"The barotropic-closure displacement action "
|
||||
"requires the density finite-element space."
|
||||
f.densityFes != nullptr, "The barotropic-closure displacement action "
|
||||
"requires the density finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.enthalpyFes != nullptr,
|
||||
"The barotropic-closure displacement action "
|
||||
"requires the enthalpy finite-element space."
|
||||
f.enthalpyFes != nullptr, "The barotropic-closure displacement action "
|
||||
"requires the enthalpy finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr,
|
||||
"The barotropic-closure displacement action "
|
||||
"requires the displacement finite-element space."
|
||||
f.displacementFes != nullptr, "The barotropic-closure displacement action "
|
||||
"requires the displacement finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.compactificationFes != nullptr,
|
||||
"The barotropic-closure displacement action "
|
||||
"requires the compactification finite-element space."
|
||||
f.compactificationFes != nullptr, "The barotropic-closure displacement action "
|
||||
"requires the compactification finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.compactificationCoordinate != nullptr,
|
||||
"The barotropic-closure displacement action "
|
||||
"requires the compactification coordinate."
|
||||
f.compactificationCoordinate != nullptr, "The barotropic-closure displacement action "
|
||||
"requires the compactification coordinate."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr,
|
||||
"The barotropic-closure displacement action "
|
||||
"requires the quadrature-rule factory."
|
||||
f.quadratureFactory != nullptr, "The barotropic-closure displacement action "
|
||||
"requires the quadrature-rule factory."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
baseDensityTrue.Size() == f.densityFes->GetTrueVSize(),
|
||||
"The base-density vector has the wrong size."
|
||||
baseDensityTrue.Size() == f.densityFes->GetTrueVSize(), "The base-density vector has the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
baseEnthalpyTrue.Size() == f.enthalpyFes->GetTrueVSize(),
|
||||
"The base-enthalpy vector has the wrong size."
|
||||
baseEnthalpyTrue.Size() == f.enthalpyFes->GetTrueVSize(), "The base-enthalpy vector has the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The displacement vector has the wrong size."
|
||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(), "The displacement vector has the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementVariationTrue.Size() ==
|
||||
f.displacementFes->GetTrueVSize(),
|
||||
displacementVariationTrue.Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The displacement-variation vector has the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
domainMapper.GetDimension() == f.mesh->Dimension(),
|
||||
"The domain-mapper dimension does not match the "
|
||||
"mesh dimension."
|
||||
domainMapper.GetDimension() == f.mesh->Dimension(), "The domain-mapper dimension does not match the "
|
||||
"mesh dimension."
|
||||
);
|
||||
|
||||
mfem::Vector baseDensityLocal;
|
||||
@@ -584,17 +485,12 @@ namespace mean_field::operators::kernels {
|
||||
|
||||
true_to_local(*f.displacementFes, displacementTrue, displacementLocal);
|
||||
|
||||
true_to_local(
|
||||
*f.displacementFes, displacementVariationTrue,
|
||||
displacementVariationLocal
|
||||
);
|
||||
true_to_local(*f.displacementFes, displacementVariationTrue, displacementVariationLocal);
|
||||
|
||||
mfem::Vector localAction(f.densityFes->GetVSize());
|
||||
localAction = 0.0;
|
||||
|
||||
mapping::DomainMapperStateless::Workspace workspace(
|
||||
f.mesh->Dimension()
|
||||
);
|
||||
mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
||||
|
||||
mfem::Array<int> densityDofs;
|
||||
mfem::Array<int> enthalpyDofs;
|
||||
@@ -614,109 +510,76 @@ namespace mean_field::operators::kernels {
|
||||
mapping::VolumeMappingContext mappingContext;
|
||||
mapping::VolumeMappingVariation mappingVariation;
|
||||
|
||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
||||
|
||||
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
||||
mfem::ElementTransformation *transformation =
|
||||
f.mesh->GetElementTransformation(elementId);
|
||||
mfem::ElementTransformation *transformation = f.mesh->GetElementTransformation(elementId);
|
||||
|
||||
MFEM_VERIFY(
|
||||
transformation != nullptr,
|
||||
"The barotropic-closure displacement action "
|
||||
"received a null element transformation."
|
||||
transformation != nullptr, "The barotropic-closure displacement action "
|
||||
"received a null element transformation."
|
||||
);
|
||||
|
||||
if (transformation->Attribute == vacuumAttribute) {
|
||||
if (!element_is_in_closure_support(transformation->Attribute)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &densityElement =
|
||||
*f.densityFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &densityElement = *f.densityFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &enthalpyElement =
|
||||
*f.enthalpyFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &enthalpyElement = *f.enthalpyFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &displacementElement =
|
||||
*f.displacementFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &displacementElement = *f.displacementFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &compactificationElement =
|
||||
*f.compactificationFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &compactificationElement = *f.compactificationFes->GetFE(elementId);
|
||||
|
||||
mfem::DofTransformation *densityDofTransformation =
|
||||
f.densityFes->GetElementDofs(elementId, densityDofs);
|
||||
mfem::DofTransformation *densityDofTransformation = f.densityFes->GetElementDofs(elementId, densityDofs);
|
||||
|
||||
mfem::DofTransformation *enthalpyDofTransformation =
|
||||
f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
||||
mfem::DofTransformation *enthalpyDofTransformation = f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
||||
|
||||
mfem::DofTransformation *displacementDofTransformation =
|
||||
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
||||
|
||||
mfem::DofTransformation *compactificationDofTransformation =
|
||||
f.compactificationFes->GetElementDofs(
|
||||
elementId, compactificationDofs
|
||||
);
|
||||
f.compactificationFes->GetElementDofs(elementId, compactificationDofs);
|
||||
|
||||
baseDensityLocal.GetSubVector(densityDofs, elementBaseDensity);
|
||||
|
||||
baseEnthalpyLocal.GetSubVector(enthalpyDofs, elementBaseEnthalpy);
|
||||
|
||||
displacementLocal.GetSubVector(
|
||||
displacementDofs, elementDisplacement
|
||||
);
|
||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||
|
||||
displacementVariationLocal.GetSubVector(
|
||||
displacementDofs, elementDisplacementVariation
|
||||
);
|
||||
displacementVariationLocal.GetSubVector(displacementDofs, elementDisplacementVariation);
|
||||
|
||||
f.compactificationCoordinate->GetSubVector(
|
||||
compactificationDofs, elementCompactification
|
||||
);
|
||||
f.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
||||
|
||||
if (densityDofTransformation != nullptr) {
|
||||
densityDofTransformation->InvTransformPrimal(
|
||||
elementBaseDensity
|
||||
);
|
||||
densityDofTransformation->InvTransformPrimal(elementBaseDensity);
|
||||
}
|
||||
|
||||
if (enthalpyDofTransformation != nullptr) {
|
||||
enthalpyDofTransformation->InvTransformPrimal(
|
||||
elementBaseEnthalpy
|
||||
);
|
||||
enthalpyDofTransformation->InvTransformPrimal(elementBaseEnthalpy);
|
||||
}
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->InvTransformPrimal(
|
||||
elementDisplacement
|
||||
);
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
||||
|
||||
displacementDofTransformation->InvTransformPrimal(
|
||||
elementDisplacementVariation
|
||||
);
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacementVariation);
|
||||
}
|
||||
|
||||
if (compactificationDofTransformation != nullptr) {
|
||||
compactificationDofTransformation->InvTransformPrimal(
|
||||
elementCompactification
|
||||
);
|
||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
||||
}
|
||||
|
||||
const mapping::ElementDisplacementData displacementData =
|
||||
mapping::ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacement
|
||||
);
|
||||
mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
||||
|
||||
const mapping::ElementDisplacementData displacementVariationData =
|
||||
mapping::ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacementVariation
|
||||
);
|
||||
mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacementVariation);
|
||||
|
||||
const mapping::ElementCompactificationData compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
|
||||
const mapping::ElementMappingData mappingData{
|
||||
.displacement = displacementData,
|
||||
.compactification = compactificationData
|
||||
.displacement = displacementData, .compactification = compactificationData
|
||||
};
|
||||
|
||||
densityShape.SetSize(densityElement.GetDof());
|
||||
@@ -724,74 +587,57 @@ namespace mean_field::operators::kernels {
|
||||
enthalpyShape.SetSize(enthalpyElement.GetDof());
|
||||
|
||||
elementAction.SetSize(densityElement.GetDof());
|
||||
elementAction = 0.0;
|
||||
elementAction = 0.0;
|
||||
|
||||
const mfem::IntegrationRule &integrationRule = get_eos_rule(
|
||||
f, barotrope, densityElement, enthalpyElement, *transformation
|
||||
);
|
||||
const mfem::IntegrationRule &integrationRule =
|
||||
get_eos_rule(f, barotrope, densityElement, enthalpyElement, *transformation);
|
||||
|
||||
for (int quadraturePoint = 0;
|
||||
quadraturePoint < integrationRule.GetNPoints();
|
||||
++quadraturePoint) {
|
||||
const mfem::IntegrationPoint &integrationPoint =
|
||||
integrationRule.IntPoint(quadraturePoint);
|
||||
for (int quadraturePoint = 0; quadraturePoint < integrationRule.GetNPoints(); ++quadraturePoint) {
|
||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadraturePoint);
|
||||
|
||||
transformation->SetIntPoint(&integrationPoint);
|
||||
|
||||
const mapping::MappingStatus mappingStatus =
|
||||
domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint,
|
||||
workspace, mappingContext
|
||||
);
|
||||
const mapping::MappingStatus mappingStatus = domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
mappingStatus == mapping::MappingStatus::valid,
|
||||
"The base mapping is invalid while applying "
|
||||
"the barotropic-closure displacement action. "
|
||||
"Element: "
|
||||
<< elementId
|
||||
<< ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadraturePoint
|
||||
<< ", status: " << static_cast<int>(mappingStatus)
|
||||
<< elementId << ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadraturePoint << ", status: " << static_cast<int>(mappingStatus)
|
||||
);
|
||||
|
||||
const mapping::MappingStatus variationStatus =
|
||||
domainMapper.EvaluateVolumeVariation(
|
||||
mappingData, displacementVariationData, *transformation,
|
||||
integrationPoint, mappingContext, workspace,
|
||||
mappingVariation
|
||||
);
|
||||
const mapping::MappingStatus variationStatus = domainMapper.EvaluateVolumeVariation(
|
||||
mappingData, displacementVariationData, *transformation, integrationPoint, mappingContext,
|
||||
workspace, mappingVariation
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
variationStatus == mapping::MappingStatus::valid,
|
||||
"The mapping variation is invalid while "
|
||||
"applying the barotropic-closure "
|
||||
"displacement action. Element: "
|
||||
<< elementId
|
||||
<< ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadraturePoint
|
||||
<< ", status: " << static_cast<int>(variationStatus)
|
||||
<< elementId << ", attribute: " << transformation->Attribute << ", quadrature point: "
|
||||
<< quadraturePoint << ", status: " << static_cast<int>(variationStatus)
|
||||
);
|
||||
|
||||
densityElement.CalcShape(integrationPoint, densityShape);
|
||||
|
||||
enthalpyElement.CalcShape(integrationPoint, enthalpyShape);
|
||||
|
||||
const double densityValue = elementBaseDensity * densityShape;
|
||||
const double densityValue = elementBaseDensity * densityShape;
|
||||
|
||||
const double enthalpyValue =
|
||||
elementBaseEnthalpy * enthalpyShape;
|
||||
const double enthalpyValue = elementBaseEnthalpy * enthalpyShape;
|
||||
|
||||
const double closureValue =
|
||||
densityValue -
|
||||
barotrope.density_from_enthalpy(enthalpyValue);
|
||||
const double closureValue = densityValue - barotrope.density_from_enthalpy(enthalpyValue);
|
||||
|
||||
const double geometryActionValue =
|
||||
closureValue * mappingVariation.weight_variation;
|
||||
const double geometryActionValue = closureValue * mappingVariation.weight_variation;
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(closureValue) &&
|
||||
std::isfinite(geometryActionValue),
|
||||
std::isfinite(closureValue) && std::isfinite(geometryActionValue),
|
||||
"The barotropic-closure displacement action "
|
||||
"encountered a non-finite quadrature value."
|
||||
);
|
||||
@@ -808,4 +654,4 @@ namespace mean_field::operators::kernels {
|
||||
|
||||
local_to_true(*f.densityFes, localAction, action);
|
||||
}
|
||||
} // namespace mean_field::operators::kernels
|
||||
} // namespace mean_field::operators::kernels
|
||||
|
||||
@@ -0,0 +1,718 @@
|
||||
module;
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
module mean_field;
|
||||
|
||||
import :operators.kernels.gravity_displacement_force;
|
||||
|
||||
namespace {
|
||||
enum class GravityDisplacementForceAction { residual, density, gravityGradient, displacement, complete };
|
||||
|
||||
void true_to_local(
|
||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||
const mfem::Vector &trueVector,
|
||||
mfem::Vector &localVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
trueVector.Size() == finiteElementSpace.GetTrueVSize(),
|
||||
"The gravity-displacement-force true vector has the wrong size."
|
||||
);
|
||||
|
||||
localVector.SetSize(finiteElementSpace.GetVSize());
|
||||
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->Mult(trueVector, localVector);
|
||||
} else {
|
||||
localVector = trueVector;
|
||||
}
|
||||
}
|
||||
|
||||
void local_to_true(
|
||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||
const mfem::Vector &localVector,
|
||||
mfem::Vector &trueVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
localVector.Size() == finiteElementSpace.GetVSize(),
|
||||
"The gravity-displacement-force local vector has the wrong size."
|
||||
);
|
||||
|
||||
trueVector.SetSize(finiteElementSpace.GetTrueVSize());
|
||||
trueVector = 0.0;
|
||||
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->MultTranspose(localVector, trueVector);
|
||||
} else {
|
||||
trueVector = localVector;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] int vector_dof_index(
|
||||
const mfem::Ordering::Type ordering,
|
||||
const int scalarDof,
|
||||
const int component,
|
||||
const int scalarDofCount,
|
||||
const int dimension
|
||||
) {
|
||||
if (ordering == mfem::Ordering::byNODES) {
|
||||
return scalarDof + component * scalarDofCount;
|
||||
}
|
||||
|
||||
if (ordering == mfem::Ordering::byVDIM) {
|
||||
return scalarDof * dimension + component;
|
||||
}
|
||||
|
||||
MFEM_ABORT(
|
||||
"The gravity-displacement-force test space uses an unsupported "
|
||||
"ordering."
|
||||
);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
[[nodiscard]] const mfem::IntegrationRule &get_gravity_force_rule(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mfem::FiniteElement &densityElement,
|
||||
const mfem::FiniteElement &gravityGradientElement,
|
||||
const mfem::FiniteElement &displacementElement,
|
||||
const mfem::ElementTransformation &transformation
|
||||
) {
|
||||
using DisplacementField = mean_field::field::Field<mean_field::field::Displacement>;
|
||||
|
||||
MFEM_VERIFY(
|
||||
densityElement.GetOrder() == mean_field::field::Density::Scalar::familyOrder,
|
||||
"The gravity-displacement-force density element does not match "
|
||||
"the registered density field."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
gravityGradientElement.GetOrder() == mean_field::field::Gravity::Flux::familyOrder + 1,
|
||||
"The gravity-displacement-force RT element does not match the "
|
||||
"registered gravity-gradient field."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementElement.GetOrder() == mean_field::field::Displacement::Vector::familyOrder,
|
||||
"The gravity-displacement-force test element does not match the "
|
||||
"registered displacement field."
|
||||
);
|
||||
|
||||
const mean_field::quadrature::Query query =
|
||||
DisplacementField::make_query<mean_field::field::Displacement::Form::GravityForce>(
|
||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), {},
|
||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
|
||||
const mean_field::quadrature::MfemRule rule = f.quadratureFactory->get(query, transformation.GetGeometryType());
|
||||
|
||||
MFEM_VERIFY(
|
||||
rule.integration_rule != nullptr, "The quadrature policy did not return a gravity-displacement-"
|
||||
"force integration rule."
|
||||
);
|
||||
|
||||
return *rule.integration_rule;
|
||||
}
|
||||
|
||||
void validate_finite_vector(
|
||||
const mfem::Vector &vector,
|
||||
const char *message
|
||||
) {
|
||||
for (int index = 0; index < vector.Size(); ++index) {
|
||||
MFEM_VERIFY(std::isfinite(vector(index)), message);
|
||||
}
|
||||
}
|
||||
|
||||
void validate_common_inputs(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
||||
const mfem::Vector &displacementTrue
|
||||
) {
|
||||
MFEM_VERIFY(f.mesh != nullptr, "The gravity-displacement-force kernel requires a mesh.");
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr, "The gravity-displacement-force kernel requires the density "
|
||||
"finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.gravityFluxFes != nullptr, "The gravity-displacement-force kernel requires the gravity-"
|
||||
"gradient finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr, "The gravity-displacement-force kernel requires the displacement "
|
||||
"finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.compactificationFes != nullptr && f.compactificationCoordinate != nullptr,
|
||||
"The gravity-displacement-force kernel requires the "
|
||||
"compactification coordinate."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr, "The gravity-displacement-force kernel requires the quadrature "
|
||||
"rule factory."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The gravity-displacement-force displacement vector has the "
|
||||
"wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
domainMapper.GetDimension() == f.mesh->Dimension(),
|
||||
"The gravity-displacement-force mapper dimension does not match "
|
||||
"the mesh dimension."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes->GetVDim() == f.mesh->Dimension(),
|
||||
"The gravity-displacement-force displacement dimension does not "
|
||||
"match the mesh dimension."
|
||||
);
|
||||
|
||||
validate_finite_vector(
|
||||
displacementTrue, "The gravity-displacement-force displacement contains a "
|
||||
"non-finite value."
|
||||
);
|
||||
}
|
||||
|
||||
void validate_density(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mfem::Vector &density,
|
||||
const char *message
|
||||
) {
|
||||
MFEM_VERIFY(density.Size() == f.densityFes->GetTrueVSize(), message);
|
||||
validate_finite_vector(density, message);
|
||||
}
|
||||
|
||||
void validate_gravity_gradient(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mfem::Vector &gravityGradient,
|
||||
const char *message
|
||||
) {
|
||||
MFEM_VERIFY(gravityGradient.Size() == f.gravityFluxFes->GetTrueVSize(), message);
|
||||
|
||||
validate_finite_vector(gravityGradient, message);
|
||||
}
|
||||
|
||||
void apply_gravity_displacement_force_action(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
||||
const GravityDisplacementForceAction requestedAction,
|
||||
const mfem::Vector *baseDensityTrue,
|
||||
const mfem::Vector *densityVariationTrue,
|
||||
const mfem::Vector *baseGravityGradientTrue,
|
||||
const mfem::Vector *gravityGradientVariationTrue,
|
||||
const mfem::Vector *displacementVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
validate_common_inputs(f, domainMapper, displacementTrue);
|
||||
|
||||
const bool needsBaseDensity = requestedAction == GravityDisplacementForceAction::residual ||
|
||||
requestedAction == GravityDisplacementForceAction::gravityGradient ||
|
||||
requestedAction == GravityDisplacementForceAction::displacement ||
|
||||
requestedAction == GravityDisplacementForceAction::complete;
|
||||
|
||||
const bool needsDensityVariation = requestedAction == GravityDisplacementForceAction::density ||
|
||||
requestedAction == GravityDisplacementForceAction::complete;
|
||||
|
||||
const bool needsBaseGravityGradient = requestedAction == GravityDisplacementForceAction::residual ||
|
||||
requestedAction == GravityDisplacementForceAction::density ||
|
||||
requestedAction == GravityDisplacementForceAction::displacement ||
|
||||
requestedAction == GravityDisplacementForceAction::complete;
|
||||
|
||||
const bool needsGravityGradientVariation = requestedAction == GravityDisplacementForceAction::gravityGradient ||
|
||||
requestedAction == GravityDisplacementForceAction::complete;
|
||||
|
||||
const bool needsDisplacementVariation = requestedAction == GravityDisplacementForceAction::displacement ||
|
||||
requestedAction == GravityDisplacementForceAction::complete;
|
||||
|
||||
if (needsBaseDensity) {
|
||||
MFEM_VERIFY(
|
||||
baseDensityTrue != nullptr, "The gravity-displacement-force action requires a base "
|
||||
"density."
|
||||
);
|
||||
|
||||
validate_density(f, *baseDensityTrue, "The gravity-displacement-force base density is invalid.");
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
MFEM_VERIFY(
|
||||
densityVariationTrue != nullptr, "The gravity-displacement-force action requires a density "
|
||||
"variation."
|
||||
);
|
||||
|
||||
validate_density(
|
||||
f, *densityVariationTrue,
|
||||
"The gravity-displacement-force density variation is "
|
||||
"invalid."
|
||||
);
|
||||
}
|
||||
|
||||
if (needsBaseGravityGradient) {
|
||||
MFEM_VERIFY(
|
||||
baseGravityGradientTrue != nullptr, "The gravity-displacement-force action requires a base "
|
||||
"gravity gradient."
|
||||
);
|
||||
|
||||
validate_gravity_gradient(
|
||||
f, *baseGravityGradientTrue,
|
||||
"The gravity-displacement-force base gravity gradient is "
|
||||
"invalid."
|
||||
);
|
||||
}
|
||||
|
||||
if (needsGravityGradientVariation) {
|
||||
MFEM_VERIFY(
|
||||
gravityGradientVariationTrue != nullptr, "The gravity-displacement-force action requires a gravity-"
|
||||
"gradient variation."
|
||||
);
|
||||
|
||||
validate_gravity_gradient(
|
||||
f, *gravityGradientVariationTrue,
|
||||
"The gravity-displacement-force gravity-gradient variation "
|
||||
"is invalid."
|
||||
);
|
||||
}
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
MFEM_VERIFY(
|
||||
displacementVariationTrue != nullptr &&
|
||||
displacementVariationTrue->Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The gravity-displacement-force displacement variation is "
|
||||
"invalid."
|
||||
);
|
||||
|
||||
validate_finite_vector(
|
||||
*displacementVariationTrue, "The gravity-displacement-force displacement variation "
|
||||
"contains a non-finite value."
|
||||
);
|
||||
}
|
||||
|
||||
mfem::Vector baseDensityLocal;
|
||||
mfem::Vector densityVariationLocal;
|
||||
mfem::Vector baseGravityGradientLocal;
|
||||
mfem::Vector gravityGradientVariationLocal;
|
||||
mfem::Vector displacementLocal;
|
||||
mfem::Vector displacementVariationLocal;
|
||||
|
||||
if (needsBaseDensity) {
|
||||
true_to_local(*f.densityFes, *baseDensityTrue, baseDensityLocal);
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
true_to_local(*f.densityFes, *densityVariationTrue, densityVariationLocal);
|
||||
}
|
||||
|
||||
if (needsBaseGravityGradient) {
|
||||
true_to_local(*f.gravityFluxFes, *baseGravityGradientTrue, baseGravityGradientLocal);
|
||||
}
|
||||
|
||||
if (needsGravityGradientVariation) {
|
||||
true_to_local(*f.gravityFluxFes, *gravityGradientVariationTrue, gravityGradientVariationLocal);
|
||||
}
|
||||
|
||||
true_to_local(*f.displacementFes, displacementTrue, displacementLocal);
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
true_to_local(*f.displacementFes, *displacementVariationTrue, displacementVariationLocal);
|
||||
}
|
||||
|
||||
mfem::Vector localAction(f.displacementFes->GetVSize());
|
||||
localAction = 0.0;
|
||||
|
||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
||||
|
||||
mfem::Array<int> densityDofs;
|
||||
mfem::Array<int> gravityGradientDofs;
|
||||
mfem::Array<int> displacementDofs;
|
||||
mfem::Array<int> compactificationDofs;
|
||||
|
||||
mfem::Vector elementBaseDensity;
|
||||
mfem::Vector elementDensityVariation;
|
||||
mfem::Vector elementBaseGravityGradient;
|
||||
mfem::Vector elementGravityGradientVariation;
|
||||
mfem::Vector elementDisplacement;
|
||||
mfem::Vector elementDisplacementVariation;
|
||||
mfem::Vector elementCompactification;
|
||||
mfem::Vector elementAction;
|
||||
|
||||
mfem::Vector densityShape;
|
||||
mfem::Vector displacementShape;
|
||||
mfem::DenseMatrix gravityGradientShape;
|
||||
|
||||
mfem::Vector baseGravityReferenceValue;
|
||||
mfem::Vector gravityVariationReferenceValue;
|
||||
mfem::Vector mappedBaseGravity;
|
||||
mfem::Vector mappedGravityVariation;
|
||||
mfem::Vector mappedGeometryVariation;
|
||||
mfem::Vector forceValue;
|
||||
|
||||
mean_field::mapping::VolumeMappingContext mappingContext;
|
||||
mean_field::mapping::VolumeMappingVariation mappingVariation;
|
||||
|
||||
const int dimension = f.mesh->Dimension();
|
||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
||||
|
||||
const mfem::Ordering::Type displacementOrdering = f.displacementFes->GetOrdering();
|
||||
|
||||
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
||||
mfem::ElementTransformation *transformation = f.mesh->GetElementTransformation(elementId);
|
||||
|
||||
MFEM_VERIFY(
|
||||
transformation != nullptr, "The gravity-displacement-force kernel received a null "
|
||||
"element transformation."
|
||||
);
|
||||
|
||||
if (transformation->Attribute == vacuumAttribute) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &densityElement = *f.densityFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &gravityGradientElement = *f.gravityFluxFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &displacementElement = *f.displacementFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &compactificationElement = *f.compactificationFes->GetFE(elementId);
|
||||
|
||||
mfem::DofTransformation *densityDofTransformation = f.densityFes->GetElementDofs(elementId, densityDofs);
|
||||
|
||||
mfem::DofTransformation *gravityGradientDofTransformation =
|
||||
f.gravityFluxFes->GetElementVDofs(elementId, gravityGradientDofs);
|
||||
|
||||
mfem::DofTransformation *displacementDofTransformation =
|
||||
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
||||
|
||||
mfem::DofTransformation *compactificationDofTransformation =
|
||||
f.compactificationFes->GetElementDofs(elementId, compactificationDofs);
|
||||
|
||||
if (needsBaseDensity) {
|
||||
baseDensityLocal.GetSubVector(densityDofs, elementBaseDensity);
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
densityVariationLocal.GetSubVector(densityDofs, elementDensityVariation);
|
||||
}
|
||||
|
||||
if (needsBaseGravityGradient) {
|
||||
baseGravityGradientLocal.GetSubVector(gravityGradientDofs, elementBaseGravityGradient);
|
||||
}
|
||||
|
||||
if (needsGravityGradientVariation) {
|
||||
gravityGradientVariationLocal.GetSubVector(gravityGradientDofs, elementGravityGradientVariation);
|
||||
}
|
||||
|
||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
displacementVariationLocal.GetSubVector(displacementDofs, elementDisplacementVariation);
|
||||
}
|
||||
|
||||
f.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
||||
|
||||
if (densityDofTransformation != nullptr) {
|
||||
if (needsBaseDensity) {
|
||||
densityDofTransformation->InvTransformPrimal(elementBaseDensity);
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
densityDofTransformation->InvTransformPrimal(elementDensityVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (gravityGradientDofTransformation != nullptr) {
|
||||
if (needsBaseGravityGradient) {
|
||||
gravityGradientDofTransformation->InvTransformPrimal(elementBaseGravityGradient);
|
||||
}
|
||||
|
||||
if (needsGravityGradientVariation) {
|
||||
gravityGradientDofTransformation->InvTransformPrimal(elementGravityGradientVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacementVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (compactificationDofTransformation != nullptr) {
|
||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
||||
}
|
||||
|
||||
const mean_field::mapping::ElementDisplacementData displacementData =
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
||||
|
||||
const mean_field::mapping::ElementCompactificationData compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
|
||||
const mean_field::mapping::ElementMappingData mappingData{
|
||||
.displacement = displacementData, .compactification = compactificationData
|
||||
};
|
||||
|
||||
std::optional<mean_field::mapping::ElementDisplacementData> displacementVariationData;
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
displacementVariationData.emplace(
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacementVariation
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const int scalarDisplacementDofCount = displacementElement.GetDof();
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementDofs.Size() == scalarDisplacementDofCount * dimension,
|
||||
"The gravity-displacement-force element displacement vector "
|
||||
"has the wrong size."
|
||||
);
|
||||
|
||||
densityShape.SetSize(densityElement.GetDof());
|
||||
displacementShape.SetSize(scalarDisplacementDofCount);
|
||||
gravityGradientShape.SetSize(gravityGradientElement.GetDof(), dimension);
|
||||
|
||||
baseGravityReferenceValue.SetSize(dimension);
|
||||
gravityVariationReferenceValue.SetSize(dimension);
|
||||
mappedBaseGravity.SetSize(dimension);
|
||||
mappedGravityVariation.SetSize(dimension);
|
||||
mappedGeometryVariation.SetSize(dimension);
|
||||
forceValue.SetSize(dimension);
|
||||
|
||||
elementAction.SetSize(displacementDofs.Size());
|
||||
elementAction = 0.0;
|
||||
|
||||
const mfem::IntegrationRule &integrationRule =
|
||||
get_gravity_force_rule(f, densityElement, gravityGradientElement, displacementElement, *transformation);
|
||||
|
||||
for (int quadratureIndex = 0; quadratureIndex < integrationRule.GetNPoints(); ++quadratureIndex) {
|
||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadratureIndex);
|
||||
|
||||
transformation->SetIntPoint(&integrationPoint);
|
||||
|
||||
const mean_field::mapping::MappingStatus mappingStatus = domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
mappingStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"Stateless mapping failed in the gravity-displacement-"
|
||||
"force kernel. Element: "
|
||||
<< elementId << ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadratureIndex << ", status: " << static_cast<int>(mappingStatus)
|
||||
);
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
const mean_field::mapping::MappingStatus variationStatus = domainMapper.EvaluateVolumeVariation(
|
||||
mappingData, *displacementVariationData, *transformation, integrationPoint, mappingContext,
|
||||
workspace, mappingVariation
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
variationStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"Stateless mapping variation failed in the gravity-"
|
||||
"displacement-force kernel. Element: "
|
||||
<< elementId << ", attribute: " << transformation->Attribute << ", quadrature point: "
|
||||
<< quadratureIndex << ", status: " << static_cast<int>(variationStatus)
|
||||
);
|
||||
}
|
||||
|
||||
densityElement.CalcShape(integrationPoint, densityShape);
|
||||
|
||||
displacementElement.CalcShape(integrationPoint, displacementShape);
|
||||
|
||||
gravityGradientElement.CalcVShape(*transformation, gravityGradientShape);
|
||||
|
||||
double baseDensityValue = 0.0;
|
||||
double densityVariationValue = 0.0;
|
||||
|
||||
if (needsBaseDensity) {
|
||||
baseDensityValue = elementBaseDensity * densityShape;
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
densityVariationValue = elementDensityVariation * densityShape;
|
||||
}
|
||||
|
||||
if (needsBaseGravityGradient) {
|
||||
gravityGradientShape.MultTranspose(elementBaseGravityGradient, baseGravityReferenceValue);
|
||||
|
||||
mappingContext.mapping.mapping_jacobian.Mult(baseGravityReferenceValue, mappedBaseGravity);
|
||||
} else {
|
||||
mappedBaseGravity = 0.0;
|
||||
}
|
||||
|
||||
if (needsGravityGradientVariation) {
|
||||
gravityGradientShape.MultTranspose(elementGravityGradientVariation, gravityVariationReferenceValue);
|
||||
|
||||
mappingContext.mapping.mapping_jacobian.Mult(
|
||||
gravityVariationReferenceValue, mappedGravityVariation
|
||||
);
|
||||
} else {
|
||||
mappedGravityVariation = 0.0;
|
||||
}
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
mappingVariation.mapping.mapping_jacobian_variation.Mult(
|
||||
baseGravityReferenceValue, mappedGeometryVariation
|
||||
);
|
||||
} else {
|
||||
mappedGeometryVariation = 0.0;
|
||||
}
|
||||
|
||||
forceValue = 0.0;
|
||||
|
||||
if (requestedAction == GravityDisplacementForceAction::residual) {
|
||||
forceValue.Add(baseDensityValue, mappedBaseGravity);
|
||||
} else {
|
||||
if (needsDensityVariation) {
|
||||
forceValue.Add(densityVariationValue, mappedBaseGravity);
|
||||
}
|
||||
|
||||
if (needsGravityGradientVariation) {
|
||||
forceValue.Add(baseDensityValue, mappedGravityVariation);
|
||||
}
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
forceValue.Add(baseDensityValue, mappedGeometryVariation);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If g_ref is the RT pullback, then
|
||||
*
|
||||
* g_phys = J_map g_ref / det(J_map),
|
||||
* dV_phys = det(J_map) dV_ref.
|
||||
*
|
||||
* The determinant cancels exactly. Consequently the base
|
||||
* integrand uses J_map g_ref and its geometry derivative uses
|
||||
* delta(J_map) g_ref. This is algebraically identical to
|
||||
* differentiating the Piola map and physical volume weight,
|
||||
* but avoids a numerically pointless cancellation.
|
||||
*/
|
||||
const double referenceWeight = integrationPoint.weight * transformation->Weight();
|
||||
|
||||
forceValue *= referenceWeight;
|
||||
|
||||
for (int scalarDof = 0; scalarDof < scalarDisplacementDofCount; ++scalarDof) {
|
||||
for (int component = 0; component < dimension; ++component) {
|
||||
const int vectorDof = vector_dof_index(
|
||||
displacementOrdering, scalarDof, component, scalarDisplacementDofCount, dimension
|
||||
);
|
||||
|
||||
const double contribution = displacementShape(scalarDof) * forceValue(component);
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(contribution), "The gravity-displacement-force kernel "
|
||||
"encountered a non-finite contribution."
|
||||
);
|
||||
|
||||
elementAction(vectorDof) += contribution;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->TransformDual(elementAction);
|
||||
}
|
||||
|
||||
localAction.AddElementVector(displacementDofs, elementAction);
|
||||
}
|
||||
|
||||
local_to_true(*f.displacementFes, localAction, actionTrue);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace mean_field::operators::kernels {
|
||||
void apply_gravity_displacement_force_residual(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const mfem::Vector &densityTrue,
|
||||
const mfem::Vector &gravityGradientTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &residualTrue
|
||||
) {
|
||||
apply_gravity_displacement_force_action(
|
||||
f, domainMapper, GravityDisplacementForceAction::residual, &densityTrue, nullptr, &gravityGradientTrue,
|
||||
nullptr, nullptr, displacementTrue, residualTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_gravity_displacement_force_density_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const mfem::Vector &densityVariationTrue,
|
||||
const mfem::Vector &baseGravityGradientTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_gravity_displacement_force_action(
|
||||
f, domainMapper, GravityDisplacementForceAction::density, nullptr, &densityVariationTrue,
|
||||
&baseGravityGradientTrue, nullptr, nullptr, displacementTrue, actionTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_gravity_displacement_force_gradient_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const mfem::Vector &baseDensityTrue,
|
||||
const mfem::Vector &gravityGradientVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_gravity_displacement_force_action(
|
||||
f, domainMapper, GravityDisplacementForceAction::gravityGradient, &baseDensityTrue, nullptr, nullptr,
|
||||
&gravityGradientVariationTrue, nullptr, displacementTrue, actionTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_gravity_displacement_force_displacement_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const mfem::Vector &baseDensityTrue,
|
||||
const mfem::Vector &baseGravityGradientTrue,
|
||||
const mfem::Vector &displacementVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_gravity_displacement_force_action(
|
||||
f, domainMapper, GravityDisplacementForceAction::displacement, &baseDensityTrue, nullptr,
|
||||
&baseGravityGradientTrue, nullptr, &displacementVariationTrue, displacementTrue, actionTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_gravity_displacement_force_complete_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const mfem::Vector &baseDensityTrue,
|
||||
const mfem::Vector &densityVariationTrue,
|
||||
const mfem::Vector &baseGravityGradientTrue,
|
||||
const mfem::Vector &gravityGradientVariationTrue,
|
||||
const mfem::Vector &displacementVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_gravity_displacement_force_action(
|
||||
f, domainMapper, GravityDisplacementForceAction::complete, &baseDensityTrue, &densityVariationTrue,
|
||||
&baseGravityGradientTrue, &gravityGradientVariationTrue, &displacementVariationTrue, displacementTrue,
|
||||
actionTrue
|
||||
);
|
||||
}
|
||||
} // namespace mean_field::operators::kernels
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,15 +16,11 @@ namespace {
|
||||
const mfem::Vector &trueVector,
|
||||
mfem::Vector &localVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
trueVector.Size() == finiteElementSpace.GetTrueVSize(),
|
||||
"True vector has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(trueVector.Size() == finiteElementSpace.GetTrueVSize(), "True vector has the wrong size.");
|
||||
|
||||
localVector.SetSize(finiteElementSpace.GetVSize());
|
||||
|
||||
const mfem::Operator *prolongation =
|
||||
finiteElementSpace.GetProlongationMatrix();
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->Mult(trueVector, localVector);
|
||||
@@ -38,17 +34,13 @@ namespace {
|
||||
const mfem::Vector &localVector,
|
||||
mfem::Vector &trueVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
localVector.Size() == finiteElementSpace.GetVSize(),
|
||||
"Local vector has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(localVector.Size() == finiteElementSpace.GetVSize(), "Local vector has the wrong size.");
|
||||
|
||||
trueVector.SetSize(finiteElementSpace.GetTrueVSize());
|
||||
|
||||
trueVector = 0.0;
|
||||
trueVector = 0.0;
|
||||
|
||||
const mfem::Operator *prolongation =
|
||||
finiteElementSpace.GetProlongationMatrix();
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->MultTranspose(localVector, trueVector);
|
||||
@@ -61,9 +53,7 @@ namespace {
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::mapping::DomainMapperStateless &domainMapper
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
f.mesh != nullptr, "The hydrostatic kernel requires a mesh."
|
||||
);
|
||||
MFEM_VERIFY(f.mesh != nullptr, "The hydrostatic kernel requires a mesh.");
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.enthalpyFes != nullptr, "The hydrostatic kernel requires the "
|
||||
@@ -71,9 +61,8 @@ namespace {
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.gravityPotentialFes != nullptr,
|
||||
"The hydrostatic kernel requires the "
|
||||
"gravity-potential finite-element space."
|
||||
f.gravityPotentialFes != nullptr, "The hydrostatic kernel requires the "
|
||||
"gravity-potential finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
@@ -82,33 +71,28 @@ namespace {
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.compactificationFes != nullptr,
|
||||
"The hydrostatic kernel requires the "
|
||||
"compactification finite-element space."
|
||||
f.compactificationFes != nullptr, "The hydrostatic kernel requires the "
|
||||
"compactification finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.compactificationCoordinate != nullptr,
|
||||
"The hydrostatic kernel requires the "
|
||||
"compactification coordinate."
|
||||
f.compactificationCoordinate != nullptr, "The hydrostatic kernel requires the "
|
||||
"compactification coordinate."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr,
|
||||
"The hydrostatic kernel requires the "
|
||||
"quadrature-rule factory."
|
||||
f.quadratureFactory != nullptr, "The hydrostatic kernel requires the "
|
||||
"quadrature-rule factory."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.mesh->Dimension() == 3,
|
||||
"The rigid-rotation hydrostatic kernel "
|
||||
"currently requires a three-dimensional mesh."
|
||||
f.mesh->Dimension() == 3, "The rigid-rotation hydrostatic kernel "
|
||||
"currently requires a three-dimensional mesh."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
domainMapper.GetDimension() == f.mesh->Dimension(),
|
||||
"The domain-mapper dimension does not match "
|
||||
"the mesh dimension."
|
||||
domainMapper.GetDimension() == f.mesh->Dimension(), "The domain-mapper dimension does not match "
|
||||
"the mesh dimension."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -118,69 +102,51 @@ namespace {
|
||||
const mfem::FiniteElement &potentialElement,
|
||||
const mfem::ElementTransformation &transformation
|
||||
) {
|
||||
using EnthalpyField =
|
||||
mean_field::field::Field<mean_field::field::Enthalpy>;
|
||||
using EnthalpyField = mean_field::field::Field<mean_field::field::Enthalpy>;
|
||||
|
||||
MFEM_VERIFY(
|
||||
enthalpyElement.GetOrder() ==
|
||||
mean_field::field::Enthalpy::Scalar::familyOrder,
|
||||
enthalpyElement.GetOrder() == mean_field::field::Enthalpy::Scalar::familyOrder,
|
||||
"The hydrostatic test element does not match "
|
||||
"the registered enthalpy field."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
potentialElement.GetOrder() ==
|
||||
mean_field::field::Gravity::Potential::familyOrder,
|
||||
potentialElement.GetOrder() == mean_field::field::Gravity::Potential::familyOrder,
|
||||
"The hydrostatic potential element does not "
|
||||
"match the registered gravity-potential field."
|
||||
);
|
||||
|
||||
const auto enthalpyQuery = EnthalpyField::make_query<
|
||||
mean_field::field::Enthalpy::Form::EquilibriumEnthalpy>(
|
||||
mean_field::quadrature::QuadratureRole::discretization,
|
||||
transformation.OrderW(), {}, mean_field::utils::DOMAINS::STELLAR,
|
||||
mean_field::quadrature::MappingKind::general
|
||||
const auto enthalpyQuery = EnthalpyField::make_query<mean_field::field::Enthalpy::Form::EquilibriumEnthalpy>(
|
||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), {},
|
||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
|
||||
const auto gravityQuery = EnthalpyField::make_query<
|
||||
mean_field::field::Enthalpy::Form::EquilibriumGravity>(
|
||||
mean_field::quadrature::QuadratureRole::discretization,
|
||||
transformation.OrderW(), {}, mean_field::utils::DOMAINS::STELLAR,
|
||||
mean_field::quadrature::MappingKind::general
|
||||
const auto gravityQuery = EnthalpyField::make_query<mean_field::field::Enthalpy::Form::EquilibriumGravity>(
|
||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), {},
|
||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
|
||||
const auto rotationQuery = EnthalpyField::make_query<
|
||||
mean_field::field::Enthalpy::Form::EquilibriumRotation>(
|
||||
mean_field::quadrature::QuadratureRole::discretization,
|
||||
transformation.OrderW(), std::array<int, 1>{2},
|
||||
mean_field::utils::DOMAINS::STELLAR,
|
||||
mean_field::quadrature::MappingKind::general
|
||||
const auto rotationQuery = EnthalpyField::make_query<mean_field::field::Enthalpy::Form::EquilibriumRotation>(
|
||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), std::array<int, 1>{2},
|
||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
|
||||
const auto constantQuery = EnthalpyField::make_query<
|
||||
mean_field::field::Enthalpy::Form::EquilibriumConstant>(
|
||||
mean_field::quadrature::QuadratureRole::discretization,
|
||||
transformation.OrderW(), {}, mean_field::utils::DOMAINS::STELLAR,
|
||||
mean_field::quadrature::MappingKind::general
|
||||
const auto constantQuery = EnthalpyField::make_query<mean_field::field::Enthalpy::Form::EquilibriumConstant>(
|
||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), {},
|
||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
|
||||
int integrationOrder = 0;
|
||||
|
||||
const auto update_order = [&f, &transformation, &integrationOrder](
|
||||
const mean_field::quadrature::Query &query
|
||||
) {
|
||||
const auto rule = f.quadratureFactory->get(
|
||||
query, transformation.GetGeometryType()
|
||||
);
|
||||
const auto update_order = [&f, &transformation, &integrationOrder](const mean_field::quadrature::Query &query) {
|
||||
const auto rule = f.quadratureFactory->get(query, transformation.GetGeometryType());
|
||||
|
||||
MFEM_VERIFY(
|
||||
rule.integration_rule != nullptr,
|
||||
"The quadrature policy did not return "
|
||||
"a hydrostatic-equilibrium rule."
|
||||
rule.integration_rule != nullptr, "The quadrature policy did not return "
|
||||
"a hydrostatic-equilibrium rule."
|
||||
);
|
||||
|
||||
integrationOrder =
|
||||
std::max(integrationOrder, rule.resolution.order);
|
||||
integrationOrder = std::max(integrationOrder, rule.resolution.order);
|
||||
};
|
||||
|
||||
update_order(enthalpyQuery);
|
||||
@@ -188,9 +154,7 @@ namespace {
|
||||
update_order(rotationQuery);
|
||||
update_order(constantQuery);
|
||||
|
||||
return mfem::IntRules.Get(
|
||||
transformation.GetGeometryType(), integrationOrder
|
||||
);
|
||||
return mfem::IntRules.Get(transformation.GetGeometryType(), integrationOrder);
|
||||
}
|
||||
|
||||
struct HydrostaticAssemblyRequest {
|
||||
@@ -219,81 +183,64 @@ namespace {
|
||||
validate_fem(f, domainMapper);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The hydrostatic displacement vector has "
|
||||
"the wrong size."
|
||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(), "The hydrostatic displacement vector has "
|
||||
"the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(request.bernoulliConstant),
|
||||
"The Bernoulli constant is non-finite."
|
||||
);
|
||||
MFEM_VERIFY(std::isfinite(request.bernoulliConstant), "The Bernoulli constant is non-finite.");
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(request.constantVariation),
|
||||
"The Bernoulli-constant variation is non-finite."
|
||||
);
|
||||
MFEM_VERIFY(std::isfinite(request.constantVariation), "The Bernoulli-constant variation is non-finite.");
|
||||
|
||||
const bool requiresBaseState =
|
||||
request.buildResidual ||
|
||||
request.displacementVariationTrue != nullptr;
|
||||
const bool requiresBaseState = request.buildResidual || request.displacementVariationTrue != nullptr;
|
||||
|
||||
if (requiresBaseState) {
|
||||
MFEM_VERIFY(
|
||||
request.rotation != nullptr,
|
||||
"The hydrostatic residual or geometry "
|
||||
"action requires the rotation model."
|
||||
request.rotation != nullptr, "The hydrostatic residual or geometry "
|
||||
"action requires the rotation model."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
request.baseEnthalpyTrue != nullptr,
|
||||
"The hydrostatic residual or geometry "
|
||||
"action requires the base enthalpy."
|
||||
request.baseEnthalpyTrue != nullptr, "The hydrostatic residual or geometry "
|
||||
"action requires the base enthalpy."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
request.basePotentialTrue != nullptr,
|
||||
"The hydrostatic residual or geometry "
|
||||
"action requires the base potential."
|
||||
request.basePotentialTrue != nullptr, "The hydrostatic residual or geometry "
|
||||
"action requires the base potential."
|
||||
);
|
||||
}
|
||||
|
||||
if (request.baseEnthalpyTrue != nullptr) {
|
||||
MFEM_VERIFY(
|
||||
request.baseEnthalpyTrue->Size() ==
|
||||
f.enthalpyFes->GetTrueVSize(),
|
||||
request.baseEnthalpyTrue->Size() == f.enthalpyFes->GetTrueVSize(),
|
||||
"The base enthalpy vector has the wrong size."
|
||||
);
|
||||
}
|
||||
|
||||
if (request.basePotentialTrue != nullptr) {
|
||||
MFEM_VERIFY(
|
||||
request.basePotentialTrue->Size() ==
|
||||
f.gravityPotentialFes->GetTrueVSize(),
|
||||
request.basePotentialTrue->Size() == f.gravityPotentialFes->GetTrueVSize(),
|
||||
"The base potential vector has the wrong size."
|
||||
);
|
||||
}
|
||||
|
||||
if (request.enthalpyVariationTrue != nullptr) {
|
||||
MFEM_VERIFY(
|
||||
request.enthalpyVariationTrue->Size() ==
|
||||
f.enthalpyFes->GetTrueVSize(),
|
||||
request.enthalpyVariationTrue->Size() == f.enthalpyFes->GetTrueVSize(),
|
||||
"The enthalpy variation has the wrong size."
|
||||
);
|
||||
}
|
||||
|
||||
if (request.potentialVariationTrue != nullptr) {
|
||||
MFEM_VERIFY(
|
||||
request.potentialVariationTrue->Size() ==
|
||||
f.gravityPotentialFes->GetTrueVSize(),
|
||||
request.potentialVariationTrue->Size() == f.gravityPotentialFes->GetTrueVSize(),
|
||||
"The potential variation has the wrong size."
|
||||
);
|
||||
}
|
||||
|
||||
if (request.displacementVariationTrue != nullptr) {
|
||||
MFEM_VERIFY(
|
||||
request.displacementVariationTrue->Size() ==
|
||||
f.displacementFes->GetTrueVSize(),
|
||||
request.displacementVariationTrue->Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The displacement variation has the wrong size."
|
||||
);
|
||||
}
|
||||
@@ -308,46 +255,30 @@ namespace {
|
||||
mfem::Vector displacementVariationLocal;
|
||||
|
||||
if (request.baseEnthalpyTrue != nullptr) {
|
||||
true_to_local(
|
||||
*f.enthalpyFes, *request.baseEnthalpyTrue, baseEnthalpyLocal
|
||||
);
|
||||
true_to_local(*f.enthalpyFes, *request.baseEnthalpyTrue, baseEnthalpyLocal);
|
||||
}
|
||||
|
||||
if (request.basePotentialTrue != nullptr) {
|
||||
true_to_local(
|
||||
*f.gravityPotentialFes, *request.basePotentialTrue,
|
||||
basePotentialLocal
|
||||
);
|
||||
true_to_local(*f.gravityPotentialFes, *request.basePotentialTrue, basePotentialLocal);
|
||||
}
|
||||
|
||||
if (request.enthalpyVariationTrue != nullptr) {
|
||||
true_to_local(
|
||||
*f.enthalpyFes, *request.enthalpyVariationTrue,
|
||||
enthalpyVariationLocal
|
||||
);
|
||||
true_to_local(*f.enthalpyFes, *request.enthalpyVariationTrue, enthalpyVariationLocal);
|
||||
}
|
||||
|
||||
if (request.potentialVariationTrue != nullptr) {
|
||||
true_to_local(
|
||||
*f.gravityPotentialFes, *request.potentialVariationTrue,
|
||||
potentialVariationLocal
|
||||
);
|
||||
true_to_local(*f.gravityPotentialFes, *request.potentialVariationTrue, potentialVariationLocal);
|
||||
}
|
||||
|
||||
if (request.displacementVariationTrue != nullptr) {
|
||||
true_to_local(
|
||||
*f.displacementFes, *request.displacementVariationTrue,
|
||||
displacementVariationLocal
|
||||
);
|
||||
true_to_local(*f.displacementFes, *request.displacementVariationTrue, displacementVariationLocal);
|
||||
}
|
||||
|
||||
mfem::Vector localResult(f.enthalpyFes->GetVSize());
|
||||
|
||||
localResult = 0.0;
|
||||
|
||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(
|
||||
f.mesh->Dimension()
|
||||
);
|
||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
||||
|
||||
mfem::Array<int> enthalpyDofs;
|
||||
mfem::Array<int> potentialDofs;
|
||||
@@ -369,33 +300,26 @@ namespace {
|
||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
||||
|
||||
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
||||
mfem::ElementTransformation *transformation =
|
||||
f.mesh->GetElementTransformation(elementId);
|
||||
mfem::ElementTransformation *transformation = f.mesh->GetElementTransformation(elementId);
|
||||
|
||||
MFEM_VERIFY(
|
||||
transformation != nullptr,
|
||||
"The hydrostatic kernel received a null "
|
||||
"element transformation."
|
||||
transformation != nullptr, "The hydrostatic kernel received a null "
|
||||
"element transformation."
|
||||
);
|
||||
|
||||
if (transformation->Attribute == vacuumAttribute) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &enthalpyElement =
|
||||
*f.enthalpyFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &enthalpyElement = *f.enthalpyFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &potentialElement =
|
||||
*f.gravityPotentialFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &potentialElement = *f.gravityPotentialFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &displacementElement =
|
||||
*f.displacementFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &displacementElement = *f.displacementFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &compactificationElement =
|
||||
*f.compactificationFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &compactificationElement = *f.compactificationFes->GetFE(elementId);
|
||||
|
||||
mfem::DofTransformation *enthalpyDofTransformation =
|
||||
f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
||||
mfem::DofTransformation *enthalpyDofTransformation = f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
||||
|
||||
mfem::DofTransformation *potentialDofTransformation =
|
||||
f.gravityPotentialFes->GetElementDofs(elementId, potentialDofs);
|
||||
@@ -404,119 +328,82 @@ namespace {
|
||||
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
||||
|
||||
mfem::DofTransformation *compactificationDofTransformation =
|
||||
f.compactificationFes->GetElementDofs(
|
||||
elementId, compactificationDofs
|
||||
);
|
||||
f.compactificationFes->GetElementDofs(elementId, compactificationDofs);
|
||||
|
||||
displacementLocal.GetSubVector(
|
||||
displacementDofs, elementDisplacement
|
||||
);
|
||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||
|
||||
f.compactificationCoordinate->GetSubVector(
|
||||
compactificationDofs, elementCompactification
|
||||
);
|
||||
f.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
||||
|
||||
if (request.baseEnthalpyTrue != nullptr) {
|
||||
baseEnthalpyLocal.GetSubVector(
|
||||
enthalpyDofs, elementBaseEnthalpy
|
||||
);
|
||||
baseEnthalpyLocal.GetSubVector(enthalpyDofs, elementBaseEnthalpy);
|
||||
}
|
||||
|
||||
if (request.basePotentialTrue != nullptr) {
|
||||
basePotentialLocal.GetSubVector(
|
||||
potentialDofs, elementBasePotential
|
||||
);
|
||||
basePotentialLocal.GetSubVector(potentialDofs, elementBasePotential);
|
||||
}
|
||||
|
||||
if (request.enthalpyVariationTrue != nullptr) {
|
||||
enthalpyVariationLocal.GetSubVector(
|
||||
enthalpyDofs, elementEnthalpyVariation
|
||||
);
|
||||
enthalpyVariationLocal.GetSubVector(enthalpyDofs, elementEnthalpyVariation);
|
||||
}
|
||||
|
||||
if (request.potentialVariationTrue != nullptr) {
|
||||
potentialVariationLocal.GetSubVector(
|
||||
potentialDofs, elementPotentialVariation
|
||||
);
|
||||
potentialVariationLocal.GetSubVector(potentialDofs, elementPotentialVariation);
|
||||
}
|
||||
|
||||
if (request.displacementVariationTrue != nullptr) {
|
||||
displacementVariationLocal.GetSubVector(
|
||||
displacementDofs, elementDisplacementVariation
|
||||
);
|
||||
displacementVariationLocal.GetSubVector(displacementDofs, elementDisplacementVariation);
|
||||
}
|
||||
|
||||
if (enthalpyDofTransformation != nullptr) {
|
||||
if (request.baseEnthalpyTrue != nullptr) {
|
||||
enthalpyDofTransformation->InvTransformPrimal(
|
||||
elementBaseEnthalpy
|
||||
);
|
||||
enthalpyDofTransformation->InvTransformPrimal(elementBaseEnthalpy);
|
||||
}
|
||||
|
||||
if (request.enthalpyVariationTrue != nullptr) {
|
||||
enthalpyDofTransformation->InvTransformPrimal(
|
||||
elementEnthalpyVariation
|
||||
);
|
||||
enthalpyDofTransformation->InvTransformPrimal(elementEnthalpyVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (potentialDofTransformation != nullptr) {
|
||||
if (request.basePotentialTrue != nullptr) {
|
||||
potentialDofTransformation->InvTransformPrimal(
|
||||
elementBasePotential
|
||||
);
|
||||
potentialDofTransformation->InvTransformPrimal(elementBasePotential);
|
||||
}
|
||||
|
||||
if (request.potentialVariationTrue != nullptr) {
|
||||
potentialDofTransformation->InvTransformPrimal(
|
||||
elementPotentialVariation
|
||||
);
|
||||
potentialDofTransformation->InvTransformPrimal(elementPotentialVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->InvTransformPrimal(
|
||||
elementDisplacement
|
||||
);
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
||||
|
||||
if (request.displacementVariationTrue != nullptr) {
|
||||
displacementDofTransformation->InvTransformPrimal(
|
||||
elementDisplacementVariation
|
||||
);
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacementVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (compactificationDofTransformation != nullptr) {
|
||||
compactificationDofTransformation->InvTransformPrimal(
|
||||
elementCompactification
|
||||
);
|
||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
||||
}
|
||||
|
||||
const mean_field::mapping::ElementDisplacementData
|
||||
displacementData = mean_field::mapping::
|
||||
ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacement
|
||||
);
|
||||
const mean_field::mapping::ElementDisplacementData displacementData =
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
||||
|
||||
const mean_field::mapping::ElementCompactificationData
|
||||
compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
const mean_field::mapping::ElementCompactificationData compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
|
||||
const mean_field::mapping::ElementMappingData mappingData{
|
||||
.displacement = displacementData,
|
||||
.compactification = compactificationData
|
||||
.displacement = displacementData, .compactification = compactificationData
|
||||
};
|
||||
|
||||
std::optional<mean_field::mapping::ElementDisplacementData>
|
||||
displacementVariationData;
|
||||
std::optional<mean_field::mapping::ElementDisplacementData> displacementVariationData;
|
||||
|
||||
if (request.displacementVariationTrue != nullptr) {
|
||||
displacementVariationData.emplace(
|
||||
mean_field::mapping::
|
||||
ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacementVariation
|
||||
)
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacementVariation
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -528,32 +415,25 @@ namespace {
|
||||
|
||||
potentialShape.SetSize(potentialElement.GetDof());
|
||||
|
||||
const mfem::IntegrationRule &integrationRule = get_hydrostatic_rule(
|
||||
f, enthalpyElement, potentialElement, *transformation
|
||||
);
|
||||
const mfem::IntegrationRule &integrationRule =
|
||||
get_hydrostatic_rule(f, enthalpyElement, potentialElement, *transformation);
|
||||
|
||||
for (int quadraturePoint = 0;
|
||||
quadraturePoint < integrationRule.GetNPoints();
|
||||
++quadraturePoint) {
|
||||
const mfem::IntegrationPoint &integrationPoint =
|
||||
integrationRule.IntPoint(quadraturePoint);
|
||||
for (int quadraturePoint = 0; quadraturePoint < integrationRule.GetNPoints(); ++quadraturePoint) {
|
||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadraturePoint);
|
||||
|
||||
transformation->SetIntPoint(&integrationPoint);
|
||||
|
||||
mean_field::mapping::VolumeMappingContext mappingContext;
|
||||
|
||||
const mean_field::mapping::MappingStatus mappingStatus =
|
||||
domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint,
|
||||
workspace, mappingContext
|
||||
);
|
||||
const mean_field::mapping::MappingStatus mappingStatus = domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
mappingStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"The base mapping is invalid in the "
|
||||
"hydrostatic kernel. Element: "
|
||||
<< elementId
|
||||
<< ", quadrature point: " << quadraturePoint
|
||||
<< elementId << ", quadrature point: " << quadraturePoint
|
||||
<< ", status: " << static_cast<int>(mappingStatus)
|
||||
);
|
||||
|
||||
@@ -564,27 +444,18 @@ namespace {
|
||||
double baseIntegrand = 0.0;
|
||||
|
||||
if (requiresBaseState) {
|
||||
const double enthalpyValue =
|
||||
elementBaseEnthalpy * enthalpyShape;
|
||||
const double enthalpyValue = elementBaseEnthalpy * enthalpyShape;
|
||||
|
||||
const double potentialValue =
|
||||
elementBasePotential * potentialShape;
|
||||
const double potentialValue = elementBasePotential * potentialShape;
|
||||
|
||||
const double rotationPotential =
|
||||
request.rotation->potential(
|
||||
mappingContext.mapping.physical_position
|
||||
);
|
||||
request.rotation->potential(mappingContext.mapping.physical_position);
|
||||
|
||||
baseIntegrand = enthalpyValue + potentialValue -
|
||||
rotationPotential -
|
||||
request.bernoulliConstant;
|
||||
baseIntegrand = enthalpyValue + potentialValue - rotationPotential - request.bernoulliConstant;
|
||||
}
|
||||
|
||||
if (request.buildResidual) {
|
||||
elementResult.Add(
|
||||
mappingContext.quadrature.weight * baseIntegrand,
|
||||
enthalpyShape
|
||||
);
|
||||
elementResult.Add(mappingContext.quadrature.weight * baseIntegrand, enthalpyShape);
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -592,45 +463,35 @@ namespace {
|
||||
double materialVariation = -request.constantVariation;
|
||||
|
||||
if (request.enthalpyVariationTrue != nullptr) {
|
||||
materialVariation +=
|
||||
elementEnthalpyVariation * enthalpyShape;
|
||||
materialVariation += elementEnthalpyVariation * enthalpyShape;
|
||||
}
|
||||
|
||||
if (request.potentialVariationTrue != nullptr) {
|
||||
materialVariation +=
|
||||
elementPotentialVariation * potentialShape;
|
||||
materialVariation += elementPotentialVariation * potentialShape;
|
||||
}
|
||||
|
||||
double weightedVariation =
|
||||
mappingContext.quadrature.weight * materialVariation;
|
||||
double weightedVariation = mappingContext.quadrature.weight * materialVariation;
|
||||
|
||||
if (request.displacementVariationTrue != nullptr) {
|
||||
mean_field::mapping::VolumeMappingVariation
|
||||
mappingVariation;
|
||||
mean_field::mapping::VolumeMappingVariation mappingVariation;
|
||||
|
||||
const mean_field::mapping::MappingStatus variationStatus =
|
||||
domainMapper.EvaluateVolumeVariation(
|
||||
mappingData, *displacementVariationData,
|
||||
*transformation, integrationPoint, mappingContext,
|
||||
workspace, mappingVariation
|
||||
);
|
||||
const mean_field::mapping::MappingStatus variationStatus = domainMapper.EvaluateVolumeVariation(
|
||||
mappingData, *displacementVariationData, *transformation, integrationPoint, mappingContext,
|
||||
workspace, mappingVariation
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
variationStatus ==
|
||||
mean_field::mapping::MappingStatus::valid,
|
||||
variationStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"The mapping variation is invalid "
|
||||
"in the hydrostatic kernel."
|
||||
);
|
||||
|
||||
const double rotationVariation =
|
||||
request.rotation->potential_directional_derivative(
|
||||
mappingContext.mapping.physical_position,
|
||||
mappingVariation.mapping.physical_position_variation
|
||||
);
|
||||
const double rotationVariation = request.rotation->potential_directional_derivative(
|
||||
mappingContext.mapping.physical_position, mappingVariation.mapping.physical_position_variation
|
||||
);
|
||||
|
||||
weightedVariation +=
|
||||
baseIntegrand * mappingVariation.weight_variation -
|
||||
rotationVariation * mappingContext.quadrature.weight;
|
||||
weightedVariation += baseIntegrand * mappingVariation.weight_variation -
|
||||
rotationVariation * mappingContext.quadrature.weight;
|
||||
}
|
||||
|
||||
elementResult.Add(weightedVariation, enthalpyShape);
|
||||
@@ -666,9 +527,7 @@ namespace mean_field::operators::kernels {
|
||||
request.bernoulliConstant = bernoulliConstant;
|
||||
request.buildResidual = true;
|
||||
|
||||
assemble_hydrostatic_form(
|
||||
f, domainMapper, displacementTrue, request, residual
|
||||
);
|
||||
assemble_hydrostatic_form(f, domainMapper, displacementTrue, request, residual);
|
||||
}
|
||||
|
||||
void apply_hydrostatic_equilibrium_enthalpy_action(
|
||||
@@ -682,9 +541,7 @@ namespace mean_field::operators::kernels {
|
||||
|
||||
request.enthalpyVariationTrue = &enthalpyVariationTrue;
|
||||
|
||||
assemble_hydrostatic_form(
|
||||
f, domainMapper, displacementTrue, request, action
|
||||
);
|
||||
assemble_hydrostatic_form(f, domainMapper, displacementTrue, request, action);
|
||||
}
|
||||
|
||||
void apply_hydrostatic_equilibrium_potential_action(
|
||||
@@ -698,9 +555,7 @@ namespace mean_field::operators::kernels {
|
||||
|
||||
request.potentialVariationTrue = &potentialVariationTrue;
|
||||
|
||||
assemble_hydrostatic_form(
|
||||
f, domainMapper, displacementTrue, request, action
|
||||
);
|
||||
assemble_hydrostatic_form(f, domainMapper, displacementTrue, request, action);
|
||||
}
|
||||
|
||||
void apply_hydrostatic_equilibrium_constant_action(
|
||||
@@ -714,9 +569,7 @@ namespace mean_field::operators::kernels {
|
||||
|
||||
request.constantVariation = constantVariation;
|
||||
|
||||
assemble_hydrostatic_form(
|
||||
f, domainMapper, displacementTrue, request, action
|
||||
);
|
||||
assemble_hydrostatic_form(f, domainMapper, displacementTrue, request, action);
|
||||
}
|
||||
|
||||
void apply_hydrostatic_equilibrium_displacement_action(
|
||||
@@ -738,9 +591,7 @@ namespace mean_field::operators::kernels {
|
||||
request.displacementVariationTrue = &displacementVariationTrue;
|
||||
request.bernoulliConstant = baseBernoulliConstant;
|
||||
|
||||
assemble_hydrostatic_form(
|
||||
f, domainMapper, baseDisplacementTrue, request, action
|
||||
);
|
||||
assemble_hydrostatic_form(f, domainMapper, baseDisplacementTrue, request, action);
|
||||
}
|
||||
|
||||
void apply_hydrostatic_equilibrium_action(
|
||||
@@ -768,8 +619,6 @@ namespace mean_field::operators::kernels {
|
||||
request.bernoulliConstant = baseBernoulliConstant;
|
||||
request.constantVariation = constantVariation;
|
||||
|
||||
assemble_hydrostatic_form(
|
||||
f, domainMapper, baseDisplacementTrue, request, action
|
||||
);
|
||||
assemble_hydrostatic_form(f, domainMapper, baseDisplacementTrue, request, action);
|
||||
}
|
||||
} // namespace mean_field::operators::kernels
|
||||
@@ -3,6 +3,7 @@ module;
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
@@ -11,20 +12,20 @@ module mean_field;
|
||||
import :operators.kernels.pressure_force;
|
||||
|
||||
namespace {
|
||||
enum class PressureForceAction { residual, enthalpy, displacement };
|
||||
|
||||
void true_to_local(
|
||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||
const mfem::Vector &trueVector,
|
||||
mfem::Vector &localVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
trueVector.Size() == finiteElementSpace.GetTrueVSize(),
|
||||
"The pressure-force true vector has the wrong size."
|
||||
trueVector.Size() == finiteElementSpace.GetTrueVSize(), "The pressure-force true vector has the wrong size."
|
||||
);
|
||||
|
||||
localVector.SetSize(finiteElementSpace.GetVSize());
|
||||
|
||||
const mfem::Operator *prolongation =
|
||||
finiteElementSpace.GetProlongationMatrix();
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->Mult(trueVector, localVector);
|
||||
@@ -39,15 +40,13 @@ namespace {
|
||||
mfem::Vector &trueVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
localVector.Size() == finiteElementSpace.GetVSize(),
|
||||
"The pressure-force local vector has the wrong size."
|
||||
localVector.Size() == finiteElementSpace.GetVSize(), "The pressure-force local vector has the wrong size."
|
||||
);
|
||||
|
||||
trueVector.SetSize(finiteElementSpace.GetTrueVSize());
|
||||
trueVector = 0.0;
|
||||
trueVector = 0.0;
|
||||
|
||||
const mfem::Operator *prolongation =
|
||||
finiteElementSpace.GetProlongationMatrix();
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->MultTranspose(localVector, trueVector);
|
||||
@@ -68,15 +67,14 @@ namespace {
|
||||
}
|
||||
|
||||
if (ordering == mfem::Ordering::byVDIM) {
|
||||
return component + scalarDof * dimension;
|
||||
return scalarDof * dimension + component;
|
||||
}
|
||||
|
||||
MFEM_ABORT("The displacement space uses an unsupported ordering.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
[[nodiscard]] int get_pressure_extra_order(
|
||||
const mean_field::physics::PolytropicBarotrope &barotrope
|
||||
) {
|
||||
[[nodiscard]] int get_pressure_extra_order(const mean_field::eos::Polytrope &barotrope) {
|
||||
/*
|
||||
* Pressure has the enthalpy dependence
|
||||
*
|
||||
@@ -87,15 +85,11 @@ namespace {
|
||||
* contribution is therefore n times that order.
|
||||
*/
|
||||
const double extraOrder =
|
||||
barotrope.polytropic_index() *
|
||||
static_cast<double>(
|
||||
mean_field::field::Enthalpy::Scalar::familyOrder
|
||||
);
|
||||
barotrope.polytropic_index() * static_cast<double>(mean_field::field::Enthalpy::Scalar::familyOrder);
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(extraOrder) && extraOrder >= 0.0 &&
|
||||
extraOrder <=
|
||||
static_cast<double>(std::numeric_limits<int>::max()),
|
||||
extraOrder <= static_cast<double>(std::numeric_limits<int>::max()),
|
||||
"The pressure EOS effective polynomial order is invalid."
|
||||
);
|
||||
|
||||
@@ -104,44 +98,37 @@ namespace {
|
||||
|
||||
[[nodiscard]] const mfem::IntegrationRule &get_pressure_force_rule(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::physics::PolytropicBarotrope &barotrope,
|
||||
const mean_field::eos::Polytrope &barotrope,
|
||||
const mfem::FiniteElement &enthalpyElement,
|
||||
const mfem::FiniteElement &displacementElement,
|
||||
const mfem::ElementTransformation &transformation
|
||||
) {
|
||||
using EnthalpyField =
|
||||
mean_field::field::Field<mean_field::field::Enthalpy>;
|
||||
using EnthalpyField = mean_field::field::Field<mean_field::field::Enthalpy>;
|
||||
|
||||
MFEM_VERIFY(
|
||||
enthalpyElement.GetOrder() ==
|
||||
mean_field::field::Enthalpy::Scalar::familyOrder,
|
||||
enthalpyElement.GetOrder() == mean_field::field::Enthalpy::Scalar::familyOrder,
|
||||
"The pressure-force enthalpy element does not match the "
|
||||
"registered enthalpy field."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementElement.GetOrder() ==
|
||||
mean_field::field::Displacement::Vector::familyOrder,
|
||||
displacementElement.GetOrder() == mean_field::field::Displacement::Vector::familyOrder,
|
||||
"The pressure-force test element does not match the "
|
||||
"registered displacement field."
|
||||
);
|
||||
|
||||
const mean_field::quadrature::Query query = EnthalpyField::make_query<
|
||||
mean_field::field::Enthalpy::Form::PressureForce>(
|
||||
mean_field::quadrature::QuadratureRole::discretization,
|
||||
transformation.OrderW(),
|
||||
std::array<int, 1>{get_pressure_extra_order(barotrope)},
|
||||
mean_field::utils::DOMAINS::STELLAR,
|
||||
mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
const mean_field::quadrature::Query query =
|
||||
EnthalpyField::make_query<mean_field::field::Enthalpy::Form::PressureForce>(
|
||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(),
|
||||
std::array<int, 1>{get_pressure_extra_order(barotrope)}, mean_field::utils::DOMAINS::STELLAR,
|
||||
mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
|
||||
const mean_field::quadrature::MfemRule rule =
|
||||
f.quadratureFactory->get(query, transformation.GetGeometryType());
|
||||
const mean_field::quadrature::MfemRule rule = f.quadratureFactory->get(query, transformation.GetGeometryType());
|
||||
|
||||
MFEM_VERIFY(
|
||||
rule.integration_rule != nullptr,
|
||||
"The quadrature policy did not return a pressure-force "
|
||||
"integration rule."
|
||||
rule.integration_rule != nullptr, "The quadrature policy did not return a pressure-force "
|
||||
"integration rule."
|
||||
);
|
||||
|
||||
return *rule.integration_rule;
|
||||
@@ -153,38 +140,31 @@ namespace {
|
||||
const mfem::Vector &enthalpyTrue,
|
||||
const mfem::Vector &displacementTrue
|
||||
) {
|
||||
MFEM_VERIFY(f.mesh != nullptr, "The pressure-force kernel requires a mesh.");
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.mesh != nullptr, "The pressure-force kernel requires a mesh."
|
||||
f.enthalpyFes != nullptr, "The pressure-force kernel requires the enthalpy "
|
||||
"finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.enthalpyFes != nullptr,
|
||||
"The pressure-force kernel requires the enthalpy "
|
||||
"finite-element space."
|
||||
f.displacementFes != nullptr, "The pressure-force kernel requires the displacement "
|
||||
"finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr,
|
||||
"The pressure-force kernel requires the displacement "
|
||||
"finite-element space."
|
||||
f.compactificationFes != nullptr, "The pressure-force kernel requires the compactification "
|
||||
"finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.compactificationFes != nullptr,
|
||||
"The pressure-force kernel requires the compactification "
|
||||
"finite-element space."
|
||||
f.compactificationCoordinate != nullptr, "The pressure-force kernel requires the compactification "
|
||||
"coordinate."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.compactificationCoordinate != nullptr,
|
||||
"The pressure-force kernel requires the compactification "
|
||||
"coordinate."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr,
|
||||
"The pressure-force kernel requires the quadrature "
|
||||
"rule factory."
|
||||
f.quadratureFactory != nullptr, "The pressure-force kernel requires the quadrature "
|
||||
"rule factory."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
@@ -204,73 +184,105 @@ namespace {
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes->GetVDim() == f.mesh->Dimension(),
|
||||
"The displacement vector dimension does not match the "
|
||||
"mesh dimension."
|
||||
f.displacementFes->GetVDim() == f.mesh->Dimension(), "The displacement vector dimension does not match the "
|
||||
"mesh dimension."
|
||||
);
|
||||
|
||||
/*
|
||||
* ElementDisplacementDataFromElementVDofs currently consumes the
|
||||
* registered byNODES layout. Keep this explicit so a future
|
||||
* registry change fails immediately rather than silently
|
||||
* corrupting the geometry.
|
||||
*/
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes->GetOrdering() == mfem::Ordering::byNODES,
|
||||
"The pressure-force kernel requires the registered byNODES "
|
||||
"displacement ordering."
|
||||
);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace mean_field::operators::kernels {
|
||||
void apply_pressure_force_residual(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope,
|
||||
const mfem::Vector &enthalpyTrue,
|
||||
void apply_pressure_force_action(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
||||
const mean_field::eos::Polytrope &barotrope,
|
||||
const PressureForceAction pressureForceAction,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector *enthalpyVariationTrue,
|
||||
const mfem::Vector *displacementVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &residualTrue
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
validate_inputs(f, domainMapper, enthalpyTrue, displacementTrue);
|
||||
validate_inputs(f, domainMapper, baseEnthalpyTrue, displacementTrue);
|
||||
|
||||
mfem::Vector enthalpyLocal;
|
||||
if (pressureForceAction == PressureForceAction::enthalpy) {
|
||||
MFEM_VERIFY(
|
||||
enthalpyVariationTrue != nullptr && enthalpyVariationTrue->Size() == f.enthalpyFes->GetTrueVSize(),
|
||||
"The pressure-force enthalpy variation has the wrong size."
|
||||
);
|
||||
}
|
||||
|
||||
if (pressureForceAction == PressureForceAction::displacement) {
|
||||
MFEM_VERIFY(
|
||||
displacementVariationTrue != nullptr &&
|
||||
displacementVariationTrue->Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The pressure-force displacement variation has the wrong "
|
||||
"size."
|
||||
);
|
||||
}
|
||||
|
||||
mfem::Vector baseEnthalpyLocal;
|
||||
mfem::Vector enthalpyVariationLocal;
|
||||
mfem::Vector displacementLocal;
|
||||
mfem::Vector displacementVariationLocal;
|
||||
|
||||
true_to_local(*f.enthalpyFes, enthalpyTrue, enthalpyLocal);
|
||||
true_to_local(*f.enthalpyFes, baseEnthalpyTrue, baseEnthalpyLocal);
|
||||
|
||||
if (enthalpyVariationTrue != nullptr) {
|
||||
true_to_local(*f.enthalpyFes, *enthalpyVariationTrue, enthalpyVariationLocal);
|
||||
}
|
||||
|
||||
true_to_local(*f.displacementFes, displacementTrue, displacementLocal);
|
||||
|
||||
mfem::Vector localResidual(f.displacementFes->GetVSize());
|
||||
localResidual = 0.0;
|
||||
if (displacementVariationTrue != nullptr) {
|
||||
true_to_local(*f.displacementFes, *displacementVariationTrue, displacementVariationLocal);
|
||||
}
|
||||
|
||||
mapping::DomainMapperStateless::Workspace workspace(
|
||||
f.mesh->Dimension()
|
||||
);
|
||||
mfem::Vector localAction(f.displacementFes->GetVSize());
|
||||
localAction = 0.0;
|
||||
|
||||
mfem::Array<int> enthalpyDofs;
|
||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
||||
|
||||
mfem::Array<int> enthalpyDofsofs;
|
||||
mfem::Array<int> displacementDofs;
|
||||
mfem::Array<int> compactificationDofs;
|
||||
|
||||
mfem::Vector elementEnthalpy;
|
||||
mfem::Vector elementBaseEnthalpy;
|
||||
mfem::Vector elementEnthalpyVariation;
|
||||
mfem::Vector elementDisplacement;
|
||||
mfem::Vector elementDisplacementVariation;
|
||||
mfem::Vector elementCompactification;
|
||||
mfem::Vector elementResidual;
|
||||
mfem::Vector elementAction;
|
||||
mfem::Vector enthalpyShape;
|
||||
|
||||
mfem::Array<int> enthalpyDofs;
|
||||
|
||||
mfem::DenseMatrix displacementDShapeReference;
|
||||
mfem::DenseMatrix displacementDShapePhysical;
|
||||
mfem::DenseMatrix displacementDShapePhysicalVariation;
|
||||
|
||||
mapping::VolumeMappingContext mappingContext;
|
||||
mean_field::mapping::VolumeMappingContext mappingContext;
|
||||
|
||||
const int dimension = f.mesh->Dimension();
|
||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
||||
const int dimension = f.mesh->Dimension();
|
||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
||||
|
||||
const mfem::Ordering::Type displacementOrdering =
|
||||
f.displacementFes->GetOrdering();
|
||||
const mfem::Ordering::Type displacementOrdering = f.displacementFes->GetOrdering();
|
||||
|
||||
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
||||
mfem::ElementTransformation *transformation =
|
||||
f.mesh->GetElementTransformation(elementId);
|
||||
mfem::ElementTransformation *transformation = f.mesh->GetElementTransformation(elementId);
|
||||
|
||||
MFEM_VERIFY(
|
||||
transformation != nullptr,
|
||||
"The pressure-force kernel received a null element "
|
||||
"transformation."
|
||||
transformation != nullptr, "The pressure-force kernel received a null element "
|
||||
"transformation."
|
||||
);
|
||||
|
||||
/*
|
||||
@@ -281,128 +293,131 @@ namespace mean_field::operators::kernels {
|
||||
continue;
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &enthalpyElement =
|
||||
*f.enthalpyFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &enthalpyElement = *f.enthalpyFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &displacementElement =
|
||||
*f.displacementFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &displacementElement = *f.displacementFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &compactificationElement =
|
||||
*f.compactificationFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &compactificationElement = *f.compactificationFes->GetFE(elementId);
|
||||
|
||||
mfem::DofTransformation *enthalpyDofTransformation =
|
||||
f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
||||
mfem::DofTransformation *enthalpyDofTransformation = f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
||||
|
||||
mfem::DofTransformation *displacementDofTransformation =
|
||||
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
||||
|
||||
mfem::DofTransformation *compactificationDofTransformation =
|
||||
f.compactificationFes->GetElementDofs(
|
||||
elementId, compactificationDofs
|
||||
);
|
||||
f.compactificationFes->GetElementDofs(elementId, compactificationDofs);
|
||||
|
||||
enthalpyLocal.GetSubVector(enthalpyDofs, elementEnthalpy);
|
||||
baseEnthalpyLocal.GetSubVector(enthalpyDofs, elementBaseEnthalpy);
|
||||
|
||||
displacementLocal.GetSubVector(
|
||||
displacementDofs, elementDisplacement
|
||||
);
|
||||
if (enthalpyVariationTrue != nullptr) {
|
||||
enthalpyVariationLocal.GetSubVector(enthalpyDofs, elementEnthalpyVariation);
|
||||
}
|
||||
|
||||
f.compactificationCoordinate->GetSubVector(
|
||||
compactificationDofs, elementCompactification
|
||||
);
|
||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||
|
||||
if (displacementVariationTrue != nullptr) {
|
||||
displacementVariationLocal.GetSubVector(displacementDofs, elementDisplacementVariation);
|
||||
}
|
||||
|
||||
f.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
||||
|
||||
if (enthalpyDofTransformation != nullptr) {
|
||||
enthalpyDofTransformation->InvTransformPrimal(elementEnthalpy);
|
||||
enthalpyDofTransformation->InvTransformPrimal(elementBaseEnthalpy);
|
||||
|
||||
if (enthalpyVariationTrue != nullptr) {
|
||||
enthalpyDofTransformation->InvTransformPrimal(elementEnthalpyVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->InvTransformPrimal(
|
||||
elementDisplacement
|
||||
);
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
||||
|
||||
if (displacementVariationTrue != nullptr) {
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacementVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (compactificationDofTransformation != nullptr) {
|
||||
compactificationDofTransformation->InvTransformPrimal(
|
||||
elementCompactification
|
||||
);
|
||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
||||
}
|
||||
|
||||
const mapping::ElementDisplacementData displacementData =
|
||||
mapping::ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacement
|
||||
);
|
||||
const mean_field::mapping::ElementDisplacementData displacementData =
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
||||
|
||||
const mapping::ElementCompactificationData compactificationData(
|
||||
const mean_field::mapping::ElementCompactificationData compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
|
||||
const mapping::ElementMappingData mappingData{
|
||||
.displacement = displacementData,
|
||||
.compactification = compactificationData
|
||||
const mean_field::mapping::ElementMappingData mappingData{
|
||||
.displacement = displacementData, .compactification = compactificationData
|
||||
};
|
||||
|
||||
std::optional<mean_field::mapping::ElementDisplacementData> displacementVariationData;
|
||||
|
||||
if (displacementVariationTrue != nullptr) {
|
||||
displacementVariationData.emplace(
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacementVariation
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const int scalarDisplacementDofCount = displacementElement.GetDof();
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementDofs.Size() ==
|
||||
scalarDisplacementDofCount * dimension,
|
||||
displacementDofs.Size() == scalarDisplacementDofCount * dimension,
|
||||
"The pressure-force element displacement vector has "
|
||||
"the wrong size."
|
||||
);
|
||||
|
||||
enthalpyShape.SetSize(enthalpyElement.GetDof());
|
||||
|
||||
displacementDShapeReference.SetSize(
|
||||
scalarDisplacementDofCount, dimension
|
||||
);
|
||||
displacementDShapeReference.SetSize(scalarDisplacementDofCount, dimension);
|
||||
|
||||
displacementDShapePhysical.SetSize(
|
||||
scalarDisplacementDofCount, dimension
|
||||
);
|
||||
displacementDShapePhysical.SetSize(scalarDisplacementDofCount, dimension);
|
||||
|
||||
elementResidual.SetSize(displacementDofs.Size());
|
||||
elementResidual = 0.0;
|
||||
displacementDShapePhysicalVariation.SetSize(scalarDisplacementDofCount, dimension);
|
||||
|
||||
elementAction.SetSize(displacementDofs.Size());
|
||||
elementAction = 0.0;
|
||||
|
||||
const mfem::IntegrationRule &integrationRule =
|
||||
get_pressure_force_rule(
|
||||
f, barotrope, enthalpyElement, displacementElement,
|
||||
*transformation
|
||||
);
|
||||
get_pressure_force_rule(f, barotrope, enthalpyElement, displacementElement, *transformation);
|
||||
|
||||
for (int quadratureIndex = 0;
|
||||
quadratureIndex < integrationRule.GetNPoints();
|
||||
++quadratureIndex) {
|
||||
const mfem::IntegrationPoint &integrationPoint =
|
||||
integrationRule.IntPoint(quadratureIndex);
|
||||
for (int quadratureIndex = 0; quadratureIndex < integrationRule.GetNPoints(); ++quadratureIndex) {
|
||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadratureIndex);
|
||||
|
||||
transformation->SetIntPoint(&integrationPoint);
|
||||
|
||||
const mapping::MappingStatus mappingStatus =
|
||||
domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint,
|
||||
workspace, mappingContext
|
||||
);
|
||||
const mean_field::mapping::MappingStatus mappingStatus = domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
mappingStatus == mapping::MappingStatus::valid,
|
||||
mappingStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"Stateless mapping failed in the pressure-force "
|
||||
"kernel. Element: "
|
||||
<< elementId
|
||||
<< ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadratureIndex
|
||||
<< ", status: " << static_cast<int>(mappingStatus)
|
||||
<< elementId << ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadratureIndex << ", status: " << static_cast<int>(mappingStatus)
|
||||
);
|
||||
|
||||
enthalpyElement.CalcShape(integrationPoint, enthalpyShape);
|
||||
|
||||
const double enthalpyValue = elementEnthalpy * enthalpyShape;
|
||||
const double enthalpyValue = elementBaseEnthalpy * enthalpyShape;
|
||||
|
||||
const double pressureValue =
|
||||
barotrope.pressure_from_enthalpy(enthalpyValue);
|
||||
double pressureFactor = 0.0;
|
||||
|
||||
displacementElement.CalcDShape(
|
||||
integrationPoint, displacementDShapeReference
|
||||
);
|
||||
if (pressureForceAction == PressureForceAction::residual ||
|
||||
pressureForceAction == PressureForceAction::displacement) {
|
||||
pressureFactor = barotrope.pressure_from_enthalpy(enthalpyValue);
|
||||
} else {
|
||||
const double enthalpyVariationValue = elementEnthalpyVariation * enthalpyShape;
|
||||
|
||||
pressureFactor =
|
||||
barotrope.pressure_derivative_from_enthalpy(enthalpyValue) * enthalpyVariationValue;
|
||||
}
|
||||
|
||||
displacementElement.CalcDShape(integrationPoint, displacementDShapeReference);
|
||||
|
||||
/*
|
||||
* Row i of DShape is grad_reference(N_i). Multiplication
|
||||
@@ -411,17 +426,45 @@ namespace mean_field::operators::kernels {
|
||||
* grad_physical(N_i)
|
||||
* = grad_reference(N_i) J^{-1}.
|
||||
*/
|
||||
mfem::Mult(
|
||||
displacementDShapeReference,
|
||||
mappingContext.quadrature.J_inv, displacementDShapePhysical
|
||||
);
|
||||
mfem::Mult(displacementDShapeReference, mappingContext.quadrature.J_inv, displacementDShapePhysical);
|
||||
|
||||
const double weightedPressure =
|
||||
pressureValue * mappingContext.quadrature.weight;
|
||||
std::optional<mean_field::mapping::VolumeMappingVariation> mappingVariation;
|
||||
|
||||
if (pressureForceAction == PressureForceAction::displacement) {
|
||||
mappingVariation.emplace();
|
||||
|
||||
const mean_field::mapping::MappingStatus variationStatus = domainMapper.EvaluateVolumeVariation(
|
||||
mappingData, *displacementVariationData, *transformation, integrationPoint, mappingContext,
|
||||
workspace, *mappingVariation
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
variationStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"Stateless mapping variation failed in the "
|
||||
"pressure-force kernel. Element: "
|
||||
<< elementId << ", attribute: " << transformation->Attribute << ", quadrature point: "
|
||||
<< quadratureIndex << ", status: " << static_cast<int>(variationStatus)
|
||||
);
|
||||
|
||||
/*
|
||||
* Differentiating
|
||||
*
|
||||
* grad_x(N_i) = grad_reference(N_i) J^{-1}
|
||||
*
|
||||
* at the frozen base geometry gives the physical
|
||||
* test-gradient variation used by the geometric
|
||||
* pressure block.
|
||||
*/
|
||||
mfem::Mult(
|
||||
displacementDShapeReference, mappingVariation->inverse_element_jacobian_variation,
|
||||
displacementDShapePhysicalVariation
|
||||
);
|
||||
}
|
||||
|
||||
const double weightedPressureFactor = pressureFactor * mappingContext.quadrature.weight;
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(pressureValue) &&
|
||||
std::isfinite(weightedPressure),
|
||||
std::isfinite(pressureFactor) && std::isfinite(weightedPressureFactor),
|
||||
"The pressure-force kernel encountered a non-finite "
|
||||
"quadrature value."
|
||||
);
|
||||
@@ -436,29 +479,96 @@ namespace mean_field::operators::kernels {
|
||||
* R_(i,c)
|
||||
* = -integral P partial_c N_i dV.
|
||||
*/
|
||||
for (int scalarDof = 0; scalarDof < scalarDisplacementDofCount;
|
||||
++scalarDof) {
|
||||
for (int component = 0; component < dimension;
|
||||
++component) {
|
||||
for (int scalarDof = 0; scalarDof < scalarDisplacementDofCount; ++scalarDof) {
|
||||
for (int component = 0; component < dimension; ++component) {
|
||||
const int vectorDof = vector_dof_index(
|
||||
displacementOrdering, scalarDof, component,
|
||||
scalarDisplacementDofCount, dimension
|
||||
displacementOrdering, scalarDof, component, scalarDisplacementDofCount, dimension
|
||||
);
|
||||
|
||||
elementResidual(vectorDof) -=
|
||||
weightedPressure *
|
||||
displacementDShapePhysical(scalarDof, component);
|
||||
if (pressureForceAction == PressureForceAction::displacement) {
|
||||
/*
|
||||
* Differentiate the complete discrete factor
|
||||
*
|
||||
* grad_x(N_i) dV_x.
|
||||
*
|
||||
* The enthalpy DOFs, and therefore P(h), are
|
||||
* frozen in this Jacobian column.
|
||||
*/
|
||||
const double gradientWeightVariation =
|
||||
mappingContext.quadrature.weight *
|
||||
displacementDShapePhysicalVariation(scalarDof, component) +
|
||||
mappingVariation->weight_variation * displacementDShapePhysical(scalarDof, component);
|
||||
|
||||
const double contribution = pressureFactor * gradientWeightVariation;
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(gradientWeightVariation) && std::isfinite(contribution),
|
||||
"The pressure-force geometry action "
|
||||
"encountered a non-finite contribution."
|
||||
);
|
||||
|
||||
elementAction(vectorDof) -= contribution;
|
||||
} else {
|
||||
elementAction(vectorDof) -=
|
||||
weightedPressureFactor * displacementDShapePhysical(scalarDof, component);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->TransformDual(elementResidual);
|
||||
displacementDofTransformation->TransformDual(elementAction);
|
||||
}
|
||||
|
||||
localResidual.AddElementVector(displacementDofs, elementResidual);
|
||||
localAction.AddElementVector(displacementDofs, elementAction);
|
||||
}
|
||||
|
||||
local_to_true(*f.displacementFes, localResidual, residualTrue);
|
||||
local_to_true(*f.displacementFes, localAction, actionTrue);
|
||||
}
|
||||
} // namespace mean_field::operators::kernels
|
||||
} // namespace
|
||||
|
||||
namespace mean_field::operators::kernels {
|
||||
void apply_pressure_force_residual(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const eos::Polytrope &barotrope,
|
||||
const mfem::Vector &enthalpyTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &residualTrue
|
||||
) {
|
||||
apply_pressure_force_action(
|
||||
f, domainMapper, barotrope, PressureForceAction::residual, enthalpyTrue, nullptr, nullptr, displacementTrue,
|
||||
residualTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_pressure_force_enthalpy_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const eos::Polytrope &barotrope,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector &enthalpyVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_pressure_force_action(
|
||||
f, domainMapper, barotrope, PressureForceAction::enthalpy, baseEnthalpyTrue, &enthalpyVariationTrue,
|
||||
nullptr, displacementTrue, actionTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_pressure_force_displacement_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const eos::Polytrope &barotrope,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector &displacementVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_pressure_force_action(
|
||||
f, domainMapper, barotrope, PressureForceAction::displacement, baseEnthalpyTrue, nullptr,
|
||||
&displacementVariationTrue, displacementTrue, actionTrue
|
||||
);
|
||||
}
|
||||
} // namespace mean_field::operators::kernels
|
||||
|
||||
@@ -0,0 +1,590 @@
|
||||
module;
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
module mean_field;
|
||||
|
||||
import :operators.kernels.rotational_displacement_force;
|
||||
|
||||
namespace {
|
||||
enum class RotationalDisplacementForceAction { residual, density, displacement, complete };
|
||||
|
||||
void true_to_local(
|
||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||
const mfem::Vector &trueVector,
|
||||
mfem::Vector &localVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
trueVector.Size() == finiteElementSpace.GetTrueVSize(),
|
||||
"The rotational-displacement-force true vector has the wrong "
|
||||
"size."
|
||||
);
|
||||
|
||||
localVector.SetSize(finiteElementSpace.GetVSize());
|
||||
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->Mult(trueVector, localVector);
|
||||
} else {
|
||||
localVector = trueVector;
|
||||
}
|
||||
}
|
||||
|
||||
void local_to_true(
|
||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||
const mfem::Vector &localVector,
|
||||
mfem::Vector &trueVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
localVector.Size() == finiteElementSpace.GetVSize(),
|
||||
"The rotational-displacement-force local vector has the wrong "
|
||||
"size."
|
||||
);
|
||||
|
||||
trueVector.SetSize(finiteElementSpace.GetTrueVSize());
|
||||
trueVector = 0.0;
|
||||
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->MultTranspose(localVector, trueVector);
|
||||
} else {
|
||||
trueVector = localVector;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] int vector_dof_index(
|
||||
const mfem::Ordering::Type ordering,
|
||||
const int scalarDof,
|
||||
const int component,
|
||||
const int scalarDofCount,
|
||||
const int dimension
|
||||
) {
|
||||
if (ordering == mfem::Ordering::byNODES) {
|
||||
return scalarDof + component * scalarDofCount;
|
||||
}
|
||||
|
||||
if (ordering == mfem::Ordering::byVDIM) {
|
||||
return scalarDof * dimension + component;
|
||||
}
|
||||
|
||||
MFEM_ABORT(
|
||||
"The rotational-displacement-force test space uses an "
|
||||
"unsupported ordering."
|
||||
);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
[[nodiscard]] const mfem::IntegrationRule &get_rotation_force_rule(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mfem::FiniteElement &densityElement,
|
||||
const mfem::FiniteElement &displacementElement,
|
||||
const mfem::ElementTransformation &transformation
|
||||
) {
|
||||
using DisplacementField = mean_field::field::Field<mean_field::field::Displacement>;
|
||||
|
||||
MFEM_VERIFY(
|
||||
densityElement.GetOrder() == mean_field::field::Density::Scalar::familyOrder,
|
||||
"The rotational-displacement-force density element does not "
|
||||
"match the registered density field."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementElement.GetOrder() == mean_field::field::Displacement::Vector::familyOrder,
|
||||
"The rotational-displacement-force test element does not match "
|
||||
"the registered displacement field."
|
||||
);
|
||||
|
||||
/*
|
||||
* grad(Psi_rotation) is linear in physical position, so it adds one
|
||||
* dynamic polynomial-order contribution.
|
||||
*/
|
||||
const mean_field::quadrature::Query query =
|
||||
DisplacementField::make_query<mean_field::field::Displacement::Form::CentrifugalForce>(
|
||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), std::array<int, 1>{1},
|
||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
|
||||
const mean_field::quadrature::MfemRule rule = f.quadratureFactory->get(query, transformation.GetGeometryType());
|
||||
|
||||
MFEM_VERIFY(
|
||||
rule.integration_rule != nullptr, "The quadrature policy did not return a rotational-"
|
||||
"displacement-force integration rule."
|
||||
);
|
||||
|
||||
return *rule.integration_rule;
|
||||
}
|
||||
|
||||
void validate_finite_vector(
|
||||
const mfem::Vector &vector,
|
||||
const char *message
|
||||
) {
|
||||
for (int index = 0; index < vector.Size(); ++index) {
|
||||
MFEM_VERIFY(std::isfinite(vector(index)), message);
|
||||
}
|
||||
}
|
||||
|
||||
void validate_common_inputs(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
||||
const mfem::Vector &displacementTrue
|
||||
) {
|
||||
MFEM_VERIFY(f.mesh != nullptr, "The rotational-displacement-force kernel requires a mesh.");
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.mesh->Dimension() == 3, "The rotational-displacement-force kernel requires a "
|
||||
"three-dimensional mesh."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr, "The rotational-displacement-force kernel requires the density "
|
||||
"finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr, "The rotational-displacement-force kernel requires the "
|
||||
"displacement finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.compactificationFes != nullptr && f.compactificationCoordinate != nullptr,
|
||||
"The rotational-displacement-force kernel requires the "
|
||||
"compactification coordinate."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr, "The rotational-displacement-force kernel requires the "
|
||||
"quadrature-rule factory."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The rotational-displacement-force displacement vector has the "
|
||||
"wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
domainMapper.GetDimension() == f.mesh->Dimension(),
|
||||
"The rotational-displacement-force mapper dimension does not "
|
||||
"match the mesh dimension."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes->GetVDim() == f.mesh->Dimension(),
|
||||
"The rotational-displacement-force displacement dimension does "
|
||||
"not match the mesh dimension."
|
||||
);
|
||||
|
||||
validate_finite_vector(
|
||||
displacementTrue, "The rotational-displacement-force displacement contains a "
|
||||
"non-finite value."
|
||||
);
|
||||
}
|
||||
|
||||
void validate_density(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mfem::Vector &density,
|
||||
const char *message
|
||||
) {
|
||||
MFEM_VERIFY(density.Size() == f.densityFes->GetTrueVSize(), message);
|
||||
validate_finite_vector(density, message);
|
||||
}
|
||||
|
||||
void apply_rotational_displacement_force_action(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
||||
const mean_field::physics::RigidRotation &rotation,
|
||||
const RotationalDisplacementForceAction requestedAction,
|
||||
const mfem::Vector *baseDensityTrue,
|
||||
const mfem::Vector *densityVariationTrue,
|
||||
const mfem::Vector *displacementVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
validate_common_inputs(f, domainMapper, displacementTrue);
|
||||
|
||||
const bool needsBaseDensity = requestedAction == RotationalDisplacementForceAction::residual ||
|
||||
requestedAction == RotationalDisplacementForceAction::displacement ||
|
||||
requestedAction == RotationalDisplacementForceAction::complete;
|
||||
|
||||
const bool needsDensityVariation = requestedAction == RotationalDisplacementForceAction::density ||
|
||||
requestedAction == RotationalDisplacementForceAction::complete;
|
||||
|
||||
const bool needsDisplacementVariation = requestedAction == RotationalDisplacementForceAction::displacement ||
|
||||
requestedAction == RotationalDisplacementForceAction::complete;
|
||||
|
||||
if (needsBaseDensity) {
|
||||
MFEM_VERIFY(
|
||||
baseDensityTrue != nullptr, "The rotational-displacement-force action requires a base "
|
||||
"density."
|
||||
);
|
||||
|
||||
validate_density(f, *baseDensityTrue, "The rotational-displacement-force base density is invalid.");
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
MFEM_VERIFY(
|
||||
densityVariationTrue != nullptr, "The rotational-displacement-force action requires a "
|
||||
"density variation."
|
||||
);
|
||||
|
||||
validate_density(
|
||||
f, *densityVariationTrue,
|
||||
"The rotational-displacement-force density variation is "
|
||||
"invalid."
|
||||
);
|
||||
}
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
MFEM_VERIFY(
|
||||
displacementVariationTrue != nullptr &&
|
||||
displacementVariationTrue->Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The rotational-displacement-force displacement variation "
|
||||
"is invalid."
|
||||
);
|
||||
|
||||
validate_finite_vector(
|
||||
*displacementVariationTrue, "The rotational-displacement-force displacement variation "
|
||||
"contains a non-finite value."
|
||||
);
|
||||
}
|
||||
|
||||
mfem::Vector baseDensityLocal;
|
||||
mfem::Vector densityVariationLocal;
|
||||
mfem::Vector displacementLocal;
|
||||
mfem::Vector displacementVariationLocal;
|
||||
|
||||
if (needsBaseDensity) {
|
||||
true_to_local(*f.densityFes, *baseDensityTrue, baseDensityLocal);
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
true_to_local(*f.densityFes, *densityVariationTrue, densityVariationLocal);
|
||||
}
|
||||
|
||||
true_to_local(*f.displacementFes, displacementTrue, displacementLocal);
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
true_to_local(*f.displacementFes, *displacementVariationTrue, displacementVariationLocal);
|
||||
}
|
||||
|
||||
mfem::Vector localAction(f.displacementFes->GetVSize());
|
||||
localAction = 0.0;
|
||||
|
||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
||||
|
||||
mfem::Array<int> densityDofs;
|
||||
mfem::Array<int> displacementDofs;
|
||||
mfem::Array<int> compactificationDofs;
|
||||
|
||||
mfem::Vector elementBaseDensity;
|
||||
mfem::Vector elementDensityVariation;
|
||||
mfem::Vector elementDisplacement;
|
||||
mfem::Vector elementDisplacementVariation;
|
||||
mfem::Vector elementCompactification;
|
||||
mfem::Vector elementAction;
|
||||
|
||||
mfem::Vector densityShape;
|
||||
mfem::Vector displacementShape;
|
||||
mfem::Vector potentialGradient;
|
||||
mfem::Vector potentialGradientVariation;
|
||||
mfem::Vector centrifugalAcceleration;
|
||||
mfem::Vector centrifugalAccelerationVariation;
|
||||
mfem::Vector weightedForce;
|
||||
|
||||
mean_field::mapping::VolumeMappingContext mappingContext;
|
||||
mean_field::mapping::VolumeMappingVariation mappingVariation;
|
||||
|
||||
const int dimension = f.mesh->Dimension();
|
||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
||||
|
||||
const mfem::Ordering::Type displacementOrdering = f.displacementFes->GetOrdering();
|
||||
|
||||
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
||||
mfem::ElementTransformation *transformation = f.mesh->GetElementTransformation(elementId);
|
||||
|
||||
MFEM_VERIFY(
|
||||
transformation != nullptr, "The rotational-displacement-force kernel received a null "
|
||||
"element transformation."
|
||||
);
|
||||
|
||||
if (transformation->Attribute == vacuumAttribute) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &densityElement = *f.densityFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &displacementElement = *f.displacementFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &compactificationElement = *f.compactificationFes->GetFE(elementId);
|
||||
|
||||
mfem::DofTransformation *densityDofTransformation = f.densityFes->GetElementDofs(elementId, densityDofs);
|
||||
|
||||
mfem::DofTransformation *displacementDofTransformation =
|
||||
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
||||
|
||||
mfem::DofTransformation *compactificationDofTransformation =
|
||||
f.compactificationFes->GetElementDofs(elementId, compactificationDofs);
|
||||
|
||||
if (needsBaseDensity) {
|
||||
baseDensityLocal.GetSubVector(densityDofs, elementBaseDensity);
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
densityVariationLocal.GetSubVector(densityDofs, elementDensityVariation);
|
||||
}
|
||||
|
||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
displacementVariationLocal.GetSubVector(displacementDofs, elementDisplacementVariation);
|
||||
}
|
||||
|
||||
f.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
||||
|
||||
if (densityDofTransformation != nullptr) {
|
||||
if (needsBaseDensity) {
|
||||
densityDofTransformation->InvTransformPrimal(elementBaseDensity);
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
densityDofTransformation->InvTransformPrimal(elementDensityVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacementVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (compactificationDofTransformation != nullptr) {
|
||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
||||
}
|
||||
|
||||
const mean_field::mapping::ElementDisplacementData displacementData =
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
||||
|
||||
const mean_field::mapping::ElementCompactificationData compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
|
||||
const mean_field::mapping::ElementMappingData mappingData{
|
||||
.displacement = displacementData, .compactification = compactificationData
|
||||
};
|
||||
|
||||
std::optional<mean_field::mapping::ElementDisplacementData> displacementVariationData;
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
displacementVariationData.emplace(
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacementVariation
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const int scalarDisplacementDofCount = displacementElement.GetDof();
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementDofs.Size() == scalarDisplacementDofCount * dimension,
|
||||
"The rotational-displacement-force element displacement "
|
||||
"vector has the wrong size."
|
||||
);
|
||||
|
||||
densityShape.SetSize(densityElement.GetDof());
|
||||
displacementShape.SetSize(scalarDisplacementDofCount);
|
||||
potentialGradient.SetSize(dimension);
|
||||
potentialGradientVariation.SetSize(dimension);
|
||||
centrifugalAcceleration.SetSize(dimension);
|
||||
centrifugalAccelerationVariation.SetSize(dimension);
|
||||
weightedForce.SetSize(dimension);
|
||||
|
||||
elementAction.SetSize(displacementDofs.Size());
|
||||
elementAction = 0.0;
|
||||
|
||||
const mfem::IntegrationRule &integrationRule =
|
||||
get_rotation_force_rule(f, densityElement, displacementElement, *transformation);
|
||||
|
||||
for (int quadratureIndex = 0; quadratureIndex < integrationRule.GetNPoints(); ++quadratureIndex) {
|
||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadratureIndex);
|
||||
|
||||
transformation->SetIntPoint(&integrationPoint);
|
||||
|
||||
const mean_field::mapping::MappingStatus mappingStatus = domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
mappingStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"Stateless mapping failed in the rotational-"
|
||||
"displacement-force kernel. Element: "
|
||||
<< elementId << ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadratureIndex << ", status: " << static_cast<int>(mappingStatus)
|
||||
);
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
const mean_field::mapping::MappingStatus variationStatus = domainMapper.EvaluateVolumeVariation(
|
||||
mappingData, *displacementVariationData, *transformation, integrationPoint, mappingContext,
|
||||
workspace, mappingVariation
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
variationStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"Stateless mapping variation failed in the "
|
||||
"rotational-displacement-force kernel. Element: "
|
||||
<< elementId << ", attribute: " << transformation->Attribute << ", quadrature point: "
|
||||
<< quadratureIndex << ", status: " << static_cast<int>(variationStatus)
|
||||
);
|
||||
}
|
||||
|
||||
densityElement.CalcShape(integrationPoint, densityShape);
|
||||
|
||||
displacementElement.CalcShape(integrationPoint, displacementShape);
|
||||
|
||||
double baseDensityValue = 0.0;
|
||||
double densityVariationValue = 0.0;
|
||||
|
||||
if (needsBaseDensity) {
|
||||
baseDensityValue = elementBaseDensity * densityShape;
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
densityVariationValue = elementDensityVariation * densityShape;
|
||||
}
|
||||
|
||||
rotation.potential_gradient(mappingContext.mapping.physical_position, potentialGradient);
|
||||
|
||||
centrifugalAcceleration = potentialGradient;
|
||||
centrifugalAcceleration *= -1.0;
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
rotation.potential_gradient_directional_derivative(
|
||||
mappingVariation.mapping.physical_position_variation, potentialGradientVariation
|
||||
);
|
||||
|
||||
centrifugalAccelerationVariation = potentialGradientVariation;
|
||||
|
||||
centrifugalAccelerationVariation *= -1.0;
|
||||
} else {
|
||||
centrifugalAccelerationVariation = 0.0;
|
||||
}
|
||||
|
||||
weightedForce = 0.0;
|
||||
|
||||
if (requestedAction == RotationalDisplacementForceAction::residual) {
|
||||
weightedForce.Add(baseDensityValue * mappingContext.quadrature.weight, centrifugalAcceleration);
|
||||
} else {
|
||||
if (needsDensityVariation) {
|
||||
weightedForce.Add(
|
||||
densityVariationValue * mappingContext.quadrature.weight, centrifugalAcceleration
|
||||
);
|
||||
}
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
weightedForce.Add(
|
||||
baseDensityValue * mappingContext.quadrature.weight, centrifugalAccelerationVariation
|
||||
);
|
||||
|
||||
weightedForce.Add(
|
||||
baseDensityValue * mappingVariation.weight_variation, centrifugalAcceleration
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (int scalarDof = 0; scalarDof < scalarDisplacementDofCount; ++scalarDof) {
|
||||
for (int component = 0; component < dimension; ++component) {
|
||||
const int vectorDof = vector_dof_index(
|
||||
displacementOrdering, scalarDof, component, scalarDisplacementDofCount, dimension
|
||||
);
|
||||
|
||||
const double contribution = displacementShape(scalarDof) * weightedForce(component);
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(contribution), "The rotational-displacement-force kernel "
|
||||
"encountered a non-finite contribution."
|
||||
);
|
||||
|
||||
elementAction(vectorDof) += contribution;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->TransformDual(elementAction);
|
||||
}
|
||||
|
||||
localAction.AddElementVector(displacementDofs, elementAction);
|
||||
}
|
||||
|
||||
local_to_true(*f.displacementFes, localAction, actionTrue);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace mean_field::operators::kernels {
|
||||
void apply_rotational_displacement_force_residual(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::RigidRotation &rotation,
|
||||
const mfem::Vector &densityTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &residualTrue
|
||||
) {
|
||||
apply_rotational_displacement_force_action(
|
||||
f, domainMapper, rotation, RotationalDisplacementForceAction::residual, &densityTrue, nullptr, nullptr,
|
||||
displacementTrue, residualTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_rotational_displacement_force_density_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::RigidRotation &rotation,
|
||||
const mfem::Vector &densityVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_rotational_displacement_force_action(
|
||||
f, domainMapper, rotation, RotationalDisplacementForceAction::density, nullptr, &densityVariationTrue,
|
||||
nullptr, displacementTrue, actionTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_rotational_displacement_force_displacement_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::RigidRotation &rotation,
|
||||
const mfem::Vector &baseDensityTrue,
|
||||
const mfem::Vector &displacementVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_rotational_displacement_force_action(
|
||||
f, domainMapper, rotation, RotationalDisplacementForceAction::displacement, &baseDensityTrue, nullptr,
|
||||
&displacementVariationTrue, displacementTrue, actionTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_rotational_displacement_force_complete_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::RigidRotation &rotation,
|
||||
const mfem::Vector &baseDensityTrue,
|
||||
const mfem::Vector &densityVariationTrue,
|
||||
const mfem::Vector &displacementVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_rotational_displacement_force_action(
|
||||
f, domainMapper, rotation, RotationalDisplacementForceAction::complete, &baseDensityTrue,
|
||||
&densityVariationTrue, &displacementVariationTrue, displacementTrue, actionTrue
|
||||
);
|
||||
}
|
||||
} // namespace mean_field::operators::kernels
|
||||
@@ -5,38 +5,54 @@ module;
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <mfem.hpp>
|
||||
#include <utility>
|
||||
|
||||
module mean_field;
|
||||
|
||||
import :operators.prepared_barotropic_closure;
|
||||
import :operators.kernels.barotropic_closure;
|
||||
import :field.registry;
|
||||
import :utils.domain;
|
||||
|
||||
namespace {
|
||||
int get_density_size(const mean_field::fem::FEM &f) {
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr,
|
||||
"PreparedBarotropicClosureOperator requires the "
|
||||
"density finite-element space."
|
||||
);
|
||||
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||
using ClosureDomain = mean_field::field::FieldDomainT<mean_field::field::Density>;
|
||||
|
||||
return f.densityFes->GetTrueVSize();
|
||||
void verify_required_spaces(const mean_field::fem::FEM &f) {
|
||||
MFEM_VERIFY(f.mesh != nullptr, "PreparedBarotropicClosureOperator requires a mesh.");
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr, "PreparedBarotropicClosureOperator requires the density finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.enthalpyFes != nullptr, "PreparedBarotropicClosureOperator requires the enthalpy finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr,
|
||||
"PreparedBarotropicClosureOperator requires the displacement finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.compactificationFes != nullptr,
|
||||
"PreparedBarotropicClosureOperator requires the compactification finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.compactificationCoordinate != nullptr,
|
||||
"PreparedBarotropicClosureOperator requires the compactification coordinate."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr, "PreparedBarotropicClosureOperator requires the quadrature factory."
|
||||
);
|
||||
}
|
||||
|
||||
int get_enthalpy_size(const mean_field::fem::FEM &f) {
|
||||
MFEM_VERIFY(
|
||||
f.enthalpyFes != nullptr,
|
||||
"PreparedBarotropicClosureOperator requires the "
|
||||
"enthalpy finite-element space."
|
||||
);
|
||||
|
||||
return f.enthalpyFes->GetTrueVSize();
|
||||
[[nodiscard]] bool element_is_in_closure_support(const int attribute) {
|
||||
return DomainSchema::template attribute_belongs_to<ClosureDomain>(attribute);
|
||||
}
|
||||
|
||||
void validate_finite_vector(
|
||||
const mfem::Vector &vector,
|
||||
const char *message
|
||||
) {
|
||||
for (int i = 0; i < vector.Size(); ++i) {
|
||||
MFEM_VERIFY(std::isfinite(vector(i)), message);
|
||||
for (int index = 0; index < vector.Size(); ++index) {
|
||||
MFEM_VERIFY(std::isfinite(vector(index)), message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,15 +61,11 @@ namespace {
|
||||
const mfem::Vector &trueVector,
|
||||
mfem::Vector &localVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
trueVector.Size() == finiteElementSpace.GetTrueVSize(),
|
||||
"True vector has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(trueVector.Size() == finiteElementSpace.GetTrueVSize(), "True vector has the wrong size.");
|
||||
|
||||
localVector.SetSize(finiteElementSpace.GetVSize());
|
||||
|
||||
const mfem::Operator *prolongation =
|
||||
finiteElementSpace.GetProlongationMatrix();
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->Mult(trueVector, localVector);
|
||||
@@ -67,16 +79,12 @@ namespace {
|
||||
const mfem::Vector &localVector,
|
||||
mfem::Vector &trueVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
localVector.Size() == finiteElementSpace.GetVSize(),
|
||||
"Local vector has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(localVector.Size() == finiteElementSpace.GetVSize(), "Local vector has the wrong size.");
|
||||
|
||||
trueVector.SetSize(finiteElementSpace.GetTrueVSize());
|
||||
trueVector = 0.0;
|
||||
trueVector = 0.0;
|
||||
|
||||
const mfem::Operator *prolongation =
|
||||
finiteElementSpace.GetProlongationMatrix();
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->MultTranspose(localVector, trueVector);
|
||||
@@ -85,65 +93,57 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
int get_eos_extra_order(
|
||||
const mean_field::physics::PolytropicBarotrope &barotrope
|
||||
) {
|
||||
const double extraOrder =
|
||||
(barotrope.polytropic_index() - 1.0) *
|
||||
static_cast<double>(
|
||||
mean_field::field::Enthalpy::Scalar::familyOrder
|
||||
);
|
||||
[[nodiscard]] int get_eos_extra_order(const mean_field::eos::Polytrope &equationOfState) {
|
||||
const double extraOrder = (equationOfState.polytropic_index() - 1.0) *
|
||||
static_cast<double>(mean_field::field::Enthalpy::Scalar::familyOrder);
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(extraOrder) && extraOrder >= 0.0 &&
|
||||
extraOrder <=
|
||||
static_cast<double>(std::numeric_limits<int>::max()),
|
||||
extraOrder <= static_cast<double>(std::numeric_limits<int>::max()),
|
||||
"The EOS effective polynomial order is invalid."
|
||||
);
|
||||
|
||||
return static_cast<int>(std::ceil(extraOrder));
|
||||
}
|
||||
|
||||
const mfem::IntegrationRule &get_eos_rule(
|
||||
[[nodiscard]] const mfem::IntegrationRule &get_eos_rule(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::physics::PolytropicBarotrope &barotrope,
|
||||
const mean_field::eos::Polytrope &equationOfState,
|
||||
const mfem::FiniteElement &densityElement,
|
||||
const mfem::FiniteElement &enthalpyElement,
|
||||
const mfem::ElementTransformation &transformation
|
||||
) {
|
||||
using EnthalpyField =
|
||||
mean_field::field::Field<mean_field::field::Enthalpy>;
|
||||
using EnthalpyField = mean_field::field::Field<mean_field::field::Enthalpy>;
|
||||
|
||||
MFEM_VERIFY(
|
||||
densityElement.GetOrder() ==
|
||||
mean_field::field::Density::Scalar::familyOrder,
|
||||
"The prepared EOS test element does not match "
|
||||
"the registered density field."
|
||||
densityElement.GetOrder() == mean_field::field::Density::Scalar::familyOrder,
|
||||
"The prepared EOS test element does not match the registered density field."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
enthalpyElement.GetOrder() ==
|
||||
mean_field::field::Enthalpy::Scalar::familyOrder,
|
||||
"The prepared EOS trial element does not match "
|
||||
"the registered enthalpy field."
|
||||
enthalpyElement.GetOrder() == mean_field::field::Enthalpy::Scalar::familyOrder,
|
||||
"The prepared EOS trial element does not match the registered enthalpy field."
|
||||
);
|
||||
|
||||
const mean_field::quadrature::Query query = EnthalpyField::make_query<
|
||||
mean_field::field::Enthalpy::Form::EosClosureSource>(
|
||||
mean_field::quadrature::QuadratureRole::discretization,
|
||||
transformation.OrderW(),
|
||||
std::array<int, 1>{get_eos_extra_order(barotrope)},
|
||||
mean_field::utils::DOMAINS::STELLAR,
|
||||
mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
/*
|
||||
* The quadrature Query still carries the legacy DOMAINS metadata.
|
||||
* Element support itself is no longer selected through that enum;
|
||||
* support is determined above through Density::Support + DomainSchema.
|
||||
* The Query metadata can be migrated independently with the quadrature
|
||||
* subsystem without changing this operator's algebra.
|
||||
*/
|
||||
const mean_field::quadrature::Query query =
|
||||
EnthalpyField::make_query<mean_field::field::Enthalpy::Form::EosClosureSource>(
|
||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(),
|
||||
std::array<int, 1>{get_eos_extra_order(equationOfState)}, mean_field::utils::DOMAINS::STELLAR,
|
||||
mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
|
||||
const auto resolution =
|
||||
f.quadratureFactory->get(query, transformation.GetGeometryType());
|
||||
const auto resolution = f.quadratureFactory->get(query, transformation.GetGeometryType());
|
||||
|
||||
MFEM_VERIFY(
|
||||
resolution.integration_rule != nullptr,
|
||||
"The quadrature policy did not return a prepared "
|
||||
"EOS-closure integration rule."
|
||||
"The quadrature policy did not return a prepared EOS-closure integration rule."
|
||||
);
|
||||
|
||||
return *resolution.integration_rule;
|
||||
@@ -151,91 +151,127 @@ namespace {
|
||||
} // namespace
|
||||
|
||||
namespace mean_field::operators {
|
||||
struct PreparedBarotropicClosureOperator::ConstructionData final {
|
||||
field::FieldDofMap densityMap;
|
||||
field::FieldDofMap enthalpyMap;
|
||||
field::FieldDofMap displacementMap;
|
||||
|
||||
explicit ConstructionData(const fem::FEM &f)
|
||||
: densityMap(
|
||||
field::make_field_dof_map<
|
||||
field::Density,
|
||||
DomainSchema>(*f.densityFes)
|
||||
),
|
||||
enthalpyMap(
|
||||
field::make_field_dof_map<
|
||||
field::Enthalpy,
|
||||
DomainSchema>(*f.enthalpyFes)
|
||||
),
|
||||
displacementMap(
|
||||
field::make_field_dof_map<
|
||||
field::Displacement,
|
||||
DomainSchema>(*f.displacementFes)
|
||||
) {
|
||||
}
|
||||
};
|
||||
|
||||
PreparedBarotropicClosureOperator::ConstructionData
|
||||
PreparedBarotropicClosureOperator::MakeConstructionData(const fem::FEM &f) {
|
||||
verify_required_spaces(f);
|
||||
return ConstructionData(f);
|
||||
}
|
||||
|
||||
PreparedBarotropicClosureOperator::PreparedBarotropicClosureOperator(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope
|
||||
const eos::Polytrope &equationOfState
|
||||
)
|
||||
: PreparedBarotropicClosureOperator(
|
||||
f,
|
||||
domainMapper,
|
||||
equationOfState,
|
||||
MakeConstructionData(f)
|
||||
) {
|
||||
}
|
||||
|
||||
PreparedBarotropicClosureOperator::PreparedBarotropicClosureOperator(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const eos::Polytrope &equationOfState,
|
||||
ConstructionData constructionData
|
||||
)
|
||||
: mfem::Operator(
|
||||
f.densityFes->GetTrueVSize(),
|
||||
f.densityFes->GetTrueVSize() + f.enthalpyFes->GetTrueVSize() +
|
||||
f.displacementFes->GetTrueVSize()
|
||||
constructionData.densityMap.reduced_size(),
|
||||
constructionData.densityMap.reduced_size() + constructionData.enthalpyMap.reduced_size() +
|
||||
constructionData.displacementMap.reduced_size()
|
||||
),
|
||||
m_fem(f),
|
||||
m_domainMapper(domainMapper),
|
||||
m_barotrope(barotrope),
|
||||
m_densitySize(f.densityFes->GetTrueVSize()),
|
||||
m_enthalpySize(f.enthalpyFes->GetTrueVSize()) {
|
||||
m_equationOfState(equationOfState),
|
||||
m_densityMap(std::move(constructionData.densityMap)),
|
||||
m_enthalpyMap(std::move(constructionData.enthalpyMap)),
|
||||
m_displacementMap(std::move(constructionData.displacementMap)),
|
||||
m_context(
|
||||
f,
|
||||
domainMapper,
|
||||
m_densityMap,
|
||||
m_enthalpyMap,
|
||||
m_displacementMap
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
m_fem.densityFes != nullptr,
|
||||
"PreparedBarotropicClosureOperator requires "
|
||||
"a density finite-element space."
|
||||
m_densityMap.full_size() == m_fem.densityFes->GetTrueVSize(),
|
||||
"The density FieldDofMap does not match the density finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
m_enthalpyMap.full_size() == m_fem.enthalpyFes->GetTrueVSize(),
|
||||
"The enthalpy FieldDofMap does not match the enthalpy finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
m_displacementMap.full_size() == m_fem.displacementFes->GetTrueVSize(),
|
||||
"The displacement FieldDofMap does not match the displacement finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_fem.enthalpyFes != nullptr,
|
||||
"PreparedBarotropicClosureOperator requires "
|
||||
"an enthalpy finite-element space."
|
||||
);
|
||||
m_baseDensityTrue.SetSize(m_densityMap.full_size());
|
||||
m_baseEnthalpyTrue.SetSize(m_enthalpyMap.full_size());
|
||||
m_baseDisplacementTrue.SetSize(m_displacementMap.full_size());
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_fem.displacementFes != nullptr,
|
||||
"PreparedBarotropicClosureOperator requires "
|
||||
"a displacement finite-element space."
|
||||
);
|
||||
m_densityVariationTrue.SetSize(m_densityMap.full_size());
|
||||
m_enthalpyVariationTrue.SetSize(m_enthalpyMap.full_size());
|
||||
m_displacementVariationTrue.SetSize(m_displacementMap.full_size());
|
||||
m_fullThermodynamicAction.SetSize(m_densityMap.full_size());
|
||||
m_fullDisplacementAction.SetSize(m_densityMap.full_size());
|
||||
m_fullResidual.SetSize(m_densityMap.full_size());
|
||||
|
||||
m_baseDensityTrue = 0.0;
|
||||
m_baseEnthalpyTrue = 0.0;
|
||||
m_baseDisplacementTrue = 0.0;
|
||||
m_densityVariationTrue = 0.0;
|
||||
m_enthalpyVariationTrue = 0.0;
|
||||
m_displacementVariationTrue = 0.0;
|
||||
m_fullThermodynamicAction = 0.0;
|
||||
m_fullDisplacementAction = 0.0;
|
||||
m_fullResidual = 0.0;
|
||||
}
|
||||
|
||||
void PreparedBarotropicClosureOperator::Prepare(
|
||||
const mfem::Vector &baseDensityTrue,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector &displacementTrue
|
||||
PreparedBarotropicClosureReport PreparedBarotropicClosureOperator::Prepare(
|
||||
const context::barotropic::BarotropicClosureStateView &state,
|
||||
const context::barotropic::BarotropicClosureDependencies &dependencies
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
baseDensityTrue.Size() == m_densitySize,
|
||||
"PreparedBarotropicClosureOperator received a "
|
||||
"base-density vector with the wrong size."
|
||||
);
|
||||
PreparedBarotropicClosureReport report;
|
||||
report.contextReport = m_context.Prepare(state, dependencies);
|
||||
|
||||
MFEM_VERIFY(
|
||||
baseEnthalpyTrue.Size() == m_enthalpySize,
|
||||
"PreparedBarotropicClosureOperator received a "
|
||||
"base-enthalpy vector with the wrong size."
|
||||
);
|
||||
if (!report.contextReport.DidAnyWork() && m_isPrepared) {
|
||||
return report;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementTrue.Size() == m_fem.displacementFes->GetTrueVSize(),
|
||||
"PreparedBarotropicClosureOperator received a "
|
||||
"displacement vector with the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
baseDensityTrue.Size() == m_fem.densityFes->GetTrueVSize(),
|
||||
"The base density true vector has the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
baseEnthalpyTrue.Size() == m_fem.enthalpyFes->GetTrueVSize(),
|
||||
"The base enthalpy true vector has the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementTrue.Size() == m_fem.displacementFes->GetTrueVSize(),
|
||||
"The base displacement true vector has the wrong size."
|
||||
);
|
||||
|
||||
validate_finite_vector(
|
||||
baseDensityTrue, "PreparedBarotropicClosureOperator received a "
|
||||
"non-finite base-density value."
|
||||
);
|
||||
|
||||
validate_finite_vector(
|
||||
baseEnthalpyTrue, "PreparedBarotropicClosureOperator received a "
|
||||
"non-finite base-enthalpy value."
|
||||
);
|
||||
|
||||
validate_finite_vector(
|
||||
displacementTrue, "PreparedBarotropicClosureOperator received a "
|
||||
"non-finite displacement value."
|
||||
);
|
||||
/*
|
||||
* Canonical solver -> MFEM expansion. Unsupported density and
|
||||
* enthalpy DOFs are zero. Displacement is currently an identity map,
|
||||
* but it is deliberately routed through the same abstraction.
|
||||
*/
|
||||
m_densityMap.scatter(m_context.GetBaseDensity(), m_baseDensityTrue);
|
||||
m_enthalpyMap.scatter(m_context.GetBaseEnthalpy(), m_baseEnthalpyTrue);
|
||||
m_displacementMap.scatter(m_context.GetDisplacement(), m_baseDisplacementTrue);
|
||||
|
||||
m_isPrepared = false;
|
||||
m_elements.clear();
|
||||
@@ -245,17 +281,11 @@ namespace mean_field::operators {
|
||||
mfem::Vector baseEnthalpyLocal;
|
||||
mfem::Vector displacementLocal;
|
||||
|
||||
true_to_local(*m_fem.densityFes, baseDensityTrue, baseDensityLocal);
|
||||
true_to_local(*m_fem.densityFes, m_baseDensityTrue, baseDensityLocal);
|
||||
true_to_local(*m_fem.enthalpyFes, m_baseEnthalpyTrue, baseEnthalpyLocal);
|
||||
true_to_local(*m_fem.displacementFes, m_baseDisplacementTrue, displacementLocal);
|
||||
|
||||
true_to_local(*m_fem.enthalpyFes, baseEnthalpyTrue, baseEnthalpyLocal);
|
||||
|
||||
true_to_local(
|
||||
*m_fem.displacementFes, displacementTrue, displacementLocal
|
||||
);
|
||||
|
||||
mapping::DomainMapperStateless::Workspace workspace(
|
||||
m_fem.mesh->Dimension()
|
||||
);
|
||||
mapping::DomainMapperStateless::Workspace workspace(m_fem.mesh->Dimension());
|
||||
|
||||
mfem::Array<int> displacementDofs;
|
||||
mfem::Array<int> compactificationDofs;
|
||||
@@ -268,222 +298,134 @@ namespace mean_field::operators {
|
||||
mfem::Vector densityShape;
|
||||
mfem::Vector enthalpyShape;
|
||||
|
||||
const int vacuumAttribute = m_domainMapper.GetVacuumElementAttribute();
|
||||
|
||||
for (int elementId = 0; elementId < m_fem.mesh->GetNE(); ++elementId) {
|
||||
mfem::ElementTransformation *transformation =
|
||||
m_fem.mesh->GetElementTransformation(elementId);
|
||||
mfem::ElementTransformation *transformation = m_fem.mesh->GetElementTransformation(elementId);
|
||||
|
||||
MFEM_VERIFY(
|
||||
transformation != nullptr,
|
||||
"PreparedBarotropicClosureOperator received "
|
||||
"a null element transformation."
|
||||
transformation != nullptr, "PreparedBarotropicClosureOperator received a null element transformation."
|
||||
);
|
||||
|
||||
if (transformation->Attribute == vacuumAttribute) {
|
||||
if (!element_is_in_closure_support(transformation->Attribute)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_elements.emplace_back();
|
||||
ElementPAData &data = m_elements.back();
|
||||
ElementPAData &data = m_elements.back();
|
||||
|
||||
data.densityDofTransformation =
|
||||
m_fem.densityFes->GetElementDofs(elementId, data.densityDofs);
|
||||
|
||||
data.enthalpyDofTransformation =
|
||||
m_fem.enthalpyFes->GetElementDofs(elementId, data.enthalpyDofs);
|
||||
data.densityDofTransformation = m_fem.densityFes->GetElementDofs(elementId, data.densityDofs);
|
||||
data.enthalpyDofTransformation = m_fem.enthalpyFes->GetElementDofs(elementId, data.enthalpyDofs);
|
||||
|
||||
mfem::DofTransformation *displacementDofTransformation =
|
||||
m_fem.displacementFes->GetElementVDofs(
|
||||
elementId, displacementDofs
|
||||
);
|
||||
|
||||
m_fem.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
||||
mfem::DofTransformation *compactificationDofTransformation =
|
||||
m_fem.compactificationFes->GetElementDofs(
|
||||
elementId, compactificationDofs
|
||||
);
|
||||
m_fem.compactificationFes->GetElementDofs(elementId, compactificationDofs);
|
||||
|
||||
baseDensityLocal.GetSubVector(data.densityDofs, elementBaseDensity);
|
||||
|
||||
baseEnthalpyLocal.GetSubVector(
|
||||
data.enthalpyDofs, elementBaseEnthalpy
|
||||
);
|
||||
|
||||
displacementLocal.GetSubVector(
|
||||
displacementDofs, elementDisplacement
|
||||
);
|
||||
|
||||
m_fem.compactificationCoordinate->GetSubVector(
|
||||
compactificationDofs, elementCompactification
|
||||
);
|
||||
baseEnthalpyLocal.GetSubVector(data.enthalpyDofs, elementBaseEnthalpy);
|
||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||
m_fem.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
||||
|
||||
if (data.densityDofTransformation != nullptr) {
|
||||
data.densityDofTransformation->InvTransformPrimal(
|
||||
elementBaseDensity
|
||||
);
|
||||
data.densityDofTransformation->InvTransformPrimal(elementBaseDensity);
|
||||
}
|
||||
|
||||
if (data.enthalpyDofTransformation != nullptr) {
|
||||
data.enthalpyDofTransformation->InvTransformPrimal(
|
||||
elementBaseEnthalpy
|
||||
);
|
||||
data.enthalpyDofTransformation->InvTransformPrimal(elementBaseEnthalpy);
|
||||
}
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->InvTransformPrimal(
|
||||
elementDisplacement
|
||||
);
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
||||
}
|
||||
|
||||
if (compactificationDofTransformation != nullptr) {
|
||||
compactificationDofTransformation->InvTransformPrimal(
|
||||
elementCompactification
|
||||
);
|
||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &densityElement =
|
||||
*m_fem.densityFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &enthalpyElement =
|
||||
*m_fem.enthalpyFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &displacementElement =
|
||||
*m_fem.displacementFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &compactificationElement =
|
||||
*m_fem.compactificationFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &densityElement = *m_fem.densityFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &enthalpyElement = *m_fem.enthalpyFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &displacementElement = *m_fem.displacementFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &compactificationElement = *m_fem.compactificationFes->GetFE(elementId);
|
||||
|
||||
const mapping::ElementDisplacementData displacementData =
|
||||
mapping::ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacement
|
||||
);
|
||||
mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
||||
|
||||
const mapping::ElementCompactificationData compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
|
||||
const mapping::ElementMappingData mappingData{
|
||||
.displacement = displacementData,
|
||||
.compactification = compactificationData
|
||||
.displacement = displacementData, .compactification = compactificationData
|
||||
};
|
||||
|
||||
const mfem::IntegrationRule &integrationRule = get_eos_rule(
|
||||
m_fem, m_barotrope, densityElement, enthalpyElement,
|
||||
*transformation
|
||||
);
|
||||
const mfem::IntegrationRule &integrationRule =
|
||||
get_eos_rule(m_fem, m_equationOfState, densityElement, enthalpyElement, *transformation);
|
||||
|
||||
const int quadraturePointCount = integrationRule.GetNPoints();
|
||||
|
||||
const int densityDofCount = densityElement.GetDof();
|
||||
|
||||
const int enthalpyDofCount = enthalpyElement.GetDof();
|
||||
|
||||
data.densityBasis.SetSize(quadraturePointCount, densityDofCount);
|
||||
|
||||
data.enthalpyBasis.SetSize(quadraturePointCount, enthalpyDofCount);
|
||||
|
||||
data.weightedResidual.SetSize(quadraturePointCount);
|
||||
|
||||
data.quadratureWeights.SetSize(quadraturePointCount);
|
||||
|
||||
data.weightedEnthalpyDerivative.SetSize(quadraturePointCount);
|
||||
|
||||
densityShape.SetSize(densityDofCount);
|
||||
|
||||
enthalpyShape.SetSize(enthalpyDofCount);
|
||||
|
||||
for (int quadraturePoint = 0;
|
||||
quadraturePoint < quadraturePointCount; ++quadraturePoint) {
|
||||
const mfem::IntegrationPoint &integrationPoint =
|
||||
integrationRule.IntPoint(quadraturePoint);
|
||||
for (int quadraturePoint = 0; quadraturePoint < quadraturePointCount; ++quadraturePoint) {
|
||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadraturePoint);
|
||||
|
||||
transformation->SetIntPoint(&integrationPoint);
|
||||
|
||||
mapping::VolumeMappingContext mappingContext;
|
||||
|
||||
const mapping::MappingStatus mappingStatus =
|
||||
m_domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint,
|
||||
workspace, mappingContext
|
||||
);
|
||||
const mapping::MappingStatus mappingStatus = m_domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
mappingStatus == mapping::MappingStatus::valid,
|
||||
"Stateless mapping failed while preparing "
|
||||
"the barotropic closure operator. Element: "
|
||||
<< elementId
|
||||
<< ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadraturePoint
|
||||
<< ", status: " << static_cast<int>(mappingStatus)
|
||||
"Stateless mapping failed while preparing the barotropic closure operator. Element: "
|
||||
<< elementId << ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadraturePoint << ", status: " << static_cast<int>(mappingStatus)
|
||||
);
|
||||
|
||||
densityElement.CalcShape(integrationPoint, densityShape);
|
||||
|
||||
enthalpyElement.CalcShape(integrationPoint, enthalpyShape);
|
||||
|
||||
for (int densityDof = 0; densityDof < densityDofCount;
|
||||
++densityDof) {
|
||||
data.densityBasis(quadraturePoint, densityDof) =
|
||||
densityShape(densityDof);
|
||||
for (int densityDof = 0; densityDof < densityDofCount; ++densityDof) {
|
||||
data.densityBasis(quadraturePoint, densityDof) = densityShape(densityDof);
|
||||
}
|
||||
for (int enthalpyDof = 0; enthalpyDof < enthalpyDofCount; ++enthalpyDof) {
|
||||
data.enthalpyBasis(quadraturePoint, enthalpyDof) = enthalpyShape(enthalpyDof);
|
||||
}
|
||||
|
||||
for (int enthalpyDof = 0; enthalpyDof < enthalpyDofCount;
|
||||
++enthalpyDof) {
|
||||
data.enthalpyBasis(quadraturePoint, enthalpyDof) =
|
||||
enthalpyShape(enthalpyDof);
|
||||
}
|
||||
|
||||
const double density = elementBaseDensity * densityShape;
|
||||
|
||||
const double enthalpy = elementBaseEnthalpy * enthalpyShape;
|
||||
|
||||
const double quadratureWeight =
|
||||
mappingContext.quadrature.weight;
|
||||
|
||||
const double eosDensity =
|
||||
m_barotrope.density_from_enthalpy(enthalpy);
|
||||
|
||||
const double enthalpyDerivative =
|
||||
m_barotrope.density_derivative_from_enthalpy(enthalpy);
|
||||
const double density = elementBaseDensity * densityShape;
|
||||
const double enthalpy = elementBaseEnthalpy * enthalpyShape;
|
||||
const double quadratureWeight = mappingContext.quadrature.weight;
|
||||
const double eosDensity = m_equationOfState.density_from_enthalpy(enthalpy);
|
||||
const double enthalpyDerivative = m_equationOfState.density_derivative_from_enthalpy(enthalpy);
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(quadratureWeight) && quadratureWeight > 0.0 &&
|
||||
std::isfinite(eosDensity) &&
|
||||
std::isfinite(quadratureWeight) && quadratureWeight > 0.0 && std::isfinite(eosDensity) &&
|
||||
std::isfinite(enthalpyDerivative),
|
||||
"PreparedBarotropicClosureOperator "
|
||||
"encountered invalid quadrature data."
|
||||
"PreparedBarotropicClosureOperator encountered invalid quadrature data."
|
||||
);
|
||||
|
||||
data.quadratureWeights(quadraturePoint) = quadratureWeight;
|
||||
|
||||
data.weightedResidual(quadraturePoint) =
|
||||
quadratureWeight * (density - eosDensity);
|
||||
|
||||
data.weightedEnthalpyDerivative(quadraturePoint) =
|
||||
quadratureWeight * enthalpyDerivative;
|
||||
data.quadratureWeights(quadraturePoint) = quadratureWeight;
|
||||
data.weightedResidual(quadraturePoint) = quadratureWeight * (density - eosDensity);
|
||||
data.weightedEnthalpyDerivative(quadraturePoint) = quadratureWeight * enthalpyDerivative;
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_VERIFY(
|
||||
!m_elements.empty(), "PreparedBarotropicClosureOperator found no "
|
||||
"stellar elements."
|
||||
);
|
||||
MFEM_VERIFY(!m_elements.empty(), "PreparedBarotropicClosureOperator found no elements in Density::Support.");
|
||||
|
||||
m_baseDensityTrue = baseDensityTrue;
|
||||
m_baseEnthalpyTrue = baseEnthalpyTrue;
|
||||
m_baseDisplacementTrue = displacementTrue;
|
||||
|
||||
m_isPrepared = true;
|
||||
m_isPrepared = true;
|
||||
++m_preparationCount;
|
||||
report.preparedElementData = true;
|
||||
return report;
|
||||
}
|
||||
|
||||
void PreparedBarotropicClosureOperator::BuildResidual(
|
||||
mfem::Vector &residual
|
||||
) const {
|
||||
MFEM_VERIFY(
|
||||
m_isPrepared, "PreparedBarotropicClosureOperator must be "
|
||||
"prepared before BuildResidual is called."
|
||||
);
|
||||
void PreparedBarotropicClosureOperator::BuildResidual(mfem::Vector &residual) const {
|
||||
VerifyPrepared();
|
||||
|
||||
mfem::Vector localResidual(m_fem.densityFes->GetVSize());
|
||||
localResidual = 0.0;
|
||||
@@ -492,10 +434,7 @@ namespace mean_field::operators {
|
||||
|
||||
for (const ElementPAData &data : m_elements) {
|
||||
elementResidual.SetSize(data.densityDofs.Size());
|
||||
|
||||
data.densityBasis.MultTranspose(
|
||||
data.weightedResidual, elementResidual
|
||||
);
|
||||
data.densityBasis.MultTranspose(data.weightedResidual, elementResidual);
|
||||
|
||||
if (data.densityDofTransformation != nullptr) {
|
||||
data.densityDofTransformation->TransformDual(elementResidual);
|
||||
@@ -504,53 +443,56 @@ namespace mean_field::operators {
|
||||
localResidual.AddElementVector(data.densityDofs, elementResidual);
|
||||
}
|
||||
|
||||
local_to_true(*m_fem.densityFes, localResidual, residual);
|
||||
local_to_true(*m_fem.densityFes, localResidual, m_fullResidual);
|
||||
residual.SetSize(m_densityMap.reduced_size());
|
||||
m_densityMap.gather(m_fullResidual, residual);
|
||||
}
|
||||
|
||||
void PreparedBarotropicClosureOperator::Mult(
|
||||
const mfem::Vector &densityVariationTrue,
|
||||
const mfem::Vector &enthalpyVariationTrue,
|
||||
const mfem::Vector &displacementVariationTrue,
|
||||
const mfem::Vector &densityVariation,
|
||||
const mfem::Vector &enthalpyVariation,
|
||||
const mfem::Vector &displacementVariation,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
|
||||
MFEM_VERIFY(
|
||||
densityVariationTrue.Size() == m_densitySize,
|
||||
"The density-variation true vector has "
|
||||
"the wrong size."
|
||||
densityVariation.Size() == m_densityMap.reduced_size(),
|
||||
"The supported density-variation vector has the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
enthalpyVariationTrue.Size() == m_enthalpySize,
|
||||
"The enthalpy-variation true vector has "
|
||||
"the wrong size."
|
||||
enthalpyVariation.Size() == m_enthalpyMap.reduced_size(),
|
||||
"The supported enthalpy-variation vector has the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementVariationTrue.Size() ==
|
||||
m_fem.displacementFes->GetTrueVSize(),
|
||||
"The displacement-variation true vector has "
|
||||
"the wrong size."
|
||||
displacementVariation.Size() == m_displacementMap.reduced_size(),
|
||||
"The supported displacement-variation vector has the wrong size."
|
||||
);
|
||||
|
||||
Mult(densityVariationTrue, enthalpyVariationTrue, action);
|
||||
validate_finite_vector(densityVariation, "The density variation contains a non-finite value.");
|
||||
validate_finite_vector(enthalpyVariation, "The enthalpy variation contains a non-finite value.");
|
||||
validate_finite_vector(displacementVariation, "The displacement variation contains a non-finite value.");
|
||||
|
||||
mfem::Vector displacementAction;
|
||||
m_densityMap.scatter(densityVariation, m_densityVariationTrue);
|
||||
m_enthalpyMap.scatter(enthalpyVariation, m_enthalpyVariationTrue);
|
||||
m_displacementMap.scatter(displacementVariation, m_displacementVariationTrue);
|
||||
|
||||
ApplyThermodynamicActionFull(m_densityVariationTrue, m_enthalpyVariationTrue, m_fullThermodynamicAction);
|
||||
|
||||
kernels::apply_barotropic_closure_displacement_action(
|
||||
m_fem, m_domainMapper, m_barotrope, m_baseDensityTrue,
|
||||
m_baseEnthalpyTrue, m_baseDisplacementTrue,
|
||||
displacementVariationTrue, displacementAction
|
||||
m_fem, m_domainMapper, m_equationOfState, m_baseDensityTrue, m_baseEnthalpyTrue, m_baseDisplacementTrue,
|
||||
m_displacementVariationTrue, m_fullDisplacementAction
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementAction.Size() == m_densitySize,
|
||||
"The barotropic-closure displacement action "
|
||||
"returned a vector with the wrong size."
|
||||
m_fullThermodynamicAction.Size() == m_densityMap.full_size() &&
|
||||
m_fullDisplacementAction.Size() == m_densityMap.full_size(),
|
||||
"A full barotropic-closure Jacobian action has an incompatible density-space size."
|
||||
);
|
||||
|
||||
action += displacementAction;
|
||||
m_fullThermodynamicAction += m_fullDisplacementAction;
|
||||
action.SetSize(m_densityMap.reduced_size());
|
||||
m_densityMap.gather(m_fullThermodynamicAction, action);
|
||||
}
|
||||
|
||||
void PreparedBarotropicClosureOperator::Mult(
|
||||
@@ -559,70 +501,40 @@ namespace mean_field::operators {
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
|
||||
const int displacementSize = m_fem.displacementFes->GetTrueVSize();
|
||||
|
||||
const int combinedSize =
|
||||
m_densitySize + m_enthalpySize + displacementSize;
|
||||
|
||||
MFEM_VERIFY(
|
||||
combinedVariation.Size() == combinedSize,
|
||||
"The combined barotropic-closure variation "
|
||||
"vector has the wrong size. Expected "
|
||||
<< combinedSize << " entries but received "
|
||||
<< combinedVariation.Size() << "."
|
||||
combinedVariation.Size() == Width(), "The packed supported barotropic-closure variation has the wrong size."
|
||||
);
|
||||
|
||||
mfem::real_t *combinedData =
|
||||
const_cast<mfem::real_t *>(combinedVariation.HostRead());
|
||||
mfem::real_t *combinedData = const_cast<mfem::real_t *>(combinedVariation.HostRead());
|
||||
|
||||
const mfem::Vector densityVariationTrue(combinedData, m_densitySize);
|
||||
const int densitySize = m_densityMap.reduced_size();
|
||||
const int enthalpySize = m_enthalpyMap.reduced_size();
|
||||
const int displacementSize = m_displacementMap.reduced_size();
|
||||
|
||||
const mfem::Vector enthalpyVariationTrue(
|
||||
combinedData + m_densitySize, m_enthalpySize
|
||||
);
|
||||
const mfem::Vector densityVariation(combinedData, densitySize);
|
||||
const mfem::Vector enthalpyVariation(combinedData + densitySize, enthalpySize);
|
||||
const mfem::Vector displacementVariation(combinedData + densitySize + enthalpySize, displacementSize);
|
||||
|
||||
const mfem::Vector displacementVariationTrue(
|
||||
combinedData + m_densitySize + m_enthalpySize, displacementSize
|
||||
);
|
||||
|
||||
Mult(
|
||||
densityVariationTrue, enthalpyVariationTrue,
|
||||
displacementVariationTrue, action
|
||||
);
|
||||
Mult(densityVariation, enthalpyVariation, displacementVariation, action);
|
||||
}
|
||||
|
||||
void PreparedBarotropicClosureOperator::Mult(
|
||||
void PreparedBarotropicClosureOperator::ApplyThermodynamicActionFull(
|
||||
const mfem::Vector &densityVariationTrue,
|
||||
const mfem::Vector &enthalpyVariationTrue,
|
||||
mfem::Vector &action
|
||||
mfem::Vector &actionTrue
|
||||
) const {
|
||||
MFEM_VERIFY(
|
||||
m_isPrepared, "PreparedBarotropicClosureOperator must be "
|
||||
"prepared before Mult is called."
|
||||
densityVariationTrue.Size() == m_densityMap.full_size(), "The full density variation has the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
densityVariationTrue.Size() == m_densitySize,
|
||||
"PreparedBarotropicClosureOperator received a "
|
||||
"density variation with the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
enthalpyVariationTrue.Size() == m_enthalpySize,
|
||||
"PreparedBarotropicClosureOperator received an "
|
||||
"enthalpy variation with the wrong size."
|
||||
enthalpyVariationTrue.Size() == m_enthalpyMap.full_size(), "The full enthalpy variation has the wrong size."
|
||||
);
|
||||
|
||||
mfem::Vector densityVariationLocal;
|
||||
mfem::Vector enthalpyVariationLocal;
|
||||
|
||||
true_to_local(
|
||||
*m_fem.densityFes, densityVariationTrue, densityVariationLocal
|
||||
);
|
||||
|
||||
true_to_local(
|
||||
*m_fem.enthalpyFes, enthalpyVariationTrue, enthalpyVariationLocal
|
||||
);
|
||||
true_to_local(*m_fem.densityFes, densityVariationTrue, densityVariationLocal);
|
||||
true_to_local(*m_fem.enthalpyFes, enthalpyVariationTrue, enthalpyVariationLocal);
|
||||
|
||||
mfem::Vector localAction(m_fem.densityFes->GetVSize());
|
||||
localAction = 0.0;
|
||||
@@ -635,51 +547,30 @@ namespace mean_field::operators {
|
||||
mfem::Vector elementAction;
|
||||
|
||||
for (const ElementPAData &data : m_elements) {
|
||||
densityVariationLocal.GetSubVector(
|
||||
data.densityDofs, elementDensityVariation
|
||||
);
|
||||
|
||||
enthalpyVariationLocal.GetSubVector(
|
||||
data.enthalpyDofs, elementEnthalpyVariation
|
||||
);
|
||||
densityVariationLocal.GetSubVector(data.densityDofs, elementDensityVariation);
|
||||
enthalpyVariationLocal.GetSubVector(data.enthalpyDofs, elementEnthalpyVariation);
|
||||
|
||||
if (data.densityDofTransformation != nullptr) {
|
||||
data.densityDofTransformation->InvTransformPrimal(
|
||||
elementDensityVariation
|
||||
);
|
||||
data.densityDofTransformation->InvTransformPrimal(elementDensityVariation);
|
||||
}
|
||||
|
||||
if (data.enthalpyDofTransformation != nullptr) {
|
||||
data.enthalpyDofTransformation->InvTransformPrimal(
|
||||
elementEnthalpyVariation
|
||||
);
|
||||
data.enthalpyDofTransformation->InvTransformPrimal(elementEnthalpyVariation);
|
||||
}
|
||||
|
||||
quadratureDensityVariation.SetSize(data.quadratureWeights.Size());
|
||||
|
||||
quadratureEnthalpyVariation.SetSize(data.quadratureWeights.Size());
|
||||
|
||||
quadratureAction.SetSize(data.quadratureWeights.Size());
|
||||
|
||||
data.densityBasis.Mult(
|
||||
elementDensityVariation, quadratureDensityVariation
|
||||
);
|
||||
data.densityBasis.Mult(elementDensityVariation, quadratureDensityVariation);
|
||||
data.enthalpyBasis.Mult(elementEnthalpyVariation, quadratureEnthalpyVariation);
|
||||
|
||||
data.enthalpyBasis.Mult(
|
||||
elementEnthalpyVariation, quadratureEnthalpyVariation
|
||||
);
|
||||
|
||||
for (int quadraturePoint = 0;
|
||||
quadraturePoint < quadratureAction.Size(); ++quadraturePoint) {
|
||||
for (int quadraturePoint = 0; quadraturePoint < quadratureAction.Size(); ++quadraturePoint) {
|
||||
quadratureAction(quadraturePoint) =
|
||||
data.quadratureWeights(quadraturePoint) *
|
||||
quadratureDensityVariation(quadraturePoint) -
|
||||
data.weightedEnthalpyDerivative(quadraturePoint) *
|
||||
quadratureEnthalpyVariation(quadraturePoint);
|
||||
data.quadratureWeights(quadraturePoint) * quadratureDensityVariation(quadraturePoint) -
|
||||
data.weightedEnthalpyDerivative(quadraturePoint) * quadratureEnthalpyVariation(quadraturePoint);
|
||||
}
|
||||
|
||||
elementAction.SetSize(data.densityDofs.Size());
|
||||
|
||||
data.densityBasis.MultTranspose(quadratureAction, elementAction);
|
||||
|
||||
if (data.densityDofTransformation != nullptr) {
|
||||
@@ -689,30 +580,42 @@ namespace mean_field::operators {
|
||||
localAction.AddElementVector(data.densityDofs, elementAction);
|
||||
}
|
||||
|
||||
local_to_true(*m_fem.densityFes, localAction, action);
|
||||
local_to_true(*m_fem.densityFes, localAction, actionTrue);
|
||||
}
|
||||
|
||||
bool PreparedBarotropicClosureOperator::IsPrepared() const noexcept {
|
||||
return m_isPrepared;
|
||||
return m_isPrepared && m_context.IsPrepared();
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
PreparedBarotropicClosureOperator::GetPreparationCount() const noexcept {
|
||||
std::uint64_t PreparedBarotropicClosureOperator::GetPreparationCount() const noexcept {
|
||||
return m_preparationCount;
|
||||
}
|
||||
|
||||
int PreparedBarotropicClosureOperator::GetDensitySize() const noexcept {
|
||||
return m_densitySize;
|
||||
return m_densityMap.reduced_size();
|
||||
}
|
||||
|
||||
int PreparedBarotropicClosureOperator::GetEnthalpySize() const noexcept {
|
||||
return m_enthalpySize;
|
||||
return m_enthalpyMap.reduced_size();
|
||||
}
|
||||
|
||||
int PreparedBarotropicClosureOperator::GetDisplacementSize() const noexcept {
|
||||
return m_displacementMap.reduced_size();
|
||||
}
|
||||
|
||||
const context::barotropic::BarotropicClosureLinearizationContext &
|
||||
PreparedBarotropicClosureOperator::GetContext() const noexcept {
|
||||
return m_context;
|
||||
}
|
||||
|
||||
const context::barotropic::BarotropicClosurePreparationStatistics &
|
||||
PreparedBarotropicClosureOperator::GetContextPreparationStatistics() const noexcept {
|
||||
return m_context.GetPreparationStatistics();
|
||||
}
|
||||
|
||||
void PreparedBarotropicClosureOperator::VerifyPrepared() const {
|
||||
MFEM_VERIFY(
|
||||
m_isPrepared, "PreparedBarotropicClosureOperator must be "
|
||||
"prepared before this operation is called."
|
||||
m_isPrepared, "PreparedBarotropicClosureOperator must be prepared before this operation is called."
|
||||
);
|
||||
}
|
||||
} // namespace mean_field::operators
|
||||
} // namespace mean_field::operators
|
||||
|
||||
554
libmeanfield/impl/operators/prepared_displacement_operator.cpp
Normal file
554
libmeanfield/impl/operators/prepared_displacement_operator.cpp
Normal file
@@ -0,0 +1,554 @@
|
||||
module;
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
module mean_field;
|
||||
|
||||
import :operators.prepared_displacement_residual;
|
||||
|
||||
namespace {
|
||||
using Dependencies = mean_field::operators::DisplacementResidualDependencies;
|
||||
|
||||
[[nodiscard]] mean_field::operators::context::pressure_force::PressureForceDependencies
|
||||
make_pressure_dependencies(const Dependencies &dependencies) {
|
||||
return {
|
||||
.discretization =
|
||||
{.identity = dependencies.discretization.identity, .revision = dependencies.discretization.revision},
|
||||
.enthalpy = {.identity = dependencies.enthalpy.identity, .revision = dependencies.enthalpy.revision},
|
||||
.displacement = {
|
||||
.identity = dependencies.displacement.identity, .revision = dependencies.displacement.revision
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] mean_field::operators::context::rotational_displacement_force::RotationalDisplacementForceDependencies
|
||||
make_rotational_dependencies(const Dependencies &dependencies) {
|
||||
return {
|
||||
.discretization =
|
||||
{.identity = dependencies.discretization.identity, .revision = dependencies.discretization.revision},
|
||||
.density = {.identity = dependencies.density.identity, .revision = dependencies.density.revision},
|
||||
.displacement =
|
||||
{.identity = dependencies.displacement.identity, .revision = dependencies.displacement.revision},
|
||||
.rotation = {.identity = dependencies.rotation.identity, .revision = dependencies.rotation.revision}
|
||||
};
|
||||
}
|
||||
|
||||
void validate_shared_gravity_revisions(
|
||||
const mean_field::operators::context::gravity_field::GravityFieldLinearizationContext &gravityContext,
|
||||
const Dependencies &dependencies
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
gravityContext.IsPrepared(), "PreparedDisplacementResidualOperator requires the shared "
|
||||
"gravity linearization context to be prepared first."
|
||||
);
|
||||
|
||||
const mean_field::operators::context::gravity_field::GravityFieldRevisions &gravityRevisions =
|
||||
gravityContext.GetRevisions();
|
||||
|
||||
MFEM_VERIFY(
|
||||
gravityRevisions.discretization.value == dependencies.discretization.revision &&
|
||||
gravityRevisions.density.value == dependencies.density.revision &&
|
||||
gravityRevisions.displacement.value == dependencies.displacement.revision &&
|
||||
gravityRevisions.gravity_gradient.value == dependencies.gravityGradient.revision,
|
||||
"PreparedDisplacementResidualOperator received dependency "
|
||||
"revisions that do not match the shared gravity context."
|
||||
);
|
||||
}
|
||||
|
||||
void validate_shared_identity_transition(
|
||||
const mean_field::operators::DisplacementResidualDependencyStamp &prepared,
|
||||
const mean_field::operators::DisplacementResidualDependencyStamp &requested,
|
||||
const char *message
|
||||
) {
|
||||
MFEM_VERIFY(prepared.identity == requested.identity || prepared.revision != requested.revision, message);
|
||||
}
|
||||
|
||||
void add_compatible(
|
||||
mfem::Vector &destination,
|
||||
const mfem::Vector &source,
|
||||
const char *message
|
||||
) {
|
||||
MFEM_VERIFY(destination.Size() == source.Size(), message);
|
||||
destination += source;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace mean_field::operators {
|
||||
PreparedDisplacementResidualOperator::PreparedDisplacementResidualOperator(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const eos::Polytrope &barotrope,
|
||||
const context::gravity_field::GravityFieldLinearizationContext &gravityContext
|
||||
)
|
||||
: m_fem(f),
|
||||
m_domainMapper(domainMapper),
|
||||
m_gravityContext(gravityContext),
|
||||
m_pressureOperator(
|
||||
f,
|
||||
domainMapper,
|
||||
barotrope
|
||||
),
|
||||
m_gravityOperator(
|
||||
f,
|
||||
domainMapper,
|
||||
gravityContext
|
||||
),
|
||||
m_rotationalOperator(
|
||||
f,
|
||||
domainMapper
|
||||
) {
|
||||
MFEM_VERIFY(m_fem.mesh != nullptr, "PreparedDisplacementResidualOperator requires a mesh.");
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_fem.densityFes != nullptr && m_fem.displacementFes != nullptr && m_fem.gravityFluxFes != nullptr &&
|
||||
m_fem.enthalpyFes != nullptr,
|
||||
"PreparedDisplacementResidualOperator requires density, "
|
||||
"displacement, gravity-gradient, and enthalpy finite-element "
|
||||
"spaces."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_domainMapper.GetDimension() == m_fem.mesh->Dimension(),
|
||||
"PreparedDisplacementResidualOperator received a mapper with "
|
||||
"the wrong dimension."
|
||||
);
|
||||
}
|
||||
|
||||
PreparedDisplacementResidualReport PreparedDisplacementResidualOperator::Prepare(
|
||||
const DisplacementResidualStateView &state,
|
||||
const DisplacementResidualDependencies &dependencies,
|
||||
const physics::RigidRotation &rotation
|
||||
) {
|
||||
validate_shared_gravity_revisions(m_gravityContext, dependencies);
|
||||
|
||||
if (m_isPrepared) {
|
||||
/*
|
||||
* GravityFieldLinearizationContext currently tracks revisions
|
||||
* but not semantic identities. Require an identity replacement
|
||||
* to be accompanied by a visible revision change so it cannot
|
||||
* silently reuse the old shared density, geometry, or flux.
|
||||
*/
|
||||
validate_shared_identity_transition(
|
||||
m_preparedDependencies.discretization, dependencies.discretization,
|
||||
"A new displacement-residual discretization identity must "
|
||||
"also change the shared gravity revision."
|
||||
);
|
||||
|
||||
validate_shared_identity_transition(
|
||||
m_preparedDependencies.density, dependencies.density,
|
||||
"A new displacement-residual density identity must also "
|
||||
"change the shared gravity revision."
|
||||
);
|
||||
|
||||
validate_shared_identity_transition(
|
||||
m_preparedDependencies.displacement, dependencies.displacement,
|
||||
"A new displacement-residual displacement identity must "
|
||||
"also change the shared gravity revision."
|
||||
);
|
||||
|
||||
validate_shared_identity_transition(
|
||||
m_preparedDependencies.gravityGradient, dependencies.gravityGradient,
|
||||
"A new displacement-residual gravity-gradient identity "
|
||||
"must also change the shared gravity revision."
|
||||
);
|
||||
}
|
||||
|
||||
const mfem::Vector &density = m_gravityContext.GetDensity();
|
||||
const mfem::Vector &displacement = m_gravityContext.GetGeometryContext().GetDisplacement();
|
||||
|
||||
m_isPrepared = false;
|
||||
|
||||
PreparedDisplacementResidualReport report;
|
||||
|
||||
report.pressure = m_pressureOperator.Prepare(
|
||||
{.enthalpy = state.enthalpy, .displacement = displacement}, make_pressure_dependencies(dependencies)
|
||||
);
|
||||
|
||||
report.gravity = m_gravityOperator.Prepare();
|
||||
|
||||
report.rotation = m_rotationalOperator.Prepare(
|
||||
{.density = density, .displacement = displacement}, make_rotational_dependencies(dependencies), rotation
|
||||
);
|
||||
|
||||
if (report.DidAnyChildWork() || m_cachedResidual.Size() != m_fem.displacementFes->GetTrueVSize()) {
|
||||
AssembleResidual();
|
||||
report.assembledResidual = true;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_cachedResidual.Size() == m_fem.displacementFes->GetTrueVSize(),
|
||||
"PreparedDisplacementResidualOperator produced a cached "
|
||||
"residual with the wrong size."
|
||||
);
|
||||
|
||||
m_preparedDependencies = dependencies;
|
||||
m_isPrepared = true;
|
||||
return report;
|
||||
}
|
||||
|
||||
void PreparedDisplacementResidualOperator::AssembleResidual() {
|
||||
mfem::Vector pressureResidual;
|
||||
mfem::Vector gravityResidual;
|
||||
mfem::Vector rotationalResidual;
|
||||
|
||||
m_pressureOperator.BuildResidual(pressureResidual);
|
||||
m_gravityOperator.BuildResidual(gravityResidual);
|
||||
m_rotationalOperator.BuildResidual(rotationalResidual);
|
||||
|
||||
m_cachedResidual = pressureResidual;
|
||||
|
||||
add_compatible(
|
||||
m_cachedResidual, gravityResidual,
|
||||
"Cannot combine pressure and gravity displacement residuals "
|
||||
"with different sizes."
|
||||
);
|
||||
|
||||
add_compatible(
|
||||
m_cachedResidual, rotationalResidual,
|
||||
"Cannot combine mechanical displacement residuals with "
|
||||
"different sizes."
|
||||
);
|
||||
|
||||
++m_residualPreparationCount;
|
||||
}
|
||||
|
||||
void PreparedDisplacementResidualOperator::BuildResidual(mfem::Vector &residual) const {
|
||||
VerifyPrepared();
|
||||
residual = m_cachedResidual;
|
||||
++m_residualApplicationCount;
|
||||
}
|
||||
|
||||
void PreparedDisplacementResidualOperator::ApplyDensityJacobianAction(
|
||||
const mfem::Vector &densityVariation,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
|
||||
mfem::Vector rotationalAction;
|
||||
|
||||
m_gravityOperator.ApplyDensityJacobianAction(densityVariation, action);
|
||||
|
||||
m_rotationalOperator.ApplyDensityJacobianAction(densityVariation, rotationalAction);
|
||||
|
||||
add_compatible(
|
||||
action, rotationalAction,
|
||||
"Cannot combine gravity and rotation density-column actions "
|
||||
"with different sizes."
|
||||
);
|
||||
|
||||
++m_actionStatistics.densityApplications;
|
||||
}
|
||||
|
||||
void PreparedDisplacementResidualOperator::ApplyDisplacementJacobianAction(
|
||||
const mfem::Vector &displacementVariation,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
|
||||
mfem::Vector gravityAction;
|
||||
mfem::Vector rotationalAction;
|
||||
|
||||
m_pressureOperator.ApplyDisplacementJacobianAction(displacementVariation, action);
|
||||
|
||||
m_gravityOperator.ApplyDisplacementJacobianAction(displacementVariation, gravityAction);
|
||||
|
||||
m_rotationalOperator.ApplyDisplacementJacobianAction(displacementVariation, rotationalAction);
|
||||
|
||||
add_compatible(
|
||||
action, gravityAction,
|
||||
"Cannot combine pressure and gravity displacement-column "
|
||||
"actions with different sizes."
|
||||
);
|
||||
|
||||
add_compatible(
|
||||
action, rotationalAction,
|
||||
"Cannot combine mechanical displacement-column actions with "
|
||||
"different sizes."
|
||||
);
|
||||
|
||||
++m_actionStatistics.displacementApplications;
|
||||
}
|
||||
|
||||
void PreparedDisplacementResidualOperator::ApplyGravityGradientJacobianAction(
|
||||
const mfem::Vector &gravityGradientVariation,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
|
||||
m_gravityOperator.ApplyGravityGradientJacobianAction(gravityGradientVariation, action);
|
||||
|
||||
++m_actionStatistics.gravityGradientApplications;
|
||||
}
|
||||
|
||||
void PreparedDisplacementResidualOperator::ApplyEnthalpyJacobianAction(
|
||||
const mfem::Vector &enthalpyVariation,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
|
||||
m_pressureOperator.ApplyEnthalpyJacobianAction(enthalpyVariation, action);
|
||||
|
||||
++m_actionStatistics.enthalpyApplications;
|
||||
}
|
||||
|
||||
void PreparedDisplacementResidualOperator::ApplyCompleteJacobianAction(
|
||||
const mfem::Vector &densityVariation,
|
||||
const mfem::Vector &displacementVariation,
|
||||
const mfem::Vector &gravityGradientVariation,
|
||||
const mfem::Vector &enthalpyVariation,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
|
||||
mfem::Vector gravityAction;
|
||||
mfem::Vector rotationalAction;
|
||||
|
||||
m_pressureOperator.ApplyCompleteJacobianAction(enthalpyVariation, displacementVariation, action);
|
||||
|
||||
m_gravityOperator.ApplyCompleteJacobianAction(
|
||||
densityVariation, displacementVariation, gravityGradientVariation, gravityAction
|
||||
);
|
||||
|
||||
m_rotationalOperator.ApplyCompleteJacobianAction(densityVariation, displacementVariation, rotationalAction);
|
||||
|
||||
add_compatible(
|
||||
action, gravityAction,
|
||||
"Cannot combine pressure and gravity complete Jacobian "
|
||||
"actions with different sizes."
|
||||
);
|
||||
|
||||
add_compatible(
|
||||
action, rotationalAction,
|
||||
"Cannot combine mechanical complete Jacobian actions with "
|
||||
"different sizes."
|
||||
);
|
||||
|
||||
++m_actionStatistics.densityApplications;
|
||||
++m_actionStatistics.displacementApplications;
|
||||
++m_actionStatistics.gravityGradientApplications;
|
||||
++m_actionStatistics.enthalpyApplications;
|
||||
++m_actionStatistics.completeApplications;
|
||||
}
|
||||
|
||||
bool PreparedDisplacementResidualOperator::IsPrepared() const noexcept {
|
||||
if (!m_isPrepared || !m_pressureOperator.IsPrepared() || !m_gravityOperator.IsPrepared() ||
|
||||
!m_rotationalOperator.IsPrepared() || !m_gravityContext.IsPrepared()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const context::gravity_field::GravityFieldRevisions &gravityRevisions = m_gravityContext.GetRevisions();
|
||||
|
||||
return gravityRevisions.discretization.value == m_preparedDependencies.discretization.revision &&
|
||||
gravityRevisions.density.value == m_preparedDependencies.density.revision &&
|
||||
gravityRevisions.displacement.value == m_preparedDependencies.displacement.revision &&
|
||||
gravityRevisions.gravity_gradient.value == m_preparedDependencies.gravityGradient.revision;
|
||||
}
|
||||
|
||||
std::uint64_t PreparedDisplacementResidualOperator::GetResidualPreparationCount() const noexcept {
|
||||
return m_residualPreparationCount;
|
||||
}
|
||||
|
||||
std::uint64_t PreparedDisplacementResidualOperator::GetResidualApplicationCount() const noexcept {
|
||||
return m_residualApplicationCount;
|
||||
}
|
||||
|
||||
const PreparedDisplacementResidualActionStatistics &
|
||||
PreparedDisplacementResidualOperator::GetActionStatistics() const noexcept {
|
||||
return m_actionStatistics;
|
||||
}
|
||||
|
||||
const PreparedPressureForceOperator &PreparedDisplacementResidualOperator::GetPressureOperator() const noexcept {
|
||||
return m_pressureOperator;
|
||||
}
|
||||
|
||||
const PreparedGravityDisplacementForceOperator &
|
||||
PreparedDisplacementResidualOperator::GetGravityOperator() const noexcept {
|
||||
return m_gravityOperator;
|
||||
}
|
||||
|
||||
const PreparedRotationalDisplacementForceOperator &
|
||||
PreparedDisplacementResidualOperator::GetRotationalOperator() const noexcept {
|
||||
return m_rotationalOperator;
|
||||
}
|
||||
|
||||
const fem::FEM &PreparedDisplacementResidualOperator::GetFEM() const noexcept {
|
||||
return m_fem;
|
||||
}
|
||||
|
||||
const context::gravity_field::GravityFieldLinearizationContext &
|
||||
PreparedDisplacementResidualOperator::GetGravityContext() const noexcept {
|
||||
return m_gravityContext;
|
||||
}
|
||||
|
||||
void PreparedDisplacementResidualOperator::VerifyPrepared() const {
|
||||
MFEM_VERIFY(
|
||||
IsPrepared(), "PreparedDisplacementResidualOperator must be prepared for "
|
||||
"the current shared gravity-context revisions before residual "
|
||||
"or Jacobian application."
|
||||
);
|
||||
}
|
||||
|
||||
PreparedDisplacementResidualJacobianOperator::PreparedDisplacementResidualJacobianOperator(
|
||||
const DisplacementResidualLayout &layout,
|
||||
const PreparedDisplacementResidualOperator &preparedOperator
|
||||
)
|
||||
: mfem::Operator(
|
||||
layout.residual_offsets().Last(),
|
||||
layout.value_offsets().Last()
|
||||
),
|
||||
m_layout(layout),
|
||||
m_preparedOperator(preparedOperator) {
|
||||
const fem::FEM &f = m_preparedOperator.GetFEM();
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr && f.displacementFes != nullptr && f.gravityFluxFes != nullptr &&
|
||||
f.gravityPotentialFes != nullptr && f.enthalpyFes != nullptr,
|
||||
"Prepared displacement-residual MFEM adapter requires every "
|
||||
"finite-element space in the barotropic equilibrium layout."
|
||||
);
|
||||
|
||||
using Form = utils::blocks::barotropic_equilibrium_form;
|
||||
|
||||
constexpr auto densityValue = utils::blocks::get_value_block<Form>(utils::blocks::density_field.mass_term);
|
||||
|
||||
constexpr auto displacementValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
|
||||
constexpr auto gravityGradientValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::gravity_field.gradient_term);
|
||||
|
||||
constexpr auto gravityPotentialValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::gravity_field.poisson_term);
|
||||
|
||||
constexpr auto enthalpyValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::enthalpy_field.specific_term);
|
||||
|
||||
constexpr auto barotropicConstantValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::barotropic_constant_field.mass_normalization_term);
|
||||
|
||||
constexpr auto gravityGradientResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::gravity_field.gradient_term);
|
||||
|
||||
constexpr auto gravityPotentialResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::gravity_field.poisson_term);
|
||||
|
||||
constexpr auto densityResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::density_field.mass_term);
|
||||
|
||||
constexpr auto displacementResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
|
||||
constexpr auto enthalpyResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::enthalpy_field.specific_term);
|
||||
|
||||
constexpr auto massResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::barotropic_constant_field.mass_normalization_term);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_layout.size(densityValue) == f.densityFes->GetTrueVSize() &&
|
||||
m_layout.size(displacementValue) == f.displacementFes->GetTrueVSize() &&
|
||||
m_layout.size(gravityGradientValue) == f.gravityFluxFes->GetTrueVSize() &&
|
||||
m_layout.size(gravityPotentialValue) == f.gravityPotentialFes->GetTrueVSize() &&
|
||||
m_layout.size(barotropicConstantValue) == 1,
|
||||
"Prepared displacement-residual MFEM adapter received "
|
||||
"incompatible barotropic value-block sizes."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_layout.size(enthalpyValue) == m_preparedOperator.GetPressureOperator().GetEnthalpySize(),
|
||||
"Prepared displacement-residual MFEM adapter received an "
|
||||
"incompatible enthalpy value block."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_layout.size(gravityGradientResidual) == f.gravityFluxFes->GetTrueVSize() &&
|
||||
m_layout.size(gravityPotentialResidual) == f.gravityPotentialFes->GetTrueVSize() &&
|
||||
m_layout.size(densityResidual) == f.densityFes->GetTrueVSize() &&
|
||||
m_layout.size(displacementResidual) == f.displacementFes->GetTrueVSize() &&
|
||||
m_layout.size(enthalpyResidual) == f.enthalpyFes->GetTrueVSize() && m_layout.size(massResidual) == 1,
|
||||
"Prepared displacement-residual MFEM adapter received "
|
||||
"incompatible barotropic residual-block sizes."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
Height() == m_layout.residual_offsets().Last() && Width() == m_layout.value_offsets().Last(),
|
||||
"Prepared displacement-residual MFEM adapter has inconsistent "
|
||||
"operator dimensions."
|
||||
);
|
||||
}
|
||||
|
||||
void PreparedDisplacementResidualJacobianOperator::Mult(
|
||||
const mfem::Vector &direction,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
MFEM_VERIFY(
|
||||
m_preparedOperator.IsPrepared(), "Prepared displacement-residual MFEM adapter requires a "
|
||||
"prepared row operator."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
direction.Size() == Width(), "Prepared displacement-residual MFEM adapter received a "
|
||||
"direction with the wrong size."
|
||||
);
|
||||
|
||||
using Form = utils::blocks::barotropic_equilibrium_form;
|
||||
|
||||
constexpr auto densityValue = utils::blocks::get_value_block<Form>(utils::blocks::density_field.mass_term);
|
||||
|
||||
constexpr auto displacementValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
|
||||
constexpr auto gravityGradientValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::gravity_field.gradient_term);
|
||||
|
||||
constexpr auto enthalpyValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::enthalpy_field.specific_term);
|
||||
|
||||
constexpr auto displacementResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
|
||||
const mfem::Vector densityVariation(
|
||||
const_cast<mfem::real_t *>(direction.GetData()) + m_layout.offset(densityValue), m_layout.size(densityValue)
|
||||
);
|
||||
|
||||
const mfem::Vector displacementVariation(
|
||||
const_cast<mfem::real_t *>(direction.GetData()) + m_layout.offset(displacementValue),
|
||||
m_layout.size(displacementValue)
|
||||
);
|
||||
|
||||
const mfem::Vector gravityGradientVariation(
|
||||
const_cast<mfem::real_t *>(direction.GetData()) + m_layout.offset(gravityGradientValue),
|
||||
m_layout.size(gravityGradientValue)
|
||||
);
|
||||
|
||||
const mfem::Vector enthalpyVariation(
|
||||
const_cast<mfem::real_t *>(direction.GetData()) + m_layout.offset(enthalpyValue),
|
||||
m_layout.size(enthalpyValue)
|
||||
);
|
||||
|
||||
mfem::Vector displacementAction;
|
||||
|
||||
m_preparedOperator.ApplyCompleteJacobianAction(
|
||||
densityVariation, displacementVariation, gravityGradientVariation, enthalpyVariation, displacementAction
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementAction.Size() == m_layout.size(displacementResidual),
|
||||
"Prepared displacement-residual MFEM adapter produced an "
|
||||
"action with the wrong size."
|
||||
);
|
||||
|
||||
action.SetSize(Height());
|
||||
action = 0.0;
|
||||
|
||||
const int residualOffset = m_layout.offset(displacementResidual);
|
||||
|
||||
for (int entry = 0; entry < displacementAction.Size(); ++entry) {
|
||||
action(residualOffset + entry) = displacementAction(entry);
|
||||
}
|
||||
}
|
||||
|
||||
const DisplacementResidualLayout &PreparedDisplacementResidualJacobianOperator::GetLayout() const noexcept {
|
||||
return m_layout;
|
||||
}
|
||||
} // namespace mean_field::operators
|
||||
@@ -0,0 +1,290 @@
|
||||
module;
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
module mean_field;
|
||||
|
||||
import :operators.kernels.gravity_displacement_force;
|
||||
import :operators.prepared_gravity_displacement_force;
|
||||
|
||||
namespace {
|
||||
[[nodiscard]] bool relevant_revisions_match(
|
||||
const mean_field::operators::context::gravity_field::GravityFieldRevisions &left,
|
||||
const mean_field::operators::context::gravity_field::GravityFieldRevisions &right
|
||||
) noexcept {
|
||||
return left.discretization == right.discretization && left.displacement == right.displacement &&
|
||||
left.density == right.density && left.gravity_gradient == right.gravity_gradient;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace mean_field::operators {
|
||||
PreparedGravityDisplacementForceOperator::PreparedGravityDisplacementForceOperator(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const context::gravity_field::GravityFieldLinearizationContext &gravityContext
|
||||
)
|
||||
: m_fem(f),
|
||||
m_domainMapper(domainMapper),
|
||||
m_gravityContext(gravityContext) {
|
||||
MFEM_VERIFY(m_fem.mesh != nullptr, "PreparedGravityDisplacementForceOperator requires a mesh.");
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_fem.densityFes != nullptr && m_fem.gravityFluxFes != nullptr && m_fem.displacementFes != nullptr,
|
||||
"PreparedGravityDisplacementForceOperator requires density, "
|
||||
"gravity-gradient, and displacement finite-element spaces."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_domainMapper.GetDimension() == m_fem.mesh->Dimension(),
|
||||
"PreparedGravityDisplacementForceOperator received a mapper "
|
||||
"with the wrong dimension."
|
||||
);
|
||||
}
|
||||
|
||||
PreparedGravityDisplacementForceReport PreparedGravityDisplacementForceOperator::Prepare() {
|
||||
MFEM_VERIFY(
|
||||
m_gravityContext.IsPrepared(), "PreparedGravityDisplacementForceOperator requires the shared "
|
||||
"gravity linearization context to be prepared first."
|
||||
);
|
||||
|
||||
const context::gravity_field::GravityFieldRevisions &requestedRevisions = m_gravityContext.GetRevisions();
|
||||
|
||||
if (m_isPrepared && relevant_revisions_match(requestedRevisions, m_preparedRevisions)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
kernels::apply_gravity_displacement_force_residual(
|
||||
m_fem, m_domainMapper, m_gravityContext.GetDensity(), m_gravityContext.GetGravityGradient(),
|
||||
m_gravityContext.GetGeometryContext().GetDisplacement(), m_cachedResidual
|
||||
);
|
||||
|
||||
m_preparedRevisions = requestedRevisions;
|
||||
++m_residualPreparationCount;
|
||||
m_isPrepared = true;
|
||||
|
||||
return {.preparedResidual = true};
|
||||
}
|
||||
|
||||
void PreparedGravityDisplacementForceOperator::BuildResidual(mfem::Vector &residual) const {
|
||||
VerifyPrepared();
|
||||
residual = m_cachedResidual;
|
||||
++m_residualApplicationCount;
|
||||
}
|
||||
|
||||
void PreparedGravityDisplacementForceOperator::ApplyDensityJacobianAction(
|
||||
const mfem::Vector &densityVariation,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
|
||||
kernels::apply_gravity_displacement_force_density_action(
|
||||
m_fem, m_domainMapper, densityVariation, m_gravityContext.GetGravityGradient(),
|
||||
m_gravityContext.GetGeometryContext().GetDisplacement(), action
|
||||
);
|
||||
|
||||
++m_densityJacobianStatistics.applications;
|
||||
}
|
||||
|
||||
void PreparedGravityDisplacementForceOperator::ApplyGravityGradientJacobianAction(
|
||||
const mfem::Vector &gravityGradientVariation,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
|
||||
kernels::apply_gravity_displacement_force_gradient_action(
|
||||
m_fem, m_domainMapper, m_gravityContext.GetDensity(), gravityGradientVariation,
|
||||
m_gravityContext.GetGeometryContext().GetDisplacement(), action
|
||||
);
|
||||
|
||||
++m_gravityGradientJacobianStatistics.applications;
|
||||
}
|
||||
|
||||
void PreparedGravityDisplacementForceOperator::ApplyDisplacementJacobianAction(
|
||||
const mfem::Vector &displacementVariation,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
|
||||
kernels::apply_gravity_displacement_force_displacement_action(
|
||||
m_fem, m_domainMapper, m_gravityContext.GetDensity(), m_gravityContext.GetGravityGradient(),
|
||||
displacementVariation, m_gravityContext.GetGeometryContext().GetDisplacement(), action
|
||||
);
|
||||
|
||||
++m_displacementJacobianStatistics.applications;
|
||||
}
|
||||
|
||||
void PreparedGravityDisplacementForceOperator::ApplyCompleteJacobianAction(
|
||||
const mfem::Vector &densityVariation,
|
||||
const mfem::Vector &displacementVariation,
|
||||
const mfem::Vector &gravityGradientVariation,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
|
||||
kernels::apply_gravity_displacement_force_complete_action(
|
||||
m_fem, m_domainMapper, m_gravityContext.GetDensity(), densityVariation,
|
||||
m_gravityContext.GetGravityGradient(), gravityGradientVariation, displacementVariation,
|
||||
m_gravityContext.GetGeometryContext().GetDisplacement(), action
|
||||
);
|
||||
|
||||
++m_densityJacobianStatistics.applications;
|
||||
++m_gravityGradientJacobianStatistics.applications;
|
||||
++m_displacementJacobianStatistics.applications;
|
||||
++m_completeJacobianStatistics.applications;
|
||||
}
|
||||
|
||||
bool PreparedGravityDisplacementForceOperator::IsPrepared() const noexcept {
|
||||
if (!m_isPrepared || !m_gravityContext.IsPrepared()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return relevant_revisions_match(m_gravityContext.GetRevisions(), m_preparedRevisions);
|
||||
}
|
||||
|
||||
std::uint64_t PreparedGravityDisplacementForceOperator::GetResidualPreparationCount() const noexcept {
|
||||
return m_residualPreparationCount;
|
||||
}
|
||||
|
||||
std::uint64_t PreparedGravityDisplacementForceOperator::GetResidualApplicationCount() const noexcept {
|
||||
return m_residualApplicationCount;
|
||||
}
|
||||
|
||||
const PreparedGravityDisplacementForceColumnStatistics &
|
||||
PreparedGravityDisplacementForceOperator::GetDensityJacobianStatistics() const noexcept {
|
||||
return m_densityJacobianStatistics;
|
||||
}
|
||||
|
||||
const PreparedGravityDisplacementForceColumnStatistics &
|
||||
PreparedGravityDisplacementForceOperator::GetGravityGradientJacobianStatistics() const noexcept {
|
||||
return m_gravityGradientJacobianStatistics;
|
||||
}
|
||||
|
||||
const PreparedGravityDisplacementForceColumnStatistics &
|
||||
PreparedGravityDisplacementForceOperator::GetDisplacementJacobianStatistics() const noexcept {
|
||||
return m_displacementJacobianStatistics;
|
||||
}
|
||||
|
||||
const PreparedGravityDisplacementForceCompleteStatistics &
|
||||
PreparedGravityDisplacementForceOperator::GetCompleteJacobianStatistics() const noexcept {
|
||||
return m_completeJacobianStatistics;
|
||||
}
|
||||
|
||||
const fem::FEM &PreparedGravityDisplacementForceOperator::GetFEM() const noexcept {
|
||||
return m_fem;
|
||||
}
|
||||
|
||||
const context::gravity_field::GravityFieldLinearizationContext &
|
||||
PreparedGravityDisplacementForceOperator::GetGravityContext() const noexcept {
|
||||
return m_gravityContext;
|
||||
}
|
||||
|
||||
void PreparedGravityDisplacementForceOperator::VerifyPrepared() const {
|
||||
MFEM_VERIFY(
|
||||
IsPrepared(), "PreparedGravityDisplacementForceOperator must be prepared for "
|
||||
"the current shared gravity-context revisions before residual or "
|
||||
"Jacobian application."
|
||||
);
|
||||
}
|
||||
|
||||
PreparedGravityDisplacementForceJacobianOperator::PreparedGravityDisplacementForceJacobianOperator(
|
||||
const GravityDisplacementForceLayout &layout,
|
||||
const PreparedGravityDisplacementForceOperator &preparedOperator
|
||||
)
|
||||
: mfem::Operator(
|
||||
layout.residual_offsets().Last(),
|
||||
layout.value_offsets().Last()
|
||||
),
|
||||
m_layout(layout),
|
||||
m_preparedOperator(preparedOperator) {
|
||||
const fem::FEM &f = m_preparedOperator.GetFEM();
|
||||
|
||||
using Form = utils::blocks::barotropic_equilibrium_form;
|
||||
|
||||
constexpr auto densityValue = utils::blocks::get_value_block<Form>(utils::blocks::density_field.mass_term);
|
||||
|
||||
constexpr auto displacementValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
|
||||
constexpr auto gravityGradientValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::gravity_field.gradient_term);
|
||||
|
||||
constexpr auto displacementResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_layout.size(densityValue) == f.densityFes->GetTrueVSize() &&
|
||||
m_layout.size(displacementValue) == f.displacementFes->GetTrueVSize() &&
|
||||
m_layout.size(gravityGradientValue) == f.gravityFluxFes->GetTrueVSize() &&
|
||||
m_layout.size(displacementResidual) == f.displacementFes->GetTrueVSize(),
|
||||
"Prepared gravity-displacement-force MFEM adapter received "
|
||||
"incompatible coupled block sizes."
|
||||
);
|
||||
}
|
||||
|
||||
void PreparedGravityDisplacementForceJacobianOperator::Mult(
|
||||
const mfem::Vector &direction,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
MFEM_VERIFY(
|
||||
m_preparedOperator.IsPrepared(), "Prepared gravity-displacement-force MFEM adapter requires a "
|
||||
"prepared operator."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
direction.Size() == Width(), "Prepared gravity-displacement-force MFEM adapter received a "
|
||||
"direction with the wrong size."
|
||||
);
|
||||
|
||||
using Form = utils::blocks::barotropic_equilibrium_form;
|
||||
|
||||
constexpr auto densityValue = utils::blocks::get_value_block<Form>(utils::blocks::density_field.mass_term);
|
||||
|
||||
constexpr auto displacementValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
|
||||
constexpr auto gravityGradientValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::gravity_field.gradient_term);
|
||||
|
||||
constexpr auto displacementResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
|
||||
const mfem::Vector densityVariation(
|
||||
const_cast<mfem::real_t *>(direction.GetData()) + m_layout.offset(densityValue), m_layout.size(densityValue)
|
||||
);
|
||||
|
||||
const mfem::Vector displacementVariation(
|
||||
const_cast<mfem::real_t *>(direction.GetData()) + m_layout.offset(displacementValue),
|
||||
m_layout.size(displacementValue)
|
||||
);
|
||||
|
||||
const mfem::Vector gravityGradientVariation(
|
||||
const_cast<mfem::real_t *>(direction.GetData()) + m_layout.offset(gravityGradientValue),
|
||||
m_layout.size(gravityGradientValue)
|
||||
);
|
||||
|
||||
mfem::Vector displacementAction;
|
||||
|
||||
m_preparedOperator.ApplyCompleteJacobianAction(
|
||||
densityVariation, displacementVariation, gravityGradientVariation, displacementAction
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementAction.Size() == m_layout.size(displacementResidual),
|
||||
"Prepared gravity-displacement-force MFEM adapter produced a "
|
||||
"displacement action with the wrong size."
|
||||
);
|
||||
|
||||
action.SetSize(Height());
|
||||
action = 0.0;
|
||||
|
||||
const int residualOffset = m_layout.offset(displacementResidual);
|
||||
|
||||
for (int entry = 0; entry < displacementAction.Size(); ++entry) {
|
||||
action(residualOffset + entry) = displacementAction(entry);
|
||||
}
|
||||
}
|
||||
|
||||
const GravityDisplacementForceLayout &PreparedGravityDisplacementForceJacobianOperator::GetLayout() const noexcept {
|
||||
return m_layout;
|
||||
}
|
||||
} // namespace mean_field::operators
|
||||
@@ -11,19 +11,17 @@ import :operators.prepared_gravity_source;
|
||||
namespace {
|
||||
int get_operator_height(const mean_field::fem::FEM &f) {
|
||||
MFEM_VERIFY(
|
||||
f.gravityPotentialFes != nullptr,
|
||||
"PreparedMappedGravitySourceOperator requires the "
|
||||
"gravity-potential "
|
||||
"finite-element space."
|
||||
f.gravityPotentialFes != nullptr, "PreparedMappedGravitySourceOperator requires the "
|
||||
"gravity-potential "
|
||||
"finite-element space."
|
||||
);
|
||||
return f.gravityPotentialFes->GetTrueVSize();
|
||||
}
|
||||
|
||||
int get_operator_width(const mean_field::fem::FEM &f) {
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr,
|
||||
"PreparedMappedGravitySourceOperator requires the density "
|
||||
"finite-element space."
|
||||
f.densityFes != nullptr, "PreparedMappedGravitySourceOperator requires the density "
|
||||
"finite-element space."
|
||||
);
|
||||
return f.densityFes->GetTrueVSize();
|
||||
}
|
||||
@@ -35,8 +33,7 @@ namespace {
|
||||
) {
|
||||
local_vector.SetSize(finite_element_space.GetVSize());
|
||||
|
||||
const mfem::Operator *prolongation =
|
||||
finite_element_space.GetProlongationMatrix();
|
||||
const mfem::Operator *prolongation = finite_element_space.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->Mult(true_vector, local_vector);
|
||||
@@ -50,16 +47,12 @@ namespace {
|
||||
const mfem::Vector &local_vector,
|
||||
mfem::Vector &true_vector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
local_vector.Size() == finite_element_space.GetVSize(),
|
||||
"Local vector has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(local_vector.Size() == finite_element_space.GetVSize(), "Local vector has the wrong size.");
|
||||
|
||||
true_vector.SetSize(finite_element_space.GetTrueVSize());
|
||||
true_vector = 0.0;
|
||||
true_vector = 0.0;
|
||||
|
||||
const mfem::Operator *prolongation =
|
||||
finite_element_space.GetProlongationMatrix();
|
||||
const mfem::Operator *prolongation = finite_element_space.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->MultTranspose(local_vector, true_vector);
|
||||
@@ -74,34 +67,27 @@ namespace {
|
||||
const mfem::FiniteElement &potential_element,
|
||||
const mfem::ElementTransformation &transformation
|
||||
) {
|
||||
using GravityField =
|
||||
mean_field::field::Field<mean_field::field::Gravity>;
|
||||
using GravityField = mean_field::field::Field<mean_field::field::Gravity>;
|
||||
MFEM_VERIFY(
|
||||
density_element.GetOrder() ==
|
||||
mean_field::field::Density::Scalar::familyOrder,
|
||||
density_element.GetOrder() == mean_field::field::Density::Scalar::familyOrder,
|
||||
"The prepared source trial element does not match the registered "
|
||||
"density field."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
potential_element.GetOrder() ==
|
||||
mean_field::field::Gravity::Potential::familyOrder,
|
||||
potential_element.GetOrder() == mean_field::field::Gravity::Potential::familyOrder,
|
||||
"The prepared source test element does not match the registered "
|
||||
"gravity potential."
|
||||
);
|
||||
const mean_field::quadrature::Query query = GravityField::make_query<
|
||||
mean_field::field::Gravity::Form::SourceProjection>(
|
||||
mean_field::quadrature::QuadratureRole::discretization,
|
||||
transformation.OrderW(), {}, mean_field::utils::DOMAINS::STELLAR,
|
||||
mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
const mean_field::quadrature::Query query =
|
||||
GravityField::make_query<mean_field::field::Gravity::Form::SourceProjection>(
|
||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), {},
|
||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
|
||||
return *f.quadratureFactory
|
||||
->get(query, transformation.GetGeometryType())
|
||||
.integration_rule;
|
||||
return *f.quadratureFactory->get(query, transformation.GetGeometryType()).integration_rule;
|
||||
}
|
||||
|
||||
class FrozenMappedGravitySourceCoefficient final
|
||||
: public mfem::Coefficient {
|
||||
class FrozenMappedGravitySourceCoefficient final : public mfem::Coefficient {
|
||||
public:
|
||||
FrozenMappedGravitySourceCoefficient(
|
||||
const mean_field::fem::FEM &f,
|
||||
@@ -111,9 +97,7 @@ namespace {
|
||||
: m_fem(f),
|
||||
m_domain_mapper(domain_mapper),
|
||||
m_workspace(domain_mapper.GetDimension()) {
|
||||
true_to_local(
|
||||
*m_fem.displacementFes, displacement_true, m_displacement_local
|
||||
);
|
||||
true_to_local(*m_fem.displacementFes, displacement_true, m_displacement_local);
|
||||
}
|
||||
|
||||
double Eval(
|
||||
@@ -128,79 +112,55 @@ namespace {
|
||||
"Mapped gravity source coefficient received an invalid element "
|
||||
"ID."
|
||||
);
|
||||
if (transformation.Attribute ==
|
||||
m_domain_mapper.GetVacuumElementAttribute()) {
|
||||
if (transformation.Attribute == m_domain_mapper.GetVacuumElementAttribute()) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
LoadElement(element_id);
|
||||
const mean_field::mapping::ElementMappingData mapping_data{
|
||||
.displacement = *m_displacement_data,
|
||||
.compactification = *m_compactification_data
|
||||
.displacement = *m_displacement_data, .compactification = *m_compactification_data
|
||||
};
|
||||
|
||||
mean_field::mapping::VolumeMappingContext mapping_context;
|
||||
|
||||
const mean_field::mapping::MappingStatus status =
|
||||
m_domain_mapper.EvaluateVolume(
|
||||
mapping_data, transformation, integration_point,
|
||||
m_workspace, mapping_context
|
||||
);
|
||||
const mean_field::mapping::MappingStatus status = m_domain_mapper.EvaluateVolume(
|
||||
mapping_data, transformation, integration_point, m_workspace, mapping_context
|
||||
);
|
||||
|
||||
if (status != mean_field::mapping::MappingStatus::valid) {
|
||||
const mfem::FiniteElement &displacement_element =
|
||||
*m_fem.displacementFes->GetFE(element_id);
|
||||
const mfem::FiniteElement &compactification_element =
|
||||
*m_fem.compactificationFes->GetFE(element_id);
|
||||
const mfem::FiniteElement &displacement_element = *m_fem.displacementFes->GetFE(element_id);
|
||||
const mfem::FiniteElement &compactification_element = *m_fem.compactificationFes->GetFE(element_id);
|
||||
|
||||
mfem::Vector displacement_shape(displacement_element.GetDof());
|
||||
mfem::Vector compactification_shape(
|
||||
compactification_element.GetDof()
|
||||
);
|
||||
mfem::Vector compactification_shape(compactification_element.GetDof());
|
||||
mfem::Vector reference_position(m_domain_mapper.GetDimension());
|
||||
mfem::Vector displacement_value(m_domain_mapper.GetDimension());
|
||||
|
||||
displacement_element.CalcShape(
|
||||
integration_point, displacement_shape
|
||||
);
|
||||
compactification_element.CalcShape(
|
||||
integration_point, compactification_shape
|
||||
);
|
||||
displacement_element.CalcShape(integration_point, displacement_shape);
|
||||
compactification_element.CalcShape(integration_point, compactification_shape);
|
||||
transformation.Transform(integration_point, reference_position);
|
||||
m_displacement_data->GetDofMatrix().MultTranspose(
|
||||
displacement_shape, displacement_value
|
||||
);
|
||||
m_displacement_data->GetDofMatrix().MultTranspose(displacement_shape, displacement_value);
|
||||
|
||||
const double compactification_coordinate =
|
||||
m_compactification_data->GetDofs() * compactification_shape;
|
||||
const double compactification_coordinate = m_compactification_data->GetDofs() * compactification_shape;
|
||||
|
||||
MFEM_ABORT(
|
||||
"Stateless domain mapping failed while preparing the "
|
||||
"gravity "
|
||||
"source operator."
|
||||
<< "\nMapping status = " << static_cast<int>(status)
|
||||
<< "\nElement ID = " << element_id
|
||||
<< "\nMapping status = " << static_cast<int>(status) << "\nElement ID = " << element_id
|
||||
<< "\nElement attribute = " << transformation.Attribute
|
||||
<< "\nIntegration-point index = " << integration_point.index
|
||||
<< "\nIntegration point = <" << integration_point.x << ", "
|
||||
<< integration_point.y << ", " << integration_point.z << ">"
|
||||
<< "\nReference position = <" << reference_position(0)
|
||||
<< ", " << reference_position(1) << ", "
|
||||
<< "\nIntegration-point index = " << integration_point.index << "\nIntegration point = <"
|
||||
<< integration_point.x << ", " << integration_point.y << ", " << integration_point.z << ">"
|
||||
<< "\nReference position = <" << reference_position(0) << ", " << reference_position(1) << ", "
|
||||
<< reference_position(2) << ">"
|
||||
<< "\nReference radius = " << reference_position.Norml2()
|
||||
<< "\nDisplacement value = <" << displacement_value(0)
|
||||
<< ", " << displacement_value(1) << ", "
|
||||
<< displacement_value(2) << ">"
|
||||
<< "\nDisplacement magnitude = "
|
||||
<< displacement_value.Norml2()
|
||||
<< "\nCompactification coordinate = "
|
||||
<< compactification_coordinate
|
||||
<< "\nDisplacement ordering = "
|
||||
<< static_cast<int>(m_fem.displacementFes->GetOrdering())
|
||||
<< "\nReference radius = " << reference_position.Norml2() << "\nDisplacement value = <"
|
||||
<< displacement_value(0) << ", " << displacement_value(1) << ", " << displacement_value(2) << ">"
|
||||
<< "\nDisplacement magnitude = " << displacement_value.Norml2()
|
||||
<< "\nCompactification coordinate = " << compactification_coordinate
|
||||
<< "\nDisplacement ordering = " << static_cast<int>(m_fem.displacementFes->GetOrdering())
|
||||
);
|
||||
}
|
||||
const double mapping_determinant =
|
||||
mapping_context.mapping.mapping_determinant;
|
||||
const double mapping_determinant = mapping_context.mapping.mapping_determinant;
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(mapping_determinant) && mapping_determinant > 0.0,
|
||||
"Prepared gravity source operator encountered a non-positive "
|
||||
@@ -208,8 +168,7 @@ namespace {
|
||||
"non-finite mapping determinant."
|
||||
);
|
||||
|
||||
return 4.0 * std::numbers::pi * mean_field::utils::G *
|
||||
mapping_determinant;
|
||||
return 4.0 * std::numbers::pi * mean_field::utils::G * mapping_determinant;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -218,48 +177,32 @@ namespace {
|
||||
return;
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &displacement_element =
|
||||
*m_fem.displacementFes->GetFE(element_id);
|
||||
const mfem::FiniteElement &compactification_element =
|
||||
*m_fem.compactificationFes->GetFE(element_id);
|
||||
const mfem::FiniteElement &displacement_element = *m_fem.displacementFes->GetFE(element_id);
|
||||
const mfem::FiniteElement &compactification_element = *m_fem.compactificationFes->GetFE(element_id);
|
||||
|
||||
mfem::DofTransformation *displacement_dof_transformation =
|
||||
m_fem.displacementFes->GetElementVDofs(
|
||||
element_id, m_displacement_dofs
|
||||
);
|
||||
m_fem.displacementFes->GetElementVDofs(element_id, m_displacement_dofs);
|
||||
mfem::DofTransformation *compactification_dof_transformation =
|
||||
m_fem.compactificationFes->GetElementDofs(
|
||||
element_id, m_compactification_dofs
|
||||
);
|
||||
m_fem.compactificationFes->GetElementDofs(element_id, m_compactification_dofs);
|
||||
|
||||
m_displacement_local.GetSubVector(
|
||||
m_displacement_dofs, m_element_displacement
|
||||
);
|
||||
m_fem.compactificationCoordinate->GetSubVector(
|
||||
m_compactification_dofs, m_element_compactification
|
||||
);
|
||||
m_displacement_local.GetSubVector(m_displacement_dofs, m_element_displacement);
|
||||
m_fem.compactificationCoordinate->GetSubVector(m_compactification_dofs, m_element_compactification);
|
||||
|
||||
if (displacement_dof_transformation != nullptr) {
|
||||
displacement_dof_transformation->InvTransformPrimal(
|
||||
m_element_displacement
|
||||
);
|
||||
displacement_dof_transformation->InvTransformPrimal(m_element_displacement);
|
||||
}
|
||||
|
||||
if (compactification_dof_transformation != nullptr) {
|
||||
compactification_dof_transformation->InvTransformPrimal(
|
||||
m_element_compactification
|
||||
);
|
||||
compactification_dof_transformation->InvTransformPrimal(m_element_compactification);
|
||||
}
|
||||
|
||||
m_displacement_data = std::make_unique<
|
||||
mean_field::mapping::ElementDisplacementData>(
|
||||
m_displacement_data = std::make_unique<mean_field::mapping::ElementDisplacementData>(
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||
displacement_element, m_element_displacement
|
||||
)
|
||||
);
|
||||
|
||||
m_compactification_data = std::make_unique<
|
||||
mean_field::mapping::ElementCompactificationData>(
|
||||
m_compactification_data = std::make_unique<mean_field::mapping::ElementCompactificationData>(
|
||||
compactification_element, m_element_compactification
|
||||
);
|
||||
|
||||
@@ -277,10 +220,8 @@ namespace {
|
||||
mfem::Vector m_element_displacement;
|
||||
mfem::Vector m_element_compactification;
|
||||
|
||||
std::unique_ptr<mean_field::mapping::ElementDisplacementData>
|
||||
m_displacement_data;
|
||||
std::unique_ptr<mean_field::mapping::ElementCompactificationData>
|
||||
m_compactification_data;
|
||||
std::unique_ptr<mean_field::mapping::ElementDisplacementData> m_displacement_data;
|
||||
std::unique_ptr<mean_field::mapping::ElementCompactificationData> m_compactification_data;
|
||||
|
||||
mean_field::mapping::DomainMapperStateless::Workspace m_workspace;
|
||||
int m_cached_element_id{-1};
|
||||
@@ -298,30 +239,23 @@ namespace mean_field::operators {
|
||||
),
|
||||
m_fem(f),
|
||||
m_domain_mapper(domain_mapper) {
|
||||
MFEM_VERIFY(f.mesh != nullptr, "PreparedMappedGravitySourceOperator requires a mesh.");
|
||||
MFEM_VERIFY(
|
||||
f.mesh != nullptr,
|
||||
"PreparedMappedGravitySourceOperator requires a mesh."
|
||||
f.densityFes != nullptr, "PreparedMappedGravitySourceOperator requires the density "
|
||||
"finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr,
|
||||
"PreparedMappedGravitySourceOperator requires the density "
|
||||
"finite-element space."
|
||||
f.gravityPotentialFes != nullptr, "PreparedMappedGravitySourceOperator requires the "
|
||||
"gravity-potential "
|
||||
"finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.gravityPotentialFes != nullptr,
|
||||
"PreparedMappedGravitySourceOperator requires the "
|
||||
"gravity-potential "
|
||||
"finite-element space."
|
||||
f.displacementFes != nullptr, "PreparedMappedGravitySourceOperator requires "
|
||||
"the displacement finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr,
|
||||
"PreparedMappedGravitySourceOperator requires "
|
||||
"the displacement finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.compactificationFes != nullptr,
|
||||
"PreparedMappedGravitySourceOperator requires the compactification "
|
||||
"finite-element space."
|
||||
f.compactificationFes != nullptr, "PreparedMappedGravitySourceOperator requires the compactification "
|
||||
"finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.compactificationCoordinate != nullptr,
|
||||
@@ -329,9 +263,8 @@ namespace mean_field::operators {
|
||||
"coordinate."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr,
|
||||
"PreparedMappedGravitySourceOperator "
|
||||
"requires the quadrature-rule factory."
|
||||
f.quadratureFactory != nullptr, "PreparedMappedGravitySourceOperator "
|
||||
"requires the quadrature-rule factory."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
domain_mapper.GetDimension() == f.mesh->Dimension(),
|
||||
@@ -339,14 +272,10 @@ namespace mean_field::operators {
|
||||
"dimension."
|
||||
);
|
||||
|
||||
utils::populate_element_mask(
|
||||
f.mesh.get(), utils::DOMAINS::STELLAR, m_stellar_marker
|
||||
);
|
||||
utils::populate_element_mask(f.mesh.get(), utils::DOMAINS::STELLAR, m_stellar_marker);
|
||||
}
|
||||
|
||||
void PreparedMappedGravitySourceOperator::Prepare(
|
||||
const mfem::Vector &displacement_true
|
||||
) {
|
||||
void PreparedMappedGravitySourceOperator::Prepare(const mfem::Vector &displacement_true) {
|
||||
MFEM_VERIFY(
|
||||
displacement_true.Size() == m_fem.displacementFes->GetTrueVSize(),
|
||||
"PreparedMappedGravitySourceOperator received a displacement "
|
||||
@@ -356,9 +285,8 @@ namespace mean_field::operators {
|
||||
|
||||
for (int i = 0; i < displacement_true.Size(); ++i) {
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(displacement_true(i)),
|
||||
"PreparedMappedGravitySourceOperator received a non-finite "
|
||||
"displacement value."
|
||||
std::isfinite(displacement_true(i)), "PreparedMappedGravitySourceOperator received a non-finite "
|
||||
"displacement value."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -366,44 +294,33 @@ namespace mean_field::operators {
|
||||
m_elements.clear();
|
||||
m_elements.reserve(m_fem.mesh->GetNE());
|
||||
|
||||
FrozenMappedGravitySourceCoefficient source_coefficient(
|
||||
m_fem, m_domain_mapper, displacement_true
|
||||
);
|
||||
FrozenMappedGravitySourceCoefficient source_coefficient(m_fem, m_domain_mapper, displacement_true);
|
||||
|
||||
for (int element_id = 0; element_id < m_fem.mesh->GetNE();
|
||||
++element_id) {
|
||||
for (int element_id = 0; element_id < m_fem.mesh->GetNE(); ++element_id) {
|
||||
const int attribute = m_fem.mesh->GetAttribute(element_id);
|
||||
|
||||
if (attribute <= 0 || attribute > m_stellar_marker.Size() ||
|
||||
m_stellar_marker[attribute - 1] == 0) {
|
||||
if (attribute <= 0 || attribute > m_stellar_marker.Size() || m_stellar_marker[attribute - 1] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_elements.emplace_back();
|
||||
ElementPAData &data = m_elements.back();
|
||||
ElementPAData &data = m_elements.back();
|
||||
|
||||
data.element_id = element_id;
|
||||
data.element_id = element_id;
|
||||
|
||||
data.density_dof_transformation =
|
||||
m_fem.densityFes->GetElementDofs(element_id, data.density_dofs);
|
||||
data.density_dof_transformation = m_fem.densityFes->GetElementDofs(element_id, data.density_dofs);
|
||||
|
||||
data.potential_dof_transformation =
|
||||
m_fem.gravityPotentialFes->GetElementDofs(
|
||||
element_id, data.potential_dofs
|
||||
);
|
||||
m_fem.gravityPotentialFes->GetElementDofs(element_id, data.potential_dofs);
|
||||
|
||||
const mfem::FiniteElement &density_element =
|
||||
*m_fem.densityFes->GetFE(element_id);
|
||||
const mfem::FiniteElement &density_element = *m_fem.densityFes->GetFE(element_id);
|
||||
|
||||
const mfem::FiniteElement &potential_element =
|
||||
*m_fem.gravityPotentialFes->GetFE(element_id);
|
||||
const mfem::FiniteElement &potential_element = *m_fem.gravityPotentialFes->GetFE(element_id);
|
||||
|
||||
mfem::ElementTransformation &transformation =
|
||||
*m_fem.mesh->GetElementTransformation(element_id);
|
||||
mfem::ElementTransformation &transformation = *m_fem.mesh->GetElementTransformation(element_id);
|
||||
|
||||
const mfem::IntegrationRule &integration_rule = get_source_rule(
|
||||
m_fem, density_element, potential_element, transformation
|
||||
);
|
||||
const mfem::IntegrationRule &integration_rule =
|
||||
get_source_rule(m_fem, density_element, potential_element, transformation);
|
||||
|
||||
const int quadrature_point_count = integration_rule.GetNPoints();
|
||||
|
||||
@@ -411,24 +328,17 @@ namespace mean_field::operators {
|
||||
|
||||
const int potential_dof_count = potential_element.GetDof();
|
||||
|
||||
data.density_basis.SetSize(
|
||||
quadrature_point_count, density_dof_count
|
||||
);
|
||||
data.density_basis.SetSize(quadrature_point_count, density_dof_count);
|
||||
|
||||
data.potential_basis.SetSize(
|
||||
quadrature_point_count, potential_dof_count
|
||||
);
|
||||
data.potential_basis.SetSize(quadrature_point_count, potential_dof_count);
|
||||
|
||||
data.quadrature_data.SetSize(quadrature_point_count);
|
||||
|
||||
mfem::Vector density_shape(density_dof_count);
|
||||
mfem::Vector potential_shape(potential_dof_count);
|
||||
|
||||
for (int quadrature_point = 0;
|
||||
quadrature_point < quadrature_point_count;
|
||||
++quadrature_point) {
|
||||
const mfem::IntegrationPoint &integration_point =
|
||||
integration_rule.IntPoint(quadrature_point);
|
||||
for (int quadrature_point = 0; quadrature_point < quadrature_point_count; ++quadrature_point) {
|
||||
const mfem::IntegrationPoint &integration_point = integration_rule.IntPoint(quadrature_point);
|
||||
|
||||
transformation.SetIntPoint(&integration_point);
|
||||
|
||||
@@ -436,44 +346,34 @@ namespace mean_field::operators {
|
||||
// including the finite-element map type.
|
||||
density_element.CalcPhysShape(transformation, density_shape);
|
||||
|
||||
potential_element.CalcPhysShape(
|
||||
transformation, potential_shape
|
||||
);
|
||||
potential_element.CalcPhysShape(transformation, potential_shape);
|
||||
|
||||
for (int i = 0; i < density_dof_count; ++i) {
|
||||
data.density_basis(quadrature_point, i) = density_shape(i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < potential_dof_count; ++i) {
|
||||
data.potential_basis(quadrature_point, i) =
|
||||
potential_shape(i);
|
||||
data.potential_basis(quadrature_point, i) = potential_shape(i);
|
||||
}
|
||||
|
||||
const double coefficient_value =
|
||||
source_coefficient.Eval(transformation, integration_point);
|
||||
const double coefficient_value = source_coefficient.Eval(transformation, integration_point);
|
||||
|
||||
transformation.SetIntPoint(&integration_point);
|
||||
|
||||
const double quadrature_value = integration_point.weight *
|
||||
transformation.Weight() *
|
||||
coefficient_value;
|
||||
const double quadrature_value = integration_point.weight * transformation.Weight() * coefficient_value;
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(quadrature_value) && quadrature_value > 0.0,
|
||||
"Prepared gravity source operator encountered invalid "
|
||||
"quadrature data on element "
|
||||
<< element_id << ", quadrature point "
|
||||
<< quadrature_point << "."
|
||||
<< element_id << ", quadrature point " << quadrature_point << "."
|
||||
);
|
||||
|
||||
data.quadrature_data(quadrature_point) = quadrature_value;
|
||||
}
|
||||
}
|
||||
|
||||
MFEM_VERIFY(
|
||||
!m_elements.empty(),
|
||||
"PreparedMappedGravitySourceOperator found no stellar elements."
|
||||
);
|
||||
MFEM_VERIFY(!m_elements.empty(), "PreparedMappedGravitySourceOperator found no stellar elements.");
|
||||
|
||||
m_is_prepared = true;
|
||||
++m_preparation_count;
|
||||
@@ -483,15 +383,13 @@ namespace mean_field::operators {
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
MFEM_VERIFY(
|
||||
m_is_prepared,
|
||||
"PreparedMappedGravitySourceOperator must be prepared before "
|
||||
"Mult is called."
|
||||
m_is_prepared, "PreparedMappedGravitySourceOperator must be prepared before "
|
||||
"Mult is called."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
density_true.Size() == Width(),
|
||||
"PreparedMappedGravitySourceOperator received a density vector "
|
||||
"with the wrong size."
|
||||
density_true.Size() == Width(), "PreparedMappedGravitySourceOperator received a density vector "
|
||||
"with the wrong size."
|
||||
);
|
||||
|
||||
mfem::Vector density_local;
|
||||
@@ -509,9 +407,7 @@ namespace mean_field::operators {
|
||||
density_local.GetSubVector(data.density_dofs, element_density);
|
||||
|
||||
if (data.density_dof_transformation != nullptr) {
|
||||
data.density_dof_transformation->InvTransformPrimal(
|
||||
element_density
|
||||
);
|
||||
data.density_dof_transformation->InvTransformPrimal(element_density);
|
||||
}
|
||||
|
||||
quadrature_density.SetSize(data.quadrature_data.Size());
|
||||
@@ -527,14 +423,10 @@ namespace mean_field::operators {
|
||||
element_action.SetSize(data.potential_dofs.Size());
|
||||
|
||||
// B_potential^T * D * B_density * x_e
|
||||
data.potential_basis.MultTranspose(
|
||||
quadrature_density, element_action
|
||||
);
|
||||
data.potential_basis.MultTranspose(quadrature_density, element_action);
|
||||
|
||||
if (data.potential_dof_transformation != nullptr) {
|
||||
data.potential_dof_transformation->TransformDual(
|
||||
element_action
|
||||
);
|
||||
data.potential_dof_transformation->TransformDual(element_action);
|
||||
}
|
||||
|
||||
local_action.AddElementVector(data.potential_dofs, element_action);
|
||||
@@ -548,22 +440,18 @@ namespace mean_field::operators {
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
MFEM_VERIFY(
|
||||
m_is_prepared,
|
||||
"PreparedMappedGravitySourceOperator must be prepared before "
|
||||
"MultTranspose is called."
|
||||
m_is_prepared, "PreparedMappedGravitySourceOperator must be prepared before "
|
||||
"MultTranspose is called."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
potential_true.Size() == Height(),
|
||||
"PreparedMappedGravitySourceOperator received a potential vector "
|
||||
"with the wrong size."
|
||||
potential_true.Size() == Height(), "PreparedMappedGravitySourceOperator received a potential vector "
|
||||
"with the wrong size."
|
||||
);
|
||||
|
||||
mfem::Vector potential_local;
|
||||
|
||||
true_to_local(
|
||||
*m_fem.gravityPotentialFes, potential_true, potential_local
|
||||
);
|
||||
true_to_local(*m_fem.gravityPotentialFes, potential_true, potential_local);
|
||||
|
||||
mfem::Vector local_action(m_fem.densityFes->GetVSize());
|
||||
local_action = 0.0;
|
||||
@@ -573,14 +461,10 @@ namespace mean_field::operators {
|
||||
mfem::Vector element_action;
|
||||
|
||||
for (const ElementPAData &data : m_elements) {
|
||||
potential_local.GetSubVector(
|
||||
data.potential_dofs, element_potential
|
||||
);
|
||||
potential_local.GetSubVector(data.potential_dofs, element_potential);
|
||||
|
||||
if (data.potential_dof_transformation != nullptr) {
|
||||
data.potential_dof_transformation->InvTransformPrimal(
|
||||
element_potential
|
||||
);
|
||||
data.potential_dof_transformation->InvTransformPrimal(element_potential);
|
||||
}
|
||||
|
||||
quadrature_potential.SetSize(data.quadrature_data.Size());
|
||||
@@ -593,9 +477,7 @@ namespace mean_field::operators {
|
||||
|
||||
element_action.SetSize(data.density_dofs.Size());
|
||||
|
||||
data.density_basis.MultTranspose(
|
||||
quadrature_potential, element_action
|
||||
);
|
||||
data.density_basis.MultTranspose(quadrature_potential, element_action);
|
||||
|
||||
if (data.density_dof_transformation != nullptr) {
|
||||
data.density_dof_transformation->TransformDual(element_action);
|
||||
@@ -610,8 +492,7 @@ namespace mean_field::operators {
|
||||
return m_is_prepared;
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
PreparedMappedGravitySourceOperator::GetPreparationCount() const noexcept {
|
||||
std::uint64_t PreparedMappedGravitySourceOperator::GetPreparationCount() const noexcept {
|
||||
return m_preparation_count;
|
||||
}
|
||||
} // namespace mean_field::operators
|
||||
|
||||
@@ -10,9 +10,8 @@ import :operators.prepared_hdiv_mass;
|
||||
namespace {
|
||||
int get_operator_size(const mean_field::fem::FEM &f) {
|
||||
MFEM_VERIFY(
|
||||
f.gravityFluxFes != nullptr,
|
||||
"PreparedMappedHDivMassOperator requires the "
|
||||
"gravity-gradient finite-element space."
|
||||
f.gravityFluxFes != nullptr, "PreparedMappedHDivMassOperator requires the "
|
||||
"gravity-gradient finite-element space."
|
||||
);
|
||||
return f.gravityFluxFes->GetTrueVSize();
|
||||
}
|
||||
@@ -24,8 +23,7 @@ namespace {
|
||||
) {
|
||||
local_vector.SetSize(finite_element_space.GetVSize());
|
||||
|
||||
const mfem::Operator *prolongation =
|
||||
finite_element_space.GetProlongationMatrix();
|
||||
const mfem::Operator *prolongation = finite_element_space.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->Mult(true_vector, local_vector);
|
||||
@@ -41,8 +39,7 @@ namespace {
|
||||
for (int element_id = 0; element_id < f.mesh->GetNE(); ++element_id) {
|
||||
const int attribute = f.mesh->GetAttribute(element_id);
|
||||
|
||||
if (attribute > 0 && attribute <= marker.Size() &&
|
||||
marker[attribute - 1] != 0) {
|
||||
if (attribute > 0 && attribute <= marker.Size() && marker[attribute - 1] != 0) {
|
||||
return element_id;
|
||||
}
|
||||
}
|
||||
@@ -55,23 +52,19 @@ namespace {
|
||||
const mfem::Array<int> &marker,
|
||||
const int representative_element_id
|
||||
) {
|
||||
const mfem::FiniteElement &representative_element =
|
||||
*f.gravityFluxFes->GetFE(representative_element_id);
|
||||
const mfem::FiniteElement &representative_element = *f.gravityFluxFes->GetFE(representative_element_id);
|
||||
const mfem::ElementTransformation &representative_transformation =
|
||||
*f.mesh->GetElementTransformation(representative_element_id);
|
||||
|
||||
for (int element_id = 0; element_id < f.mesh->GetNE(); ++element_id) {
|
||||
const int attribute = f.mesh->GetAttribute(element_id);
|
||||
|
||||
if (attribute <= 0 || attribute > marker.Size() ||
|
||||
marker[attribute - 1] == 0) {
|
||||
if (attribute <= 0 || attribute > marker.Size() || marker[attribute - 1] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &element =
|
||||
*f.gravityFluxFes->GetFE(element_id);
|
||||
const mfem::ElementTransformation &transformation =
|
||||
*f.mesh->GetElementTransformation(element_id);
|
||||
const mfem::FiniteElement &element = *f.gravityFluxFes->GetFE(element_id);
|
||||
const mfem::ElementTransformation &transformation = *f.mesh->GetElementTransformation(element_id);
|
||||
|
||||
MFEM_VERIFY(
|
||||
element.GetGeomType() == representative_element.GetGeomType(),
|
||||
@@ -85,16 +78,14 @@ namespace {
|
||||
"finite-element order."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
transformation.OrderW() ==
|
||||
representative_transformation.OrderW(),
|
||||
transformation.OrderW() == representative_transformation.OrderW(),
|
||||
"Prepared H(div) mass domains currently require a uniform "
|
||||
"geometry-weight order."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FrozenMappedHDivMassCoefficient final
|
||||
: public mfem::MatrixCoefficient {
|
||||
class FrozenMappedHDivMassCoefficient final : public mfem::MatrixCoefficient {
|
||||
public:
|
||||
FrozenMappedHDivMassCoefficient(
|
||||
const mean_field::fem::FEM &f,
|
||||
@@ -107,9 +98,7 @@ namespace {
|
||||
m_domain_mapper(domain_mapper),
|
||||
m_workspace(domain_mapper.GetDimension()),
|
||||
m_elevates_vacuum(elevates_vacuum) {
|
||||
true_to_local(
|
||||
*m_fem.displacementFes, displacement_true, m_displacement_local
|
||||
);
|
||||
true_to_local(*m_fem.displacementFes, displacement_true, m_displacement_local);
|
||||
}
|
||||
|
||||
void Eval(
|
||||
@@ -125,9 +114,7 @@ namespace {
|
||||
"Mapped H(div) mass coefficient received an invalid element ID."
|
||||
);
|
||||
|
||||
const bool element_is_vacuum =
|
||||
transformation.Attribute ==
|
||||
m_domain_mapper.GetVacuumElementAttribute();
|
||||
const bool element_is_vacuum = transformation.Attribute == m_domain_mapper.GetVacuumElementAttribute();
|
||||
|
||||
if (element_is_vacuum != m_elevates_vacuum) {
|
||||
mass_tensor.SetSize(m_domain_mapper.GetDimension());
|
||||
@@ -138,34 +125,27 @@ namespace {
|
||||
LoadElement(element_id);
|
||||
|
||||
const mean_field::mapping::ElementMappingData mapping_data{
|
||||
.displacement = *m_displacement_data,
|
||||
.compactification = *m_compactification_data
|
||||
.displacement = *m_displacement_data, .compactification = *m_compactification_data
|
||||
};
|
||||
|
||||
mean_field::mapping::VolumeMappingContext mapping_context;
|
||||
|
||||
const mean_field::mapping::MappingStatus status =
|
||||
m_domain_mapper.EvaluateVolume(
|
||||
mapping_data, transformation, integration_point,
|
||||
m_workspace, mapping_context
|
||||
);
|
||||
const mean_field::mapping::MappingStatus status = m_domain_mapper.EvaluateVolume(
|
||||
mapping_data, transformation, integration_point, m_workspace, mapping_context
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
status == mean_field::mapping::MappingStatus::valid,
|
||||
"Stateless domain mapping failed while preparing the H(div) "
|
||||
"mass "
|
||||
"operator. Mapping status = "
|
||||
<< static_cast<int>(status)
|
||||
<< ", element ID = " << element_id
|
||||
<< static_cast<int>(status) << ", element ID = " << element_id
|
||||
<< ", element attribute = " << transformation.Attribute
|
||||
<< ", coefficient domain = "
|
||||
<< (m_elevates_vacuum ? "vacuum" : "stellar")
|
||||
<< ", coefficient domain = " << (m_elevates_vacuum ? "vacuum" : "stellar")
|
||||
);
|
||||
|
||||
const mfem::DenseMatrix &mapping_jacobian =
|
||||
mapping_context.mapping.mapping_jacobian;
|
||||
const double mapping_determinant =
|
||||
mapping_context.mapping.mapping_determinant;
|
||||
const mfem::DenseMatrix &mapping_jacobian = mapping_context.mapping.mapping_jacobian;
|
||||
const double mapping_determinant = mapping_context.mapping.mapping_determinant;
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(mapping_determinant) && mapping_determinant > 0.0,
|
||||
@@ -183,48 +163,32 @@ namespace {
|
||||
return;
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &displacement_element =
|
||||
*m_fem.displacementFes->GetFE(element_id);
|
||||
const mfem::FiniteElement &compactification_element =
|
||||
*m_fem.compactificationFes->GetFE(element_id);
|
||||
const mfem::FiniteElement &displacement_element = *m_fem.displacementFes->GetFE(element_id);
|
||||
const mfem::FiniteElement &compactification_element = *m_fem.compactificationFes->GetFE(element_id);
|
||||
|
||||
mfem::DofTransformation *displacement_dof_transformation =
|
||||
m_fem.displacementFes->GetElementVDofs(
|
||||
element_id, m_displacement_dofs
|
||||
);
|
||||
m_fem.displacementFes->GetElementVDofs(element_id, m_displacement_dofs);
|
||||
mfem::DofTransformation *compactification_dof_transformation =
|
||||
m_fem.compactificationFes->GetElementDofs(
|
||||
element_id, m_compactification_dofs
|
||||
);
|
||||
m_fem.compactificationFes->GetElementDofs(element_id, m_compactification_dofs);
|
||||
|
||||
m_displacement_local.GetSubVector(
|
||||
m_displacement_dofs, m_element_displacement
|
||||
);
|
||||
m_fem.compactificationCoordinate->GetSubVector(
|
||||
m_compactification_dofs, m_element_compactification
|
||||
);
|
||||
m_displacement_local.GetSubVector(m_displacement_dofs, m_element_displacement);
|
||||
m_fem.compactificationCoordinate->GetSubVector(m_compactification_dofs, m_element_compactification);
|
||||
|
||||
if (displacement_dof_transformation != nullptr) {
|
||||
displacement_dof_transformation->InvTransformPrimal(
|
||||
m_element_displacement
|
||||
);
|
||||
displacement_dof_transformation->InvTransformPrimal(m_element_displacement);
|
||||
}
|
||||
|
||||
if (compactification_dof_transformation != nullptr) {
|
||||
compactification_dof_transformation->InvTransformPrimal(
|
||||
m_element_compactification
|
||||
);
|
||||
compactification_dof_transformation->InvTransformPrimal(m_element_compactification);
|
||||
}
|
||||
|
||||
m_displacement_data = std::make_unique<
|
||||
mean_field::mapping::ElementDisplacementData>(
|
||||
m_displacement_data = std::make_unique<mean_field::mapping::ElementDisplacementData>(
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||
displacement_element, m_element_displacement
|
||||
)
|
||||
);
|
||||
|
||||
m_compactification_data = std::make_unique<
|
||||
mean_field::mapping::ElementCompactificationData>(
|
||||
m_compactification_data = std::make_unique<mean_field::mapping::ElementCompactificationData>(
|
||||
compactification_element, m_element_compactification
|
||||
);
|
||||
|
||||
@@ -242,10 +206,8 @@ namespace {
|
||||
mfem::Vector m_element_displacement;
|
||||
mfem::Vector m_element_compactification;
|
||||
|
||||
std::unique_ptr<mean_field::mapping::ElementDisplacementData>
|
||||
m_displacement_data;
|
||||
std::unique_ptr<mean_field::mapping::ElementCompactificationData>
|
||||
m_compactification_data;
|
||||
std::unique_ptr<mean_field::mapping::ElementDisplacementData> m_displacement_data;
|
||||
std::unique_ptr<mean_field::mapping::ElementCompactificationData> m_compactification_data;
|
||||
|
||||
mean_field::mapping::DomainMapperStateless::Workspace m_workspace;
|
||||
int m_cached_element_id{-1};
|
||||
@@ -261,33 +223,26 @@ namespace mean_field::operators {
|
||||
: Operator(get_operator_size(f)),
|
||||
m_fem(f),
|
||||
m_domain_mapper(domain_mapper) {
|
||||
MFEM_VERIFY(f.mesh != nullptr, "PreparedMappedHDivMassOperator requires a mesh.");
|
||||
MFEM_VERIFY(
|
||||
f.mesh != nullptr, "PreparedMappedHDivMassOperator requires a mesh."
|
||||
f.gravityFluxFes != nullptr, "PreparedMappedHDivMassOperator requires the "
|
||||
"gravity-gradient finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.gravityFluxFes != nullptr,
|
||||
"PreparedMappedHDivMassOperator requires the "
|
||||
"gravity-gradient finite-element space."
|
||||
f.displacementFes != nullptr, "PreparedMappedHDivMassOperator requires the "
|
||||
"displacement finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr,
|
||||
"PreparedMappedHDivMassOperator requires the "
|
||||
"displacement finite-element space."
|
||||
f.compactificationFes != nullptr, "PreparedMappedHDivMassOperator requires the compactification "
|
||||
"finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.compactificationFes != nullptr,
|
||||
"PreparedMappedHDivMassOperator requires the compactification "
|
||||
"finite-element space."
|
||||
f.compactificationCoordinate != nullptr, "PreparedMappedHDivMassOperator requires the compactification "
|
||||
"coordinate."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.compactificationCoordinate != nullptr,
|
||||
"PreparedMappedHDivMassOperator requires the compactification "
|
||||
"coordinate."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr,
|
||||
"PreparedMappedHDivMassOperator requires the quadrature-rule "
|
||||
"factory."
|
||||
f.quadratureFactory != nullptr, "PreparedMappedHDivMassOperator requires the quadrature-rule "
|
||||
"factory."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
domain_mapper.GetDimension() == f.mesh->Dimension(),
|
||||
@@ -295,39 +250,26 @@ namespace mean_field::operators {
|
||||
"dimension."
|
||||
);
|
||||
|
||||
utils::populate_element_mask(
|
||||
f.mesh.get(), utils::DOMAINS::STELLAR, m_stellar_marker
|
||||
);
|
||||
utils::populate_element_mask(
|
||||
f.mesh.get(), utils::DOMAINS::VACUUM, m_vacuum_marker
|
||||
);
|
||||
utils::populate_element_mask(f.mesh.get(), utils::DOMAINS::STELLAR, m_stellar_marker);
|
||||
utils::populate_element_mask(f.mesh.get(), utils::DOMAINS::VACUUM, m_vacuum_marker);
|
||||
|
||||
const int stellar_element_id =
|
||||
find_representative_element(f, m_stellar_marker);
|
||||
const int vacuum_element_id =
|
||||
find_representative_element(f, m_vacuum_marker);
|
||||
const int stellar_element_id = find_representative_element(f, m_stellar_marker);
|
||||
const int vacuum_element_id = find_representative_element(f, m_vacuum_marker);
|
||||
|
||||
MFEM_VERIFY(
|
||||
stellar_element_id >= 0, "PreparedMappedHDivMassOperator requires "
|
||||
"at least one stellar element."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
vacuum_element_id >= 0,
|
||||
"PreparedMappedHDivMassOperator requires at "
|
||||
"least one compactified vacuum element."
|
||||
vacuum_element_id >= 0, "PreparedMappedHDivMassOperator requires at "
|
||||
"least one compactified vacuum element."
|
||||
);
|
||||
|
||||
validate_uniform_domain_discretization(
|
||||
f, m_stellar_marker, stellar_element_id
|
||||
);
|
||||
validate_uniform_domain_discretization(
|
||||
f, m_vacuum_marker, vacuum_element_id
|
||||
);
|
||||
validate_uniform_domain_discretization(f, m_stellar_marker, stellar_element_id);
|
||||
validate_uniform_domain_discretization(f, m_vacuum_marker, vacuum_element_id);
|
||||
}
|
||||
|
||||
void PreparedMappedHDivMassOperator::Prepare(
|
||||
const mfem::Vector &displacement_true
|
||||
) {
|
||||
void PreparedMappedHDivMassOperator::Prepare(const mfem::Vector &displacement_true) {
|
||||
MFEM_VERIFY(
|
||||
displacement_true.Size() == m_fem.displacementFes->GetTrueVSize(),
|
||||
"PreparedMappedHDivMassOperator received a displacement vector "
|
||||
@@ -337,71 +279,48 @@ namespace mean_field::operators {
|
||||
|
||||
for (int i = 0; i < displacement_true.Size(); ++i) {
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(displacement_true(i)),
|
||||
"PreparedMappedHDivMassOperator received a non-finite "
|
||||
"displacement "
|
||||
"value."
|
||||
std::isfinite(displacement_true(i)), "PreparedMappedHDivMassOperator received a non-finite "
|
||||
"displacement "
|
||||
"value."
|
||||
);
|
||||
}
|
||||
|
||||
const int stellar_element_id =
|
||||
find_representative_element(m_fem, m_stellar_marker);
|
||||
const int vacuum_element_id =
|
||||
find_representative_element(m_fem, m_vacuum_marker);
|
||||
const int stellar_element_id = find_representative_element(m_fem, m_stellar_marker);
|
||||
const int vacuum_element_id = find_representative_element(m_fem, m_vacuum_marker);
|
||||
|
||||
const mfem::FiniteElement &stellar_element =
|
||||
*m_fem.gravityFluxFes->GetFE(stellar_element_id);
|
||||
const mfem::FiniteElement &vacuum_element =
|
||||
*m_fem.gravityFluxFes->GetFE(vacuum_element_id);
|
||||
const mfem::FiniteElement &stellar_element = *m_fem.gravityFluxFes->GetFE(stellar_element_id);
|
||||
const mfem::FiniteElement &vacuum_element = *m_fem.gravityFluxFes->GetFE(vacuum_element_id);
|
||||
|
||||
mfem::ElementTransformation &stellar_transformation =
|
||||
*m_fem.mesh->GetElementTransformation(stellar_element_id);
|
||||
mfem::ElementTransformation &vacuum_transformation =
|
||||
*m_fem.mesh->GetElementTransformation(vacuum_element_id);
|
||||
mfem::ElementTransformation &stellar_transformation = *m_fem.mesh->GetElementTransformation(stellar_element_id);
|
||||
mfem::ElementTransformation &vacuum_transformation = *m_fem.mesh->GetElementTransformation(vacuum_element_id);
|
||||
|
||||
m_mass_form.reset();
|
||||
m_stellar_mass_coefficient.reset();
|
||||
m_vacuum_mass_coefficient.reset();
|
||||
|
||||
m_stellar_mass_coefficient =
|
||||
std::make_unique<FrozenMappedHDivMassCoefficient>(
|
||||
m_fem, m_domain_mapper, displacement_true, false
|
||||
);
|
||||
std::make_unique<FrozenMappedHDivMassCoefficient>(m_fem, m_domain_mapper, displacement_true, false);
|
||||
m_vacuum_mass_coefficient =
|
||||
std::make_unique<FrozenMappedHDivMassCoefficient>(
|
||||
m_fem, m_domain_mapper, displacement_true, true
|
||||
);
|
||||
std::make_unique<FrozenMappedHDivMassCoefficient>(m_fem, m_domain_mapper, displacement_true, true);
|
||||
|
||||
m_mass_form =
|
||||
std::make_unique<mfem::ParBilinearForm>(m_fem.gravityFluxFes.get());
|
||||
m_mass_form = std::make_unique<mfem::ParBilinearForm>(m_fem.gravityFluxFes.get());
|
||||
m_mass_form->SetAssemblyLevel(mfem::AssemblyLevel::PARTIAL);
|
||||
|
||||
auto stellar_integrator =
|
||||
std::make_unique<mfem::VectorFEMassIntegrator>(
|
||||
*m_stellar_mass_coefficient
|
||||
);
|
||||
auto vacuum_integrator = std::make_unique<mfem::VectorFEMassIntegrator>(
|
||||
*m_vacuum_mass_coefficient
|
||||
auto stellar_integrator = std::make_unique<mfem::VectorFEMassIntegrator>(*m_stellar_mass_coefficient);
|
||||
auto vacuum_integrator = std::make_unique<mfem::VectorFEMassIntegrator>(*m_vacuum_mass_coefficient);
|
||||
|
||||
m_fem.quadratureFactory->configure_gravity_hdiv_mass(
|
||||
*stellar_integrator, quadrature::QuadratureRole::discretization, stellar_element, stellar_transformation,
|
||||
utils::DOMAINS::STELLAR, quadrature::MappingKind::general
|
||||
);
|
||||
|
||||
m_fem.quadratureFactory->configure_gravity_hdiv_mass(
|
||||
*stellar_integrator, quadrature::QuadratureRole::discretization,
|
||||
stellar_element, stellar_transformation, utils::DOMAINS::STELLAR,
|
||||
quadrature::MappingKind::general
|
||||
*vacuum_integrator, quadrature::QuadratureRole::discretization, vacuum_element, vacuum_transformation,
|
||||
utils::DOMAINS::VACUUM, quadrature::MappingKind::kelvin
|
||||
);
|
||||
|
||||
m_fem.quadratureFactory->configure_gravity_hdiv_mass(
|
||||
*vacuum_integrator, quadrature::QuadratureRole::discretization,
|
||||
vacuum_element, vacuum_transformation, utils::DOMAINS::VACUUM,
|
||||
quadrature::MappingKind::kelvin
|
||||
);
|
||||
|
||||
m_mass_form->AddDomainIntegrator(
|
||||
stellar_integrator.release(), m_stellar_marker
|
||||
);
|
||||
m_mass_form->AddDomainIntegrator(
|
||||
vacuum_integrator.release(), m_vacuum_marker
|
||||
);
|
||||
m_mass_form->AddDomainIntegrator(stellar_integrator.release(), m_stellar_marker);
|
||||
m_mass_form->AddDomainIntegrator(vacuum_integrator.release(), m_vacuum_marker);
|
||||
m_mass_form->Assemble();
|
||||
|
||||
m_is_prepared = true;
|
||||
@@ -434,8 +353,7 @@ namespace mean_field::operators {
|
||||
return m_is_prepared;
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
PreparedMappedHDivMassOperator::GetPreparationCount() const noexcept {
|
||||
std::uint64_t PreparedMappedHDivMassOperator::GetPreparationCount() const noexcept {
|
||||
return m_preparation_count;
|
||||
}
|
||||
} // namespace mean_field::operators
|
||||
File diff suppressed because it is too large
Load Diff
668
libmeanfield/impl/operators/prepared_mass_normalization.cpp
Normal file
668
libmeanfield/impl/operators/prepared_mass_normalization.cpp
Normal file
@@ -0,0 +1,668 @@
|
||||
module;
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <mfem.hpp>
|
||||
|
||||
module mean_field;
|
||||
|
||||
import :operators.prepared_mass_normalization;
|
||||
|
||||
namespace {
|
||||
void validate_finite_vector(
|
||||
const mfem::Vector &vector,
|
||||
const char *message
|
||||
) {
|
||||
for (int index = 0; index < vector.Size(); ++index) {
|
||||
MFEM_VERIFY(std::isfinite(vector(index)), message);
|
||||
}
|
||||
}
|
||||
|
||||
void true_to_local(
|
||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||
const mfem::Vector &trueVector,
|
||||
mfem::Vector &localVector
|
||||
) {
|
||||
MFEM_VERIFY(trueVector.Size() == finiteElementSpace.GetTrueVSize(), "True vector has the wrong size.");
|
||||
|
||||
localVector.SetSize(finiteElementSpace.GetVSize());
|
||||
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->Mult(trueVector, localVector);
|
||||
} else {
|
||||
localVector = trueVector;
|
||||
}
|
||||
}
|
||||
|
||||
const mfem::IntegrationRule &get_mass_normalization_rule(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mfem::FiniteElement &densityElement,
|
||||
const mfem::ElementTransformation &transformation
|
||||
) {
|
||||
using DensityField = mean_field::field::Field<mean_field::field::Density>;
|
||||
|
||||
MFEM_VERIFY(
|
||||
densityElement.GetOrder() == mean_field::field::Density::Scalar::familyOrder,
|
||||
"The mass-normalization element does not match the registered "
|
||||
"density field."
|
||||
);
|
||||
|
||||
const mean_field::quadrature::Query query =
|
||||
DensityField::make_query<mean_field::field::Density::Form::MassNormalization>(
|
||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), std::array<int, 0>{},
|
||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
|
||||
const auto resolution = f.quadratureFactory->get(query, transformation.GetGeometryType());
|
||||
|
||||
MFEM_VERIFY(
|
||||
resolution.integration_rule != nullptr, "The quadrature policy did not return a mass-normalization rule."
|
||||
);
|
||||
|
||||
return *resolution.integration_rule;
|
||||
}
|
||||
|
||||
void validate_shared_gravity_revisions(
|
||||
const mean_field::operators::context::gravity_field::GravityFieldLinearizationContext &gravityContext,
|
||||
const mean_field::operators::MassNormalizationDependencies &dependencies
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
gravityContext.IsPrepared(), "PreparedMassNormalizationOperator requires the shared gravity "
|
||||
"linearization context to be prepared first."
|
||||
);
|
||||
|
||||
const auto &revisions = gravityContext.GetRevisions();
|
||||
|
||||
MFEM_VERIFY(
|
||||
revisions.discretization.value == dependencies.discretization.revision &&
|
||||
revisions.density.value == dependencies.density.revision &&
|
||||
revisions.displacement.value == dependencies.displacement.revision,
|
||||
"PreparedMassNormalizationOperator received dependency revisions "
|
||||
"that do not match the shared gravity context."
|
||||
);
|
||||
}
|
||||
|
||||
void validate_shared_identity_transition(
|
||||
const mean_field::operators::MassNormalizationDependencyStamp &prepared,
|
||||
const mean_field::operators::MassNormalizationDependencyStamp &requested,
|
||||
const char *message
|
||||
) {
|
||||
MFEM_VERIFY(prepared.identity == requested.identity || prepared.revision != requested.revision, message);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace mean_field::operators {
|
||||
PreparedMassNormalizationOperator::PreparedMassNormalizationOperator(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const context::gravity_field::GravityFieldLinearizationContext &gravityContext
|
||||
)
|
||||
: m_fem(f),
|
||||
m_domainMapper(domainMapper),
|
||||
m_gravityContext(gravityContext) {
|
||||
MFEM_VERIFY(m_fem.mesh != nullptr, "PreparedMassNormalizationOperator requires a mesh.");
|
||||
MFEM_VERIFY(
|
||||
m_fem.densityFes != nullptr && m_fem.displacementFes != nullptr && m_fem.compactificationFes != nullptr &&
|
||||
m_fem.compactificationCoordinate != nullptr && m_fem.quadratureFactory != nullptr,
|
||||
"PreparedMassNormalizationOperator requires density, "
|
||||
"displacement, compactification, and quadrature data."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
m_domainMapper.GetDimension() == m_fem.mesh->Dimension(),
|
||||
"PreparedMassNormalizationOperator received a mapper with the "
|
||||
"wrong dimension."
|
||||
);
|
||||
}
|
||||
|
||||
PreparedMassNormalizationReport PreparedMassNormalizationOperator::Prepare(
|
||||
const MassNormalizationStateView &state,
|
||||
const MassNormalizationDependencies &dependencies
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(state.targetMass) && state.targetMass > 0.0,
|
||||
"PreparedMassNormalizationOperator requires a finite, positive "
|
||||
"target mass."
|
||||
);
|
||||
|
||||
validate_shared_gravity_revisions(m_gravityContext, dependencies);
|
||||
|
||||
if (m_isPrepared) {
|
||||
validate_shared_identity_transition(
|
||||
m_preparedDependencies.discretization, dependencies.discretization,
|
||||
"A new mass-normalization discretization identity must also "
|
||||
"change the shared gravity revision."
|
||||
);
|
||||
validate_shared_identity_transition(
|
||||
m_preparedDependencies.density, dependencies.density,
|
||||
"A new mass-normalization density identity must also change "
|
||||
"the shared gravity revision."
|
||||
);
|
||||
validate_shared_identity_transition(
|
||||
m_preparedDependencies.displacement, dependencies.displacement,
|
||||
"A new mass-normalization displacement identity must also "
|
||||
"change the shared gravity revision."
|
||||
);
|
||||
}
|
||||
|
||||
const bool rebuildStaticPlan =
|
||||
!m_isPrepared || dependencies.discretization != m_preparedDependencies.discretization;
|
||||
|
||||
const bool refreshGeometry =
|
||||
rebuildStaticPlan || dependencies.displacement != m_preparedDependencies.displacement;
|
||||
|
||||
const bool refreshDensity = rebuildStaticPlan || dependencies.density != m_preparedDependencies.density;
|
||||
|
||||
const bool updateTargetMass = !m_isPrepared || dependencies.targetMass != m_preparedDependencies.targetMass ||
|
||||
state.targetMass != m_targetMass;
|
||||
|
||||
m_isPrepared = false;
|
||||
|
||||
PreparedMassNormalizationReport report;
|
||||
|
||||
if (rebuildStaticPlan) {
|
||||
BuildStaticPlan();
|
||||
report.rebuiltStaticPlan = true;
|
||||
}
|
||||
|
||||
if (refreshGeometry) {
|
||||
RefreshGeometry(m_gravityContext.GetGeometryContext().GetDisplacement());
|
||||
report.refreshedGeometry = true;
|
||||
}
|
||||
|
||||
if (refreshDensity) {
|
||||
RefreshDensity(m_gravityContext.GetDensity());
|
||||
report.refreshedDensity = true;
|
||||
}
|
||||
|
||||
if (updateTargetMass) {
|
||||
m_targetMass = state.targetMass;
|
||||
report.updatedTargetMass = true;
|
||||
}
|
||||
|
||||
if (refreshGeometry || refreshDensity) {
|
||||
AssembleResidual();
|
||||
report.assembledResidual = true;
|
||||
} else if (updateTargetMass) {
|
||||
m_cachedResidual.SetSize(1);
|
||||
m_cachedResidual(0) = m_currentMass - m_targetMass;
|
||||
++m_preparationCount;
|
||||
report.assembledResidual = true;
|
||||
}
|
||||
|
||||
m_preparedDependencies = dependencies;
|
||||
m_isPrepared = true;
|
||||
return report;
|
||||
}
|
||||
|
||||
void PreparedMassNormalizationOperator::BuildStaticPlan() {
|
||||
m_elements.clear();
|
||||
m_elements.reserve(m_fem.mesh->GetNE());
|
||||
|
||||
const int vacuumAttribute = m_domainMapper.GetVacuumElementAttribute();
|
||||
|
||||
int localStellarElementCount = 0;
|
||||
|
||||
for (int elementId = 0; elementId < m_fem.mesh->GetNE(); ++elementId) {
|
||||
mfem::ElementTransformation *transformation = m_fem.mesh->GetElementTransformation(elementId);
|
||||
|
||||
MFEM_VERIFY(
|
||||
transformation != nullptr, "PreparedMassNormalizationOperator received a null element "
|
||||
"transformation."
|
||||
);
|
||||
|
||||
if (transformation->Attribute == vacuumAttribute) {
|
||||
continue;
|
||||
}
|
||||
|
||||
++localStellarElementCount;
|
||||
m_elements.emplace_back();
|
||||
ElementPAData &data = m_elements.back();
|
||||
data.elementId = elementId;
|
||||
|
||||
data.densityDofTransformation = m_fem.densityFes->GetElementDofs(elementId, data.densityDofs);
|
||||
|
||||
data.displacementDofTransformation =
|
||||
m_fem.displacementFes->GetElementVDofs(elementId, data.displacementDofs);
|
||||
|
||||
data.compactificationDofTransformation =
|
||||
m_fem.compactificationFes->GetElementDofs(elementId, data.compactificationDofs);
|
||||
|
||||
const mfem::FiniteElement &densityElement = *m_fem.densityFes->GetFE(elementId);
|
||||
|
||||
const mfem::IntegrationRule &integrationRule =
|
||||
get_mass_normalization_rule(m_fem, densityElement, *transformation);
|
||||
|
||||
data.quadraturePoints.resize(integrationRule.GetNPoints());
|
||||
|
||||
for (int quadraturePoint = 0; quadraturePoint < integrationRule.GetNPoints(); ++quadraturePoint) {
|
||||
QuadraturePointData &point = data.quadraturePoints[quadraturePoint];
|
||||
|
||||
point.integrationPoint = integrationRule.IntPoint(quadraturePoint);
|
||||
|
||||
point.densityShape.SetSize(densityElement.GetDof());
|
||||
densityElement.CalcShape(point.integrationPoint, point.densityShape);
|
||||
}
|
||||
}
|
||||
|
||||
int globalStellarElementCount = 0;
|
||||
MPI_Allreduce(
|
||||
&localStellarElementCount, &globalStellarElementCount, 1, MPI_INT, MPI_SUM, m_fem.mesh->GetComm()
|
||||
);
|
||||
|
||||
MFEM_VERIFY(globalStellarElementCount > 0, "PreparedMassNormalizationOperator found no stellar elements.");
|
||||
}
|
||||
|
||||
void PreparedMassNormalizationOperator::RefreshGeometry(const mfem::Vector &displacement) {
|
||||
MFEM_VERIFY(
|
||||
displacement.Size() == m_fem.displacementFes->GetTrueVSize(),
|
||||
"PreparedMassNormalizationOperator received a displacement "
|
||||
"vector with the wrong size."
|
||||
);
|
||||
validate_finite_vector(
|
||||
displacement, "PreparedMassNormalizationOperator received a non-finite "
|
||||
"displacement value."
|
||||
);
|
||||
|
||||
mfem::Vector displacementLocal;
|
||||
true_to_local(*m_fem.displacementFes, displacement, displacementLocal);
|
||||
|
||||
mapping::DomainMapperStateless::Workspace workspace(m_fem.mesh->Dimension());
|
||||
|
||||
for (ElementPAData &data : m_elements) {
|
||||
displacementLocal.GetSubVector(data.displacementDofs, data.baseDisplacement);
|
||||
|
||||
m_fem.compactificationCoordinate->GetSubVector(data.compactificationDofs, data.compactification);
|
||||
|
||||
if (data.displacementDofTransformation != nullptr) {
|
||||
data.displacementDofTransformation->InvTransformPrimal(data.baseDisplacement);
|
||||
}
|
||||
|
||||
if (data.compactificationDofTransformation != nullptr) {
|
||||
data.compactificationDofTransformation->InvTransformPrimal(data.compactification);
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &displacementElement = *m_fem.displacementFes->GetFE(data.elementId);
|
||||
|
||||
const mfem::FiniteElement &compactificationElement = *m_fem.compactificationFes->GetFE(data.elementId);
|
||||
|
||||
const mapping::ElementDisplacementData displacementData =
|
||||
mapping::ElementDisplacementDataFromElementVDofs(displacementElement, data.baseDisplacement);
|
||||
|
||||
const mapping::ElementCompactificationData compactificationData(
|
||||
compactificationElement, data.compactification
|
||||
);
|
||||
|
||||
const mapping::ElementMappingData mappingData{
|
||||
.displacement = displacementData, .compactification = compactificationData
|
||||
};
|
||||
|
||||
mfem::ElementTransformation *transformation = m_fem.mesh->GetElementTransformation(data.elementId);
|
||||
|
||||
for (QuadraturePointData &point : data.quadraturePoints) {
|
||||
const mapping::MappingStatus status = m_domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, point.integrationPoint, workspace, point.mappingContext
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
status == mapping::MappingStatus::valid, "Stateless mapping failed while preparing mass "
|
||||
"normalization. Element: "
|
||||
<< data.elementId
|
||||
<< ", attribute: " << transformation->Attribute
|
||||
<< ", status: " << static_cast<int>(status)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PreparedMassNormalizationOperator::RefreshDensity(const mfem::Vector &density) {
|
||||
MFEM_VERIFY(
|
||||
density.Size() == m_fem.densityFes->GetTrueVSize(),
|
||||
"PreparedMassNormalizationOperator received a density vector "
|
||||
"with the wrong size."
|
||||
);
|
||||
validate_finite_vector(
|
||||
density, "PreparedMassNormalizationOperator received a non-finite density "
|
||||
"value."
|
||||
);
|
||||
|
||||
mfem::Vector densityLocal;
|
||||
true_to_local(*m_fem.densityFes, density, densityLocal);
|
||||
|
||||
mfem::Vector elementDensity;
|
||||
|
||||
for (ElementPAData &data : m_elements) {
|
||||
densityLocal.GetSubVector(data.densityDofs, elementDensity);
|
||||
|
||||
if (data.densityDofTransformation != nullptr) {
|
||||
data.densityDofTransformation->InvTransformPrimal(elementDensity);
|
||||
}
|
||||
|
||||
for (QuadraturePointData &point : data.quadraturePoints) {
|
||||
point.density = elementDensity * point.densityShape;
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(point.density), "PreparedMassNormalizationOperator produced a non-finite "
|
||||
"quadrature density."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PreparedMassNormalizationOperator::AssembleResidual() {
|
||||
double localMass = 0.0;
|
||||
|
||||
for (const ElementPAData &data : m_elements) {
|
||||
for (const QuadraturePointData &point : data.quadraturePoints) {
|
||||
localMass += point.density * point.mappingContext.quadrature.weight;
|
||||
}
|
||||
}
|
||||
|
||||
m_currentMass = GlobalSum(localMass);
|
||||
MFEM_VERIFY(std::isfinite(m_currentMass), "PreparedMassNormalizationOperator assembled a non-finite mass.");
|
||||
|
||||
m_cachedResidual.SetSize(1);
|
||||
m_cachedResidual(0) = m_currentMass - m_targetMass;
|
||||
++m_preparationCount;
|
||||
}
|
||||
|
||||
void PreparedMassNormalizationOperator::BuildResidual(mfem::Vector &residual) const {
|
||||
VerifyPrepared();
|
||||
residual = m_cachedResidual;
|
||||
++m_residualApplicationCount;
|
||||
}
|
||||
|
||||
double PreparedMassNormalizationOperator::EvaluateDensityActionLocal(const mfem::Vector &densityVariation) const {
|
||||
MFEM_VERIFY(
|
||||
densityVariation.Size() == m_fem.densityFes->GetTrueVSize(),
|
||||
"Mass-normalization density action received a vector with the "
|
||||
"wrong size."
|
||||
);
|
||||
validate_finite_vector(densityVariation, "Mass-normalization density action received a non-finite value.");
|
||||
|
||||
mfem::Vector densityVariationLocal;
|
||||
true_to_local(*m_fem.densityFes, densityVariation, densityVariationLocal);
|
||||
|
||||
mfem::Vector elementDensityVariation;
|
||||
double localAction = 0.0;
|
||||
|
||||
for (const ElementPAData &data : m_elements) {
|
||||
densityVariationLocal.GetSubVector(data.densityDofs, elementDensityVariation);
|
||||
|
||||
if (data.densityDofTransformation != nullptr) {
|
||||
data.densityDofTransformation->InvTransformPrimal(elementDensityVariation);
|
||||
}
|
||||
|
||||
for (const QuadraturePointData &point : data.quadraturePoints) {
|
||||
localAction += (elementDensityVariation * point.densityShape) * point.mappingContext.quadrature.weight;
|
||||
}
|
||||
}
|
||||
|
||||
return localAction;
|
||||
}
|
||||
|
||||
double PreparedMassNormalizationOperator::EvaluateDisplacementActionLocal(
|
||||
const mfem::Vector &displacementVariation
|
||||
) const {
|
||||
MFEM_VERIFY(
|
||||
displacementVariation.Size() == m_fem.displacementFes->GetTrueVSize(),
|
||||
"Mass-normalization displacement action received a vector with "
|
||||
"the wrong size."
|
||||
);
|
||||
validate_finite_vector(
|
||||
displacementVariation, "Mass-normalization displacement action received a non-finite "
|
||||
"value."
|
||||
);
|
||||
|
||||
mfem::Vector displacementVariationLocal;
|
||||
true_to_local(*m_fem.displacementFes, displacementVariation, displacementVariationLocal);
|
||||
|
||||
mapping::DomainMapperStateless::Workspace workspace(m_fem.mesh->Dimension());
|
||||
|
||||
mfem::Vector elementDisplacementVariation;
|
||||
double localAction = 0.0;
|
||||
|
||||
for (const ElementPAData &data : m_elements) {
|
||||
displacementVariationLocal.GetSubVector(data.displacementDofs, elementDisplacementVariation);
|
||||
|
||||
if (data.displacementDofTransformation != nullptr) {
|
||||
data.displacementDofTransformation->InvTransformPrimal(elementDisplacementVariation);
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &displacementElement = *m_fem.displacementFes->GetFE(data.elementId);
|
||||
|
||||
const mfem::FiniteElement &compactificationElement = *m_fem.compactificationFes->GetFE(data.elementId);
|
||||
|
||||
const mapping::ElementDisplacementData baseDisplacementData =
|
||||
mapping::ElementDisplacementDataFromElementVDofs(displacementElement, data.baseDisplacement);
|
||||
|
||||
const mapping::ElementDisplacementData directionData =
|
||||
mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacementVariation);
|
||||
|
||||
const mapping::ElementCompactificationData compactificationData(
|
||||
compactificationElement, data.compactification
|
||||
);
|
||||
|
||||
const mapping::ElementMappingData mappingData{
|
||||
.displacement = baseDisplacementData, .compactification = compactificationData
|
||||
};
|
||||
|
||||
mfem::ElementTransformation *transformation = m_fem.mesh->GetElementTransformation(data.elementId);
|
||||
|
||||
for (const QuadraturePointData &point : data.quadraturePoints) {
|
||||
mapping::VolumeMappingVariation variation;
|
||||
|
||||
const mapping::MappingStatus status = m_domainMapper.EvaluateVolumeVariation(
|
||||
mappingData, directionData, *transformation, point.integrationPoint, point.mappingContext,
|
||||
workspace, variation
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
status == mapping::MappingStatus::valid, "Stateless mapping variation failed in the "
|
||||
"mass-normalization displacement action. Element: "
|
||||
<< data.elementId
|
||||
<< ", status: " << static_cast<int>(status)
|
||||
);
|
||||
|
||||
localAction += point.density * variation.weight_variation;
|
||||
}
|
||||
}
|
||||
|
||||
return localAction;
|
||||
}
|
||||
|
||||
void PreparedMassNormalizationOperator::ApplyDensityJacobianAction(
|
||||
const mfem::Vector &densityVariation,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
action.SetSize(1);
|
||||
action(0) = GlobalSum(EvaluateDensityActionLocal(densityVariation));
|
||||
++m_actionStatistics.densityApplications;
|
||||
}
|
||||
|
||||
void PreparedMassNormalizationOperator::ApplyDisplacementJacobianAction(
|
||||
const mfem::Vector &displacementVariation,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
action.SetSize(1);
|
||||
action(0) = GlobalSum(EvaluateDisplacementActionLocal(displacementVariation));
|
||||
++m_actionStatistics.displacementApplications;
|
||||
}
|
||||
|
||||
void PreparedMassNormalizationOperator::ApplyCompleteJacobianAction(
|
||||
const mfem::Vector &densityVariation,
|
||||
const mfem::Vector &displacementVariation,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
|
||||
const double localAction =
|
||||
EvaluateDensityActionLocal(densityVariation) + EvaluateDisplacementActionLocal(displacementVariation);
|
||||
|
||||
action.SetSize(1);
|
||||
action(0) = GlobalSum(localAction);
|
||||
++m_actionStatistics.completeApplications;
|
||||
}
|
||||
|
||||
double PreparedMassNormalizationOperator::GlobalSum(const double localValue) const {
|
||||
double globalValue = 0.0;
|
||||
MPI_Allreduce(&localValue, &globalValue, 1, MPI_DOUBLE, MPI_SUM, m_fem.mesh->GetComm());
|
||||
return globalValue;
|
||||
}
|
||||
|
||||
bool PreparedMassNormalizationOperator::IsPrepared() const noexcept {
|
||||
if (!m_isPrepared || !m_gravityContext.IsPrepared()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto &revisions = m_gravityContext.GetRevisions();
|
||||
return revisions.discretization.value == m_preparedDependencies.discretization.revision &&
|
||||
revisions.density.value == m_preparedDependencies.density.revision &&
|
||||
revisions.displacement.value == m_preparedDependencies.displacement.revision;
|
||||
}
|
||||
|
||||
double PreparedMassNormalizationOperator::GetCurrentMass() const {
|
||||
VerifyPrepared();
|
||||
return m_currentMass;
|
||||
}
|
||||
|
||||
double PreparedMassNormalizationOperator::GetTargetMass() const {
|
||||
VerifyPrepared();
|
||||
return m_targetMass;
|
||||
}
|
||||
|
||||
std::uint64_t PreparedMassNormalizationOperator::GetPreparationCount() const noexcept {
|
||||
return m_preparationCount;
|
||||
}
|
||||
|
||||
std::uint64_t PreparedMassNormalizationOperator::GetResidualApplicationCount() const noexcept {
|
||||
return m_residualApplicationCount;
|
||||
}
|
||||
|
||||
const PreparedMassNormalizationActionStatistics &
|
||||
PreparedMassNormalizationOperator::GetActionStatistics() const noexcept {
|
||||
return m_actionStatistics;
|
||||
}
|
||||
|
||||
const fem::FEM &PreparedMassNormalizationOperator::GetFEM() const noexcept {
|
||||
return m_fem;
|
||||
}
|
||||
|
||||
const context::gravity_field::GravityFieldLinearizationContext &
|
||||
PreparedMassNormalizationOperator::GetGravityContext() const noexcept {
|
||||
return m_gravityContext;
|
||||
}
|
||||
|
||||
void PreparedMassNormalizationOperator::VerifyPrepared() const {
|
||||
MFEM_VERIFY(
|
||||
IsPrepared(), "PreparedMassNormalizationOperator must be prepared for the "
|
||||
"current shared gravity-context revisions."
|
||||
);
|
||||
}
|
||||
|
||||
PreparedMassNormalizationJacobianOperator::PreparedMassNormalizationJacobianOperator(
|
||||
const MassNormalizationLayout &layout,
|
||||
const PreparedMassNormalizationOperator &preparedOperator
|
||||
)
|
||||
: mfem::Operator(
|
||||
layout.residual_offsets().Last(),
|
||||
layout.value_offsets().Last()
|
||||
),
|
||||
m_layout(layout),
|
||||
m_preparedOperator(preparedOperator) {
|
||||
const fem::FEM &f = m_preparedOperator.GetFEM();
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr && f.displacementFes != nullptr && f.gravityFluxFes != nullptr &&
|
||||
f.gravityPotentialFes != nullptr && f.enthalpyFes != nullptr,
|
||||
"Prepared mass-normalization MFEM adapter requires every "
|
||||
"finite-element space in the barotropic equilibrium layout."
|
||||
);
|
||||
|
||||
using Form = utils::blocks::barotropic_equilibrium_form;
|
||||
|
||||
constexpr auto densityValue = utils::blocks::get_value_block<Form>(utils::blocks::density_field.mass_term);
|
||||
constexpr auto displacementValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
constexpr auto gravityGradientValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::gravity_field.gradient_term);
|
||||
constexpr auto gravityPotentialValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::gravity_field.poisson_term);
|
||||
constexpr auto enthalpyValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::enthalpy_field.specific_term);
|
||||
constexpr auto barotropicConstantValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::barotropic_constant_field.mass_normalization_term);
|
||||
constexpr auto gravityGradientResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::gravity_field.gradient_term);
|
||||
constexpr auto gravityPotentialResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::gravity_field.poisson_term);
|
||||
constexpr auto densityResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::density_field.mass_term);
|
||||
constexpr auto displacementResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
constexpr auto enthalpyResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::enthalpy_field.specific_term);
|
||||
constexpr auto massResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::barotropic_constant_field.mass_normalization_term);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_layout.size(densityValue) == f.densityFes->GetTrueVSize() &&
|
||||
m_layout.size(displacementValue) == f.displacementFes->GetTrueVSize() &&
|
||||
m_layout.size(gravityGradientValue) == f.gravityFluxFes->GetTrueVSize() &&
|
||||
m_layout.size(gravityPotentialValue) == f.gravityPotentialFes->GetTrueVSize() &&
|
||||
m_layout.size(enthalpyValue) == f.enthalpyFes->GetTrueVSize() &&
|
||||
m_layout.size(barotropicConstantValue) == 1 &&
|
||||
m_layout.size(gravityGradientResidual) == f.gravityFluxFes->GetTrueVSize() &&
|
||||
m_layout.size(gravityPotentialResidual) == f.gravityPotentialFes->GetTrueVSize() &&
|
||||
m_layout.size(densityResidual) == f.densityFes->GetTrueVSize() &&
|
||||
m_layout.size(displacementResidual) == f.displacementFes->GetTrueVSize() &&
|
||||
m_layout.size(enthalpyResidual) == f.enthalpyFes->GetTrueVSize() && m_layout.size(massResidual) == 1,
|
||||
"Prepared mass-normalization MFEM adapter received incompatible "
|
||||
"barotropic block sizes."
|
||||
);
|
||||
}
|
||||
|
||||
void PreparedMassNormalizationJacobianOperator::Mult(
|
||||
const mfem::Vector &direction,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
MFEM_VERIFY(
|
||||
m_preparedOperator.IsPrepared(), "Prepared mass-normalization MFEM adapter requires a prepared "
|
||||
"row operator."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
direction.Size() == Width(), "Prepared mass-normalization MFEM adapter received a direction "
|
||||
"with the wrong size."
|
||||
);
|
||||
|
||||
using Form = utils::blocks::barotropic_equilibrium_form;
|
||||
|
||||
constexpr auto densityValue = utils::blocks::get_value_block<Form>(utils::blocks::density_field.mass_term);
|
||||
constexpr auto displacementValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
constexpr auto massResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::barotropic_constant_field.mass_normalization_term);
|
||||
|
||||
const mfem::Vector densityVariation(
|
||||
const_cast<mfem::real_t *>(direction.GetData()) + m_layout.offset(densityValue), m_layout.size(densityValue)
|
||||
);
|
||||
|
||||
const mfem::Vector displacementVariation(
|
||||
const_cast<mfem::real_t *>(direction.GetData()) + m_layout.offset(displacementValue),
|
||||
m_layout.size(displacementValue)
|
||||
);
|
||||
|
||||
mfem::Vector massAction;
|
||||
m_preparedOperator.ApplyCompleteJacobianAction(densityVariation, displacementVariation, massAction);
|
||||
|
||||
action.SetSize(Height());
|
||||
action = 0.0;
|
||||
action(m_layout.offset(massResidual)) = massAction(0);
|
||||
}
|
||||
|
||||
const MassNormalizationLayout &PreparedMassNormalizationJacobianOperator::GetLayout() const noexcept {
|
||||
return m_layout;
|
||||
}
|
||||
} // namespace mean_field::operators
|
||||
1137
libmeanfield/impl/operators/prepared_pressure_force.cpp
Normal file
1137
libmeanfield/impl/operators/prepared_pressure_force.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,288 @@
|
||||
module;
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
module mean_field;
|
||||
|
||||
import :operators.kernels.rotational_displacement_force;
|
||||
import :operators.prepared_rotational_displacement_force;
|
||||
|
||||
namespace mean_field::operators {
|
||||
PreparedRotationalDisplacementForceOperator::PreparedRotationalDisplacementForceOperator(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper
|
||||
)
|
||||
: m_fem(f),
|
||||
m_domainMapper(domainMapper),
|
||||
m_context(
|
||||
f,
|
||||
domainMapper
|
||||
) {
|
||||
MFEM_VERIFY(m_fem.mesh != nullptr, "PreparedRotationalDisplacementForceOperator requires a mesh.");
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_fem.mesh->Dimension() == 3, "PreparedRotationalDisplacementForceOperator requires a "
|
||||
"three-dimensional mesh."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_fem.densityFes != nullptr && m_fem.displacementFes != nullptr,
|
||||
"PreparedRotationalDisplacementForceOperator requires density "
|
||||
"and displacement finite-element spaces."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_fem.compactificationFes != nullptr && m_fem.compactificationCoordinate != nullptr,
|
||||
"PreparedRotationalDisplacementForceOperator requires the "
|
||||
"compactification coordinate."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_fem.quadratureFactory != nullptr, "PreparedRotationalDisplacementForceOperator requires the "
|
||||
"quadrature-rule factory."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_domainMapper.GetDimension() == m_fem.mesh->Dimension(),
|
||||
"PreparedRotationalDisplacementForceOperator received a mapper "
|
||||
"with the wrong dimension."
|
||||
);
|
||||
}
|
||||
|
||||
PreparedRotationalDisplacementForceReport PreparedRotationalDisplacementForceOperator::Prepare(
|
||||
const context::rotational_displacement_force::RotationalDisplacementForceStateView &state,
|
||||
const context::rotational_displacement_force::RotationalDisplacementForceDependencies &dependencies,
|
||||
const physics::RigidRotation &rotation
|
||||
) {
|
||||
const bool rotationChanged =
|
||||
!m_context.IsPrepared() || dependencies.rotation != m_context.GetDependencies().rotation;
|
||||
|
||||
PreparedRotationalDisplacementForceReport report;
|
||||
report.contextReport = m_context.Prepare(state, dependencies);
|
||||
|
||||
if (!report.contextReport.DidAnyWork()) {
|
||||
return report;
|
||||
}
|
||||
|
||||
m_isPrepared = false;
|
||||
|
||||
if (rotationChanged) {
|
||||
m_rotation = rotation;
|
||||
report.updatedRotation = true;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_rotation.has_value(), "PreparedRotationalDisplacementForceOperator has no frozen "
|
||||
"rotation state."
|
||||
);
|
||||
|
||||
if (report.contextReport.preparedBaseState) {
|
||||
kernels::apply_rotational_displacement_force_residual(
|
||||
m_fem, m_domainMapper, *m_rotation, m_context.GetBaseDensityTrue(), m_context.GetDisplacementTrue(),
|
||||
m_cachedResidual
|
||||
);
|
||||
|
||||
++m_residualPreparationCount;
|
||||
report.preparedResidual = true;
|
||||
}
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_cachedResidual.Size() == m_fem.displacementFes->GetTrueVSize(),
|
||||
"The prepared rotational-displacement-force residual has the "
|
||||
"wrong size."
|
||||
);
|
||||
|
||||
m_preparedDependencies = dependencies;
|
||||
m_isPrepared = true;
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
void PreparedRotationalDisplacementForceOperator::BuildResidual(mfem::Vector &residual) const {
|
||||
VerifyPrepared();
|
||||
residual = m_cachedResidual;
|
||||
++m_residualApplicationCount;
|
||||
}
|
||||
|
||||
void PreparedRotationalDisplacementForceOperator::ApplyDensityJacobianAction(
|
||||
const mfem::Vector &densityVariation,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
|
||||
kernels::apply_rotational_displacement_force_density_action(
|
||||
m_fem, m_domainMapper, *m_rotation, densityVariation, m_context.GetDisplacementTrue(), action
|
||||
);
|
||||
|
||||
++m_densityJacobianStatistics.applications;
|
||||
}
|
||||
|
||||
void PreparedRotationalDisplacementForceOperator::ApplyDisplacementJacobianAction(
|
||||
const mfem::Vector &displacementVariation,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
|
||||
kernels::apply_rotational_displacement_force_displacement_action(
|
||||
m_fem, m_domainMapper, *m_rotation, m_context.GetBaseDensityTrue(), displacementVariation,
|
||||
m_context.GetDisplacementTrue(), action
|
||||
);
|
||||
|
||||
++m_displacementJacobianStatistics.applications;
|
||||
}
|
||||
|
||||
void PreparedRotationalDisplacementForceOperator::ApplyCompleteJacobianAction(
|
||||
const mfem::Vector &densityVariation,
|
||||
const mfem::Vector &displacementVariation,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
|
||||
kernels::apply_rotational_displacement_force_complete_action(
|
||||
m_fem, m_domainMapper, *m_rotation, m_context.GetBaseDensityTrue(), densityVariation, displacementVariation,
|
||||
m_context.GetDisplacementTrue(), action
|
||||
);
|
||||
|
||||
++m_densityJacobianStatistics.applications;
|
||||
++m_displacementJacobianStatistics.applications;
|
||||
++m_completeJacobianStatistics.applications;
|
||||
}
|
||||
|
||||
bool PreparedRotationalDisplacementForceOperator::IsPrepared() const noexcept {
|
||||
return m_isPrepared && m_rotation.has_value() && m_context.MatchesDependencies(m_preparedDependencies);
|
||||
}
|
||||
|
||||
const context::rotational_displacement_force::RotationalDisplacementForcePreparationStatistics &
|
||||
PreparedRotationalDisplacementForceOperator::GetContextPreparationStatistics() const noexcept {
|
||||
return m_context.GetPreparationStatistics();
|
||||
}
|
||||
|
||||
std::uint64_t PreparedRotationalDisplacementForceOperator::GetResidualPreparationCount() const noexcept {
|
||||
return m_residualPreparationCount;
|
||||
}
|
||||
|
||||
std::uint64_t PreparedRotationalDisplacementForceOperator::GetResidualApplicationCount() const noexcept {
|
||||
return m_residualApplicationCount;
|
||||
}
|
||||
|
||||
const PreparedRotationalDisplacementForceColumnStatistics &
|
||||
PreparedRotationalDisplacementForceOperator::GetDensityJacobianStatistics() const noexcept {
|
||||
return m_densityJacobianStatistics;
|
||||
}
|
||||
|
||||
const PreparedRotationalDisplacementForceColumnStatistics &
|
||||
PreparedRotationalDisplacementForceOperator::GetDisplacementJacobianStatistics() const noexcept {
|
||||
return m_displacementJacobianStatistics;
|
||||
}
|
||||
|
||||
const PreparedRotationalDisplacementForceCompleteStatistics &
|
||||
PreparedRotationalDisplacementForceOperator::GetCompleteJacobianStatistics() const noexcept {
|
||||
return m_completeJacobianStatistics;
|
||||
}
|
||||
|
||||
const fem::FEM &PreparedRotationalDisplacementForceOperator::GetFEM() const noexcept {
|
||||
return m_fem;
|
||||
}
|
||||
|
||||
const context::rotational_displacement_force::RotationalDisplacementForceLinearizationContext &
|
||||
PreparedRotationalDisplacementForceOperator::GetContext() const noexcept {
|
||||
return m_context;
|
||||
}
|
||||
|
||||
void PreparedRotationalDisplacementForceOperator::VerifyPrepared() const {
|
||||
MFEM_VERIFY(
|
||||
IsPrepared(), "PreparedRotationalDisplacementForceOperator must be prepared "
|
||||
"for the current revisions before residual or Jacobian "
|
||||
"application."
|
||||
);
|
||||
}
|
||||
|
||||
PreparedRotationalDisplacementForceJacobianOperator::PreparedRotationalDisplacementForceJacobianOperator(
|
||||
const RotationalDisplacementForceLayout &layout,
|
||||
const PreparedRotationalDisplacementForceOperator &preparedOperator
|
||||
)
|
||||
: mfem::Operator(
|
||||
layout.residual_offsets().Last(),
|
||||
layout.value_offsets().Last()
|
||||
),
|
||||
m_layout(layout),
|
||||
m_preparedOperator(preparedOperator) {
|
||||
const fem::FEM &f = m_preparedOperator.GetFEM();
|
||||
|
||||
using Form = utils::blocks::barotropic_equilibrium_form;
|
||||
|
||||
constexpr auto densityValue = utils::blocks::get_value_block<Form>(utils::blocks::density_field.mass_term);
|
||||
|
||||
constexpr auto displacementValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
|
||||
constexpr auto displacementResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_layout.size(densityValue) == f.densityFes->GetTrueVSize() &&
|
||||
m_layout.size(displacementValue) == f.displacementFes->GetTrueVSize() &&
|
||||
m_layout.size(displacementResidual) == f.displacementFes->GetTrueVSize(),
|
||||
"Prepared rotational-displacement-force MFEM adapter received "
|
||||
"incompatible coupled block sizes."
|
||||
);
|
||||
}
|
||||
|
||||
void PreparedRotationalDisplacementForceJacobianOperator::Mult(
|
||||
const mfem::Vector &direction,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
MFEM_VERIFY(
|
||||
m_preparedOperator.IsPrepared(), "Prepared rotational-displacement-force MFEM adapter requires "
|
||||
"a prepared operator."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
direction.Size() == Width(), "Prepared rotational-displacement-force MFEM adapter received "
|
||||
"a direction with the wrong size."
|
||||
);
|
||||
|
||||
using Form = utils::blocks::barotropic_equilibrium_form;
|
||||
|
||||
constexpr auto densityValue = utils::blocks::get_value_block<Form>(utils::blocks::density_field.mass_term);
|
||||
|
||||
constexpr auto displacementValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
|
||||
constexpr auto displacementResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
|
||||
const mfem::Vector densityVariation(
|
||||
const_cast<mfem::real_t *>(direction.GetData()) + m_layout.offset(densityValue), m_layout.size(densityValue)
|
||||
);
|
||||
|
||||
const mfem::Vector displacementVariation(
|
||||
const_cast<mfem::real_t *>(direction.GetData()) + m_layout.offset(displacementValue),
|
||||
m_layout.size(displacementValue)
|
||||
);
|
||||
|
||||
mfem::Vector displacementAction;
|
||||
|
||||
m_preparedOperator.ApplyCompleteJacobianAction(densityVariation, displacementVariation, displacementAction);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementAction.Size() == m_layout.size(displacementResidual),
|
||||
"Prepared rotational-displacement-force MFEM adapter produced "
|
||||
"a displacement action with the wrong size."
|
||||
);
|
||||
|
||||
action.SetSize(Height());
|
||||
action = 0.0;
|
||||
|
||||
const int residualOffset = m_layout.offset(displacementResidual);
|
||||
|
||||
for (int entry = 0; entry < displacementAction.Size(); ++entry) {
|
||||
action(residualOffset + entry) = displacementAction(entry);
|
||||
}
|
||||
}
|
||||
|
||||
const RotationalDisplacementForceLayout &
|
||||
PreparedRotationalDisplacementForceJacobianOperator::GetLayout() const noexcept {
|
||||
return m_layout;
|
||||
}
|
||||
} // namespace mean_field::operators
|
||||
809
libmeanfield/impl/operators/prepared_stellar_equilibrium.cpp
Normal file
809
libmeanfield/impl/operators/prepared_stellar_equilibrium.cpp
Normal file
@@ -0,0 +1,809 @@
|
||||
module;
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
module mean_field;
|
||||
|
||||
import :operators.prepared_stellar_equilibrium;
|
||||
import :physics.gravity;
|
||||
|
||||
namespace {
|
||||
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||
|
||||
[[nodiscard]] mean_field::fem::FEM &ensure_gravity_static_operators(mean_field::fem::FEM &f) {
|
||||
MFEM_VERIFY(
|
||||
f.mesh != nullptr && f.densityFes != nullptr && f.displacementFes != nullptr &&
|
||||
f.gravityFluxFes != nullptr && f.gravityPotentialFes != nullptr && f.enthalpyFes != nullptr,
|
||||
"PreparedStellarEquilibriumOperator requires the complete coupled finite-element discretization."
|
||||
);
|
||||
|
||||
if (f.gravityContext.b_form == nullptr || f.gravityContext.BT == nullptr) {
|
||||
mean_field::physics::update_stiffness_matrix(f);
|
||||
}
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.gravityContext.b_form != nullptr && f.gravityContext.BT != nullptr,
|
||||
"PreparedStellarEquilibriumOperator could not initialize the static gravity divergence operators."
|
||||
);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
[[nodiscard]] mean_field::operators::StellarEquilibriumLayout make_layout(
|
||||
const mean_field::field::FieldDofMap &densityMap,
|
||||
const mean_field::field::FieldDofMap &displacementMap,
|
||||
const mean_field::field::FieldDofMap &gravityFluxMap,
|
||||
const mean_field::field::FieldDofMap &gravityPotentialMap,
|
||||
const mean_field::field::FieldDofMap &enthalpyMap
|
||||
) {
|
||||
using Form = mean_field::utils::blocks::barotropic_equilibrium_form;
|
||||
|
||||
const std::array<int, Form::value_block_count> valueSizes{
|
||||
densityMap.reduced_size(), displacementMap.reduced_size(), gravityFluxMap.reduced_size(),
|
||||
gravityPotentialMap.reduced_size(), enthalpyMap.reduced_size(), 1
|
||||
};
|
||||
|
||||
const std::array<int, Form::residual_block_count> residualSizes{
|
||||
gravityFluxMap.reduced_size(), gravityPotentialMap.reduced_size(), densityMap.reduced_size(),
|
||||
displacementMap.reduced_size(), enthalpyMap.reduced_size(), 1
|
||||
};
|
||||
|
||||
return {valueSizes, residualSizes};
|
||||
}
|
||||
|
||||
[[nodiscard]] mfem::Array<int> make_gravity_state_offsets(const mean_field::fem::FEM &f) {
|
||||
mfem::Array<int> offsets(5);
|
||||
offsets[0] = 0;
|
||||
offsets[1] = offsets[0] + f.densityFes->GetTrueVSize();
|
||||
offsets[2] = offsets[1] + f.displacementFes->GetTrueVSize();
|
||||
offsets[3] = offsets[2] + f.gravityFluxFes->GetTrueVSize();
|
||||
offsets[4] = offsets[3] + f.gravityPotentialFes->GetTrueVSize();
|
||||
return offsets;
|
||||
}
|
||||
|
||||
[[nodiscard]] mfem::Array<int> make_gravity_residual_offsets(const mean_field::fem::FEM &f) {
|
||||
mfem::Array<int> offsets(3);
|
||||
offsets[0] = 0;
|
||||
offsets[1] = f.gravityFluxFes->GetTrueVSize();
|
||||
offsets[2] = offsets[1] + f.gravityPotentialFes->GetTrueVSize();
|
||||
return offsets;
|
||||
}
|
||||
|
||||
template <int index>
|
||||
[[nodiscard]] mfem::Vector make_value_view(
|
||||
const mfem::Vector &vector,
|
||||
const mean_field::operators::StellarEquilibriumLayout &layout,
|
||||
const mean_field::utils::blocks::value_block<index> block
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
vector.Size() == layout.value_offsets().Last(),
|
||||
"The coupled vector does not match the stellar-equilibrium value layout."
|
||||
);
|
||||
|
||||
return mfem::Vector(const_cast<mfem::real_t *>(vector.GetData()) + layout.offset(block), layout.size(block));
|
||||
}
|
||||
|
||||
template <int index>
|
||||
[[nodiscard]] mfem::Vector make_residual_view(
|
||||
mfem::Vector &vector,
|
||||
const mean_field::operators::StellarEquilibriumLayout &layout,
|
||||
const mean_field::utils::blocks::residual_block<index> block
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
vector.Size() == layout.residual_offsets().Last(),
|
||||
"The coupled vector does not match the stellar-equilibrium residual layout."
|
||||
);
|
||||
|
||||
return mfem::Vector(vector.GetData() + layout.offset(block), layout.size(block));
|
||||
}
|
||||
|
||||
template <int index>
|
||||
void assign_residual_block(
|
||||
mfem::Vector &coupledResidual,
|
||||
const mean_field::operators::StellarEquilibriumLayout &layout,
|
||||
const mean_field::utils::blocks::residual_block<index> block,
|
||||
const mfem::Vector &blockResidual,
|
||||
const char *message
|
||||
) {
|
||||
MFEM_VERIFY(layout.size(block) == blockResidual.Size(), message);
|
||||
mfem::Vector destination = make_residual_view(coupledResidual, layout, block);
|
||||
destination = blockResidual;
|
||||
}
|
||||
|
||||
void assign_gravity_block(
|
||||
mfem::Vector &gravityState,
|
||||
const mfem::Array<int> &offsets,
|
||||
const int blockIndex,
|
||||
const mfem::Vector &source,
|
||||
const char *message
|
||||
) {
|
||||
MFEM_VERIFY(offsets.Size() == 5, "Gravity state offsets are invalid.");
|
||||
MFEM_VERIFY(blockIndex >= 0 && blockIndex + 1 < offsets.Size(), "Requested gravity-state block is invalid.");
|
||||
|
||||
const int blockSize = offsets[blockIndex + 1] - offsets[blockIndex];
|
||||
MFEM_VERIFY(blockSize == source.Size(), message);
|
||||
MFEM_VERIFY(gravityState.Size() == offsets.Last(), "Packed gravity state has the wrong size.");
|
||||
|
||||
mfem::Vector destination(gravityState.GetData() + offsets[blockIndex], blockSize);
|
||||
destination = source;
|
||||
}
|
||||
|
||||
void pack_gravity_vector(
|
||||
mfem::Vector &gravityState,
|
||||
const mfem::Array<int> &offsets,
|
||||
const mfem::Vector &density,
|
||||
const mfem::Vector &displacement,
|
||||
const mfem::Vector &gravityGradient,
|
||||
const mfem::Vector &gravityPotential
|
||||
) {
|
||||
MFEM_VERIFY(offsets.Size() == 5, "Packed gravity state requires four blocks.");
|
||||
if (gravityState.Size() != offsets.Last()) {
|
||||
gravityState.SetSize(offsets.Last());
|
||||
}
|
||||
|
||||
assign_gravity_block(
|
||||
gravityState, offsets, 0, density, "The full density vector has the wrong gravity-state size."
|
||||
);
|
||||
assign_gravity_block(
|
||||
gravityState, offsets, 1, displacement, "The displacement vector has the wrong gravity-state size."
|
||||
);
|
||||
assign_gravity_block(
|
||||
gravityState, offsets, 2, gravityGradient, "The gravity-gradient vector has the wrong gravity-state size."
|
||||
);
|
||||
assign_gravity_block(
|
||||
gravityState, offsets, 3, gravityPotential, "The gravity-potential vector has the wrong gravity-state size."
|
||||
);
|
||||
}
|
||||
|
||||
void validate_finite_vector(
|
||||
const mfem::Vector &vector,
|
||||
const char *message
|
||||
) {
|
||||
for (int index = 0; index < vector.Size(); ++index) {
|
||||
MFEM_VERIFY(std::isfinite(vector(index)), message);
|
||||
}
|
||||
}
|
||||
|
||||
void validate_dependency_transition(
|
||||
const mean_field::operators::StellarEquilibriumDependencyStamp &prepared,
|
||||
const mean_field::operators::StellarEquilibriumDependencyStamp &requested,
|
||||
const char *message
|
||||
) {
|
||||
MFEM_VERIFY(prepared.identity != requested.identity || requested.revision >= prepared.revision, message);
|
||||
MFEM_VERIFY(
|
||||
prepared.identity == requested.identity || prepared.revision != requested.revision,
|
||||
"A new stellar-equilibrium dependency identity must also carry a visibly different revision."
|
||||
);
|
||||
}
|
||||
|
||||
[[nodiscard]] mean_field::operators::context::gravity_field::GravityFieldRevisions
|
||||
make_gravity_revisions(const mean_field::operators::StellarEquilibriumDependencies &dependencies) {
|
||||
return {
|
||||
.discretization = {.value = dependencies.discretization.revision},
|
||||
.displacement = {.value = dependencies.displacement.revision},
|
||||
.density = {.value = dependencies.density.revision},
|
||||
.gravity_gradient = {.value = dependencies.gravityGradient.revision},
|
||||
.gravity_potential = {.value = dependencies.gravityPotential.revision}
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] mean_field::operators::context::barotropic::BarotropicClosureDependencies
|
||||
make_barotropic_closure_dependencies(const mean_field::operators::StellarEquilibriumDependencies &dependencies) {
|
||||
return {
|
||||
.discretization =
|
||||
{.identity = dependencies.discretization.identity, .revision = dependencies.discretization.revision},
|
||||
.density = {.identity = dependencies.density.identity, .revision = dependencies.density.revision},
|
||||
.enthalpy = {.identity = dependencies.enthalpy.identity, .revision = dependencies.enthalpy.revision},
|
||||
.displacement = {
|
||||
.identity = dependencies.displacement.identity, .revision = dependencies.displacement.revision
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] mean_field::operators::DisplacementResidualDependencies
|
||||
make_displacement_dependencies(const mean_field::operators::StellarEquilibriumDependencies &dependencies) {
|
||||
return {
|
||||
.discretization =
|
||||
{.identity = dependencies.discretization.identity, .revision = dependencies.discretization.revision},
|
||||
.density = {.identity = dependencies.density.identity, .revision = dependencies.density.revision},
|
||||
.displacement =
|
||||
{.identity = dependencies.displacement.identity, .revision = dependencies.displacement.revision},
|
||||
.gravityGradient =
|
||||
{.identity = dependencies.gravityGradient.identity, .revision = dependencies.gravityGradient.revision},
|
||||
.enthalpy = {.identity = dependencies.enthalpy.identity, .revision = dependencies.enthalpy.revision},
|
||||
.rotation = {.identity = dependencies.rotation.identity, .revision = dependencies.rotation.revision}
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] mean_field::operators::context::hydrostatic::HydrostaticEquilibriumDependencies
|
||||
make_hydrostatic_dependencies(const mean_field::operators::StellarEquilibriumDependencies &dependencies) {
|
||||
return {
|
||||
.discretization =
|
||||
{.identity = dependencies.discretization.identity, .revision = dependencies.discretization.revision},
|
||||
.enthalpy = {.identity = dependencies.enthalpy.identity, .revision = dependencies.enthalpy.revision},
|
||||
.gravityPotential =
|
||||
{.identity = dependencies.gravityPotential.identity,
|
||||
.revision = dependencies.gravityPotential.revision},
|
||||
.displacement =
|
||||
{.identity = dependencies.displacement.identity, .revision = dependencies.displacement.revision},
|
||||
.rotation = {.identity = dependencies.rotation.identity, .revision = dependencies.rotation.revision},
|
||||
.bernoulliConstant = {
|
||||
.identity = dependencies.bernoulliConstant.identity, .revision = dependencies.bernoulliConstant.revision
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[[nodiscard]] mean_field::operators::MassNormalizationDependencies
|
||||
make_mass_dependencies(const mean_field::operators::StellarEquilibriumDependencies &dependencies) {
|
||||
return {
|
||||
.discretization =
|
||||
{.identity = dependencies.discretization.identity, .revision = dependencies.discretization.revision},
|
||||
.density = {.identity = dependencies.density.identity, .revision = dependencies.density.revision},
|
||||
.displacement =
|
||||
{.identity = dependencies.displacement.identity, .revision = dependencies.displacement.revision},
|
||||
.targetMass = {.identity = dependencies.targetMass.identity, .revision = dependencies.targetMass.revision}
|
||||
};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace mean_field::operators {
|
||||
struct PreparedStellarEquilibriumOperator::ConstructionData {
|
||||
field::FieldDofMap densityMap;
|
||||
field::FieldDofMap displacementMap;
|
||||
field::FieldDofMap gravityFluxMap;
|
||||
field::FieldDofMap gravityPotentialMap;
|
||||
field::FieldDofMap enthalpyMap;
|
||||
|
||||
StellarEquilibriumLayout layout;
|
||||
mfem::Array<int> gravityStateOffsets;
|
||||
mfem::Array<int> gravityResidualOffsets;
|
||||
|
||||
explicit ConstructionData(fem::FEM &f)
|
||||
: densityMap(
|
||||
field::make_field_dof_map<
|
||||
field::Density,
|
||||
DomainSchema>(*f.densityFes)
|
||||
),
|
||||
displacementMap(
|
||||
field::make_field_dof_map<
|
||||
field::Displacement,
|
||||
DomainSchema>(*f.displacementFes)
|
||||
),
|
||||
gravityFluxMap(
|
||||
field::make_field_dof_map<
|
||||
field::Gravity,
|
||||
DomainSchema>(*f.gravityFluxFes)
|
||||
),
|
||||
gravityPotentialMap(
|
||||
field::make_field_dof_map<
|
||||
field::Gravity,
|
||||
DomainSchema>(*f.gravityPotentialFes)
|
||||
),
|
||||
enthalpyMap(
|
||||
field::make_field_dof_map<
|
||||
field::Enthalpy,
|
||||
DomainSchema>(*f.enthalpyFes)
|
||||
),
|
||||
layout(make_layout(
|
||||
densityMap,
|
||||
displacementMap,
|
||||
gravityFluxMap,
|
||||
gravityPotentialMap,
|
||||
enthalpyMap
|
||||
)),
|
||||
gravityStateOffsets(make_gravity_state_offsets(f)),
|
||||
gravityResidualOffsets(make_gravity_residual_offsets(f)) {
|
||||
}
|
||||
};
|
||||
|
||||
PreparedStellarEquilibriumOperator::ConstructionData
|
||||
PreparedStellarEquilibriumOperator::MakeConstructionData(fem::FEM &f) {
|
||||
ensure_gravity_static_operators(f);
|
||||
return ConstructionData(f);
|
||||
}
|
||||
|
||||
PreparedStellarEquilibriumOperator::PreparedStellarEquilibriumOperator(
|
||||
fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const eos::Polytrope &equationOfState,
|
||||
const models::StellarModel &stellarModel
|
||||
)
|
||||
: PreparedStellarEquilibriumOperator(
|
||||
f,
|
||||
domainMapper,
|
||||
equationOfState,
|
||||
stellarModel.targetMass()
|
||||
) {
|
||||
}
|
||||
|
||||
PreparedStellarEquilibriumOperator::PreparedStellarEquilibriumOperator(
|
||||
fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const eos::Polytrope &equationOfState,
|
||||
const double targetMass
|
||||
)
|
||||
: PreparedStellarEquilibriumOperator(
|
||||
f,
|
||||
domainMapper,
|
||||
equationOfState,
|
||||
targetMass,
|
||||
MakeConstructionData(f)
|
||||
) {
|
||||
}
|
||||
|
||||
PreparedStellarEquilibriumOperator::PreparedStellarEquilibriumOperator(
|
||||
fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const eos::Polytrope &equationOfState,
|
||||
const double targetMass,
|
||||
ConstructionData constructionData
|
||||
)
|
||||
: mfem::Operator(
|
||||
constructionData.layout.residual_offsets().Last(),
|
||||
constructionData.layout.value_offsets().Last()
|
||||
),
|
||||
m_layout(constructionData.layout),
|
||||
m_gravityStateOffsets(constructionData.gravityStateOffsets),
|
||||
m_gravityContext(
|
||||
f,
|
||||
domainMapper
|
||||
),
|
||||
m_gravityJacobianOperator(
|
||||
f,
|
||||
domainMapper,
|
||||
m_gravityContext,
|
||||
m_gravityStateOffsets,
|
||||
constructionData.gravityResidualOffsets
|
||||
),
|
||||
m_gravityOperator(
|
||||
f,
|
||||
domainMapper,
|
||||
m_gravityContext,
|
||||
m_gravityStateOffsets,
|
||||
m_gravityJacobianOperator
|
||||
),
|
||||
m_barotropicClosureOperator(
|
||||
f,
|
||||
domainMapper,
|
||||
equationOfState
|
||||
),
|
||||
m_hydrostaticOperator(
|
||||
f,
|
||||
domainMapper
|
||||
),
|
||||
m_displacementOperator(
|
||||
f,
|
||||
domainMapper,
|
||||
equationOfState,
|
||||
m_gravityContext
|
||||
),
|
||||
m_massNormalizationOperator(
|
||||
f,
|
||||
domainMapper,
|
||||
m_gravityContext
|
||||
),
|
||||
m_targetMass(targetMass),
|
||||
m_densityMap(std::move(constructionData.densityMap)),
|
||||
m_displacementMap(std::move(constructionData.displacementMap)),
|
||||
m_gravityFluxMap(std::move(constructionData.gravityFluxMap)),
|
||||
m_gravityPotentialMap(std::move(constructionData.gravityPotentialMap)),
|
||||
m_enthalpyMap(std::move(constructionData.enthalpyMap)) {
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(m_targetMass) && m_targetMass > 0.0,
|
||||
"PreparedStellarEquilibriumOperator requires a finite, positive target mass."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
Width() == m_layout.value_offsets().Last() && Height() == m_layout.residual_offsets().Last(),
|
||||
"PreparedStellarEquilibriumOperator has inconsistent block dimensions."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
m_displacementMap.is_identity(), "PreparedStellarEquilibriumOperator currently requires Displacement "
|
||||
"support to span the full MFEM true-DOF space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
m_gravityFluxMap.is_identity(), "PreparedStellarEquilibriumOperator currently requires gravity-flux "
|
||||
"support to span the full MFEM true-DOF space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
m_gravityPotentialMap.is_identity(), "PreparedStellarEquilibriumOperator currently requires "
|
||||
"gravity-potential support to span the full MFEM true-DOF space."
|
||||
);
|
||||
|
||||
m_fullDensity.SetSize(m_densityMap.full_size());
|
||||
m_fullEnthalpy.SetSize(m_enthalpyMap.full_size());
|
||||
m_fullGravityState.SetSize(m_gravityStateOffsets.Last());
|
||||
|
||||
m_fullDensityVariation.SetSize(m_densityMap.full_size());
|
||||
m_fullEnthalpyVariation.SetSize(m_enthalpyMap.full_size());
|
||||
m_fullGravityDirection.SetSize(m_gravityStateOffsets.Last());
|
||||
m_fullEnthalpyAction.SetSize(m_enthalpyMap.full_size());
|
||||
|
||||
m_fullDensity = 0.0;
|
||||
m_fullEnthalpy = 0.0;
|
||||
m_fullGravityState = 0.0;
|
||||
m_fullDensityVariation = 0.0;
|
||||
m_fullEnthalpyVariation = 0.0;
|
||||
m_fullGravityDirection = 0.0;
|
||||
m_fullEnthalpyAction = 0.0;
|
||||
}
|
||||
|
||||
PreparedStellarEquilibriumReport PreparedStellarEquilibriumOperator::Prepare(
|
||||
const mfem::Vector &state,
|
||||
const StellarEquilibriumDependencies &dependencies,
|
||||
const physics::RigidRotation &rotation
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
state.Size() == Width(), "PreparedStellarEquilibriumOperator received a state with the wrong size."
|
||||
);
|
||||
validate_finite_vector(state, "PreparedStellarEquilibriumOperator received a non-finite state.");
|
||||
|
||||
const bool wasPrepared = m_isPrepared;
|
||||
if (wasPrepared) {
|
||||
validate_dependency_transition(
|
||||
m_preparedDependencies.discretization, dependencies.discretization,
|
||||
"The discretization revision cannot move backwards."
|
||||
);
|
||||
validate_dependency_transition(
|
||||
m_preparedDependencies.density, dependencies.density, "The density revision cannot move backwards."
|
||||
);
|
||||
validate_dependency_transition(
|
||||
m_preparedDependencies.displacement, dependencies.displacement,
|
||||
"The displacement revision cannot move backwards."
|
||||
);
|
||||
validate_dependency_transition(
|
||||
m_preparedDependencies.gravityGradient, dependencies.gravityGradient,
|
||||
"The gravity-gradient revision cannot move backwards."
|
||||
);
|
||||
validate_dependency_transition(
|
||||
m_preparedDependencies.gravityPotential, dependencies.gravityPotential,
|
||||
"The gravity-potential revision cannot move backwards."
|
||||
);
|
||||
validate_dependency_transition(
|
||||
m_preparedDependencies.enthalpy, dependencies.enthalpy, "The enthalpy revision cannot move backwards."
|
||||
);
|
||||
validate_dependency_transition(
|
||||
m_preparedDependencies.bernoulliConstant, dependencies.bernoulliConstant,
|
||||
"The Bernoulli-constant revision cannot move backwards."
|
||||
);
|
||||
validate_dependency_transition(
|
||||
m_preparedDependencies.rotation, dependencies.rotation, "The rotation revision cannot move backwards."
|
||||
);
|
||||
validate_dependency_transition(
|
||||
m_preparedDependencies.targetMass, dependencies.targetMass,
|
||||
"The target-mass revision cannot move backwards."
|
||||
);
|
||||
}
|
||||
|
||||
m_isPrepared = false;
|
||||
|
||||
using Form = utils::blocks::barotropic_equilibrium_form;
|
||||
constexpr auto densityValue = utils::blocks::get_value_block<Form>(utils::blocks::density_field.mass_term);
|
||||
constexpr auto displacementValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
constexpr auto gravityGradientValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::gravity_field.gradient_term);
|
||||
constexpr auto gravityPotentialValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::gravity_field.poisson_term);
|
||||
constexpr auto enthalpyValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::enthalpy_field.specific_term);
|
||||
constexpr auto bernoulliValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::barotropic_constant_field.mass_normalization_term);
|
||||
|
||||
const mfem::Vector reducedDensity = make_value_view(state, m_layout, densityValue);
|
||||
const mfem::Vector displacement = make_value_view(state, m_layout, displacementValue);
|
||||
const mfem::Vector gravityGradient = make_value_view(state, m_layout, gravityGradientValue);
|
||||
const mfem::Vector gravityPotential = make_value_view(state, m_layout, gravityPotentialValue);
|
||||
const mfem::Vector reducedEnthalpy = make_value_view(state, m_layout, enthalpyValue);
|
||||
const mfem::Vector bernoulli = make_value_view(state, m_layout, bernoulliValue);
|
||||
|
||||
m_densityMap.scatter(reducedDensity, m_fullDensity);
|
||||
m_enthalpyMap.scatter(reducedEnthalpy, m_fullEnthalpy);
|
||||
|
||||
pack_gravity_vector(
|
||||
m_fullGravityState, m_gravityStateOffsets, m_fullDensity, displacement, gravityGradient, gravityPotential
|
||||
);
|
||||
|
||||
PreparedStellarEquilibriumReport report;
|
||||
|
||||
report.gravity = m_gravityOperator.Prepare(m_fullGravityState, make_gravity_revisions(dependencies));
|
||||
|
||||
report.barotropicClosure = m_barotropicClosureOperator.Prepare(
|
||||
{.density = reducedDensity, .enthalpy = reducedEnthalpy, .displacement = displacement},
|
||||
make_barotropic_closure_dependencies(dependencies)
|
||||
);
|
||||
|
||||
report.hydrostatic = m_hydrostaticOperator.Prepare(
|
||||
{.enthalpy = m_fullEnthalpy,
|
||||
.gravityPotential = gravityPotential,
|
||||
.displacement = displacement,
|
||||
.bernoulliConstant = bernoulli(0)},
|
||||
make_hydrostatic_dependencies(dependencies), rotation
|
||||
);
|
||||
|
||||
report.displacement = m_displacementOperator.Prepare(
|
||||
{.enthalpy = reducedEnthalpy}, make_displacement_dependencies(dependencies), rotation
|
||||
);
|
||||
|
||||
report.massNormalization =
|
||||
m_massNormalizationOperator.Prepare({.targetMass = m_targetMass}, make_mass_dependencies(dependencies));
|
||||
|
||||
const bool dependenciesChanged = !wasPrepared || dependencies != m_preparedDependencies;
|
||||
if (dependenciesChanged || report.DidAnyChildWork()) {
|
||||
AssembleResidual();
|
||||
report.assembledResidual = true;
|
||||
}
|
||||
|
||||
m_preparedDependencies = dependencies;
|
||||
m_isPrepared = true;
|
||||
return report;
|
||||
}
|
||||
|
||||
void PreparedStellarEquilibriumOperator::AssembleResidual() {
|
||||
using Form = utils::blocks::barotropic_equilibrium_form;
|
||||
|
||||
constexpr auto gravityGradientResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::gravity_field.gradient_term);
|
||||
constexpr auto gravityPotentialResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::gravity_field.poisson_term);
|
||||
constexpr auto densityResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::density_field.mass_term);
|
||||
constexpr auto displacementResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
constexpr auto enthalpyResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::enthalpy_field.specific_term);
|
||||
constexpr auto massResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::barotropic_constant_field.mass_normalization_term);
|
||||
|
||||
mfem::Vector gravity;
|
||||
mfem::Vector closure;
|
||||
mfem::Vector displacement;
|
||||
mfem::Vector mass;
|
||||
|
||||
m_gravityOperator.Mult(m_fullGravityState, gravity);
|
||||
m_barotropicClosureOperator.BuildResidual(closure);
|
||||
m_displacementOperator.BuildResidual(displacement);
|
||||
m_hydrostaticOperator.BuildResidual(m_fullEnthalpyAction);
|
||||
m_massNormalizationOperator.BuildResidual(mass);
|
||||
|
||||
m_cachedResidual.SetSize(Height());
|
||||
m_cachedResidual = 0.0;
|
||||
|
||||
MFEM_VERIFY(
|
||||
gravity.Size() == m_layout.size(gravityGradientResidual) + m_layout.size(gravityPotentialResidual),
|
||||
"The gravity residual has the wrong size."
|
||||
);
|
||||
|
||||
mfem::Vector gravityGradient(gravity.GetData(), m_layout.size(gravityGradientResidual));
|
||||
mfem::Vector gravityPotential(
|
||||
gravity.GetData() + m_layout.size(gravityGradientResidual), m_layout.size(gravityPotentialResidual)
|
||||
);
|
||||
|
||||
assign_residual_block(
|
||||
m_cachedResidual, m_layout, gravityGradientResidual, gravityGradient,
|
||||
"The gravity-gradient residual has the wrong size."
|
||||
);
|
||||
assign_residual_block(
|
||||
m_cachedResidual, m_layout, gravityPotentialResidual, gravityPotential,
|
||||
"The gravity-potential residual has the wrong size."
|
||||
);
|
||||
assign_residual_block(
|
||||
m_cachedResidual, m_layout, densityResidual, closure, "The closure residual has the wrong size."
|
||||
);
|
||||
assign_residual_block(
|
||||
m_cachedResidual, m_layout, displacementResidual, displacement,
|
||||
"The displacement residual has the wrong size."
|
||||
);
|
||||
|
||||
{
|
||||
mfem::Vector reducedEnthalpyResidual = make_residual_view(m_cachedResidual, m_layout, enthalpyResidual);
|
||||
m_enthalpyMap.gather(m_fullEnthalpyAction, reducedEnthalpyResidual);
|
||||
}
|
||||
|
||||
assign_residual_block(
|
||||
m_cachedResidual, m_layout, massResidual, mass, "The mass-normalization residual has the wrong size."
|
||||
);
|
||||
|
||||
++m_statistics.residualAssemblies;
|
||||
}
|
||||
|
||||
void PreparedStellarEquilibriumOperator::BuildResidual(mfem::Vector &residual) const {
|
||||
VerifyPrepared();
|
||||
residual = m_cachedResidual;
|
||||
++m_statistics.residualApplications;
|
||||
}
|
||||
|
||||
void PreparedStellarEquilibriumOperator::Mult(
|
||||
const mfem::Vector &direction,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
MFEM_VERIFY(
|
||||
direction.Size() == Width(),
|
||||
"PreparedStellarEquilibriumOperator received a Jacobian direction with the wrong size."
|
||||
);
|
||||
validate_finite_vector(
|
||||
direction, "PreparedStellarEquilibriumOperator received a non-finite Jacobian direction."
|
||||
);
|
||||
|
||||
using Form = utils::blocks::barotropic_equilibrium_form;
|
||||
|
||||
constexpr auto densityValue = utils::blocks::get_value_block<Form>(utils::blocks::density_field.mass_term);
|
||||
constexpr auto displacementValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
constexpr auto gravityGradientValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::gravity_field.gradient_term);
|
||||
constexpr auto gravityPotentialValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::gravity_field.poisson_term);
|
||||
constexpr auto enthalpyValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::enthalpy_field.specific_term);
|
||||
constexpr auto bernoulliValue =
|
||||
utils::blocks::get_value_block<Form>(utils::blocks::barotropic_constant_field.mass_normalization_term);
|
||||
|
||||
constexpr auto gravityGradientResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::gravity_field.gradient_term);
|
||||
constexpr auto gravityPotentialResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::gravity_field.poisson_term);
|
||||
constexpr auto densityResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::density_field.mass_term);
|
||||
constexpr auto displacementResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::displacement_field.geometry_term);
|
||||
constexpr auto enthalpyResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::enthalpy_field.specific_term);
|
||||
constexpr auto massResidual =
|
||||
utils::blocks::get_residual_block<Form>(utils::blocks::barotropic_constant_field.mass_normalization_term);
|
||||
|
||||
const mfem::Vector reducedDensityDirection = make_value_view(direction, m_layout, densityValue);
|
||||
const mfem::Vector displacementDirection = make_value_view(direction, m_layout, displacementValue);
|
||||
const mfem::Vector gravityGradientDirection = make_value_view(direction, m_layout, gravityGradientValue);
|
||||
const mfem::Vector gravityPotentialDirection = make_value_view(direction, m_layout, gravityPotentialValue);
|
||||
const mfem::Vector reducedEnthalpyDirection = make_value_view(direction, m_layout, enthalpyValue);
|
||||
const mfem::Vector bernoulliDirection = make_value_view(direction, m_layout, bernoulliValue);
|
||||
|
||||
m_densityMap.scatter(reducedDensityDirection, m_fullDensityVariation);
|
||||
m_enthalpyMap.scatter(reducedEnthalpyDirection, m_fullEnthalpyVariation);
|
||||
|
||||
pack_gravity_vector(
|
||||
m_fullGravityDirection, m_gravityStateOffsets, m_fullDensityVariation, displacementDirection,
|
||||
gravityGradientDirection, gravityPotentialDirection
|
||||
);
|
||||
|
||||
mfem::Vector gravityAction;
|
||||
mfem::Vector closureAction;
|
||||
mfem::Vector displacementAction;
|
||||
mfem::Vector massAction;
|
||||
|
||||
m_gravityJacobianOperator.Mult(m_fullGravityDirection, gravityAction);
|
||||
|
||||
m_barotropicClosureOperator.Mult(
|
||||
reducedDensityDirection, reducedEnthalpyDirection, displacementDirection, closureAction
|
||||
);
|
||||
|
||||
m_displacementOperator.ApplyCompleteJacobianAction(
|
||||
m_fullDensityVariation, displacementDirection, gravityGradientDirection, reducedEnthalpyDirection,
|
||||
displacementAction
|
||||
);
|
||||
|
||||
m_hydrostaticOperator.ApplyCompleteJacobianAction(
|
||||
m_fullEnthalpyVariation, gravityPotentialDirection, bernoulliDirection(0), displacementDirection,
|
||||
m_fullEnthalpyAction
|
||||
);
|
||||
|
||||
m_massNormalizationOperator.ApplyCompleteJacobianAction(
|
||||
m_fullDensityVariation, displacementDirection, massAction
|
||||
);
|
||||
|
||||
action.SetSize(Height());
|
||||
action = 0.0;
|
||||
|
||||
MFEM_VERIFY(
|
||||
gravityAction.Size() == m_layout.size(gravityGradientResidual) + m_layout.size(gravityPotentialResidual),
|
||||
"The gravity Jacobian action has the wrong size."
|
||||
);
|
||||
|
||||
mfem::Vector gravityGradientAction(gravityAction.GetData(), m_layout.size(gravityGradientResidual));
|
||||
mfem::Vector gravityPotentialAction(
|
||||
gravityAction.GetData() + m_layout.size(gravityGradientResidual), m_layout.size(gravityPotentialResidual)
|
||||
);
|
||||
|
||||
assign_residual_block(
|
||||
action, m_layout, gravityGradientResidual, gravityGradientAction,
|
||||
"The gravity-gradient Jacobian action has the wrong size."
|
||||
);
|
||||
assign_residual_block(
|
||||
action, m_layout, gravityPotentialResidual, gravityPotentialAction,
|
||||
"The gravity-potential Jacobian action has the wrong size."
|
||||
);
|
||||
assign_residual_block(
|
||||
action, m_layout, densityResidual, closureAction, "The closure Jacobian action has the wrong size."
|
||||
);
|
||||
assign_residual_block(
|
||||
action, m_layout, displacementResidual, displacementAction,
|
||||
"The displacement Jacobian action has the wrong size."
|
||||
);
|
||||
|
||||
{
|
||||
mfem::Vector reducedEnthalpyAction = make_residual_view(action, m_layout, enthalpyResidual);
|
||||
m_enthalpyMap.gather(m_fullEnthalpyAction, reducedEnthalpyAction);
|
||||
}
|
||||
|
||||
assign_residual_block(
|
||||
action, m_layout, massResidual, massAction, "The mass-normalization Jacobian action has the wrong size."
|
||||
);
|
||||
|
||||
++m_statistics.jacobianApplications;
|
||||
}
|
||||
|
||||
bool PreparedStellarEquilibriumOperator::IsPrepared() const noexcept {
|
||||
return m_isPrepared && m_gravityContext.IsPrepared() && m_barotropicClosureOperator.IsPrepared() &&
|
||||
m_hydrostaticOperator.IsPrepared() && m_displacementOperator.IsPrepared() &&
|
||||
m_massNormalizationOperator.IsPrepared();
|
||||
}
|
||||
|
||||
double PreparedStellarEquilibriumOperator::GetTargetMass() const noexcept {
|
||||
return m_targetMass;
|
||||
}
|
||||
|
||||
const StellarEquilibriumLayout &PreparedStellarEquilibriumOperator::GetLayout() const noexcept {
|
||||
return m_layout;
|
||||
}
|
||||
|
||||
const StellarEquilibriumDependencies &PreparedStellarEquilibriumOperator::GetDependencies() const {
|
||||
VerifyPrepared();
|
||||
return m_preparedDependencies;
|
||||
}
|
||||
|
||||
const PreparedStellarEquilibriumStatistics &PreparedStellarEquilibriumOperator::GetStatistics() const noexcept {
|
||||
return m_statistics;
|
||||
}
|
||||
|
||||
const context::gravity_field::GravityFieldLinearizationContext &
|
||||
PreparedStellarEquilibriumOperator::GetGravityContext() const noexcept {
|
||||
return m_gravityContext;
|
||||
}
|
||||
|
||||
const GravityFieldOperator &PreparedStellarEquilibriumOperator::GetGravityOperator() const noexcept {
|
||||
return m_gravityOperator;
|
||||
}
|
||||
|
||||
const GravityFieldJacobianOperator &
|
||||
PreparedStellarEquilibriumOperator::GetGravityJacobianOperator() const noexcept {
|
||||
return m_gravityJacobianOperator;
|
||||
}
|
||||
|
||||
const PreparedBarotropicClosureOperator &
|
||||
PreparedStellarEquilibriumOperator::GetBarotropicClosureOperator() const noexcept {
|
||||
return m_barotropicClosureOperator;
|
||||
}
|
||||
|
||||
const context::barotropic::BarotropicClosureLinearizationContext &
|
||||
PreparedStellarEquilibriumOperator::GetBarotropicClosureContext() const noexcept {
|
||||
return m_barotropicClosureOperator.GetContext();
|
||||
}
|
||||
|
||||
const PreparedHydrostaticEquilibriumOperator &
|
||||
PreparedStellarEquilibriumOperator::GetHydrostaticOperator() const noexcept {
|
||||
return m_hydrostaticOperator;
|
||||
}
|
||||
|
||||
const PreparedDisplacementResidualOperator &
|
||||
PreparedStellarEquilibriumOperator::GetDisplacementOperator() const noexcept {
|
||||
return m_displacementOperator;
|
||||
}
|
||||
|
||||
const PreparedMassNormalizationOperator &
|
||||
PreparedStellarEquilibriumOperator::GetMassNormalizationOperator() const noexcept {
|
||||
return m_massNormalizationOperator;
|
||||
}
|
||||
|
||||
void PreparedStellarEquilibriumOperator::VerifyPrepared() const {
|
||||
MFEM_VERIFY(
|
||||
IsPrepared(), "PreparedStellarEquilibriumOperator must be prepared before residual or Jacobian application."
|
||||
);
|
||||
}
|
||||
} // namespace mean_field::operators
|
||||
Reference in New Issue
Block a user