feat(poly): lagrangian constrained weak form of 3D lane-Emden
added a basic implimentation of the 3D lane emden equation using a lagrangian multiplier to constrain the value at the center of a spherical domain
This commit is contained in:
@@ -13,67 +13,56 @@
|
||||
// TODO: Come back to this and think of a better way to get the mesh file
|
||||
const std::string SPHERICAL_MESH = std::string(getenv("MESON_SOURCE_ROOT")) + "/src/resources/mesh/sphere.msh";
|
||||
|
||||
PolySolver::PolySolver(double n, double order)
|
||||
PolySolver::PolySolver(double n, double order)
|
||||
: n(n),
|
||||
order(order),
|
||||
meshIO(SPHERICAL_MESH),
|
||||
mesh(meshIO.GetMesh()),
|
||||
gaussianCoeff(std::make_unique<polyMFEMUtils::GaussianCoefficient>(0.1)),
|
||||
diffusionCoeff(std::make_unique<mfem::VectorConstantCoefficient>(mfem::Vector(mesh.SpaceDimension()))),
|
||||
nonLinearSourceCoeff(std::make_unique<mfem::ConstantCoefficient>(1.0))
|
||||
{
|
||||
(*diffusionCoeff).GetVec() = 1.0;
|
||||
feCollection = std::make_unique<mfem::H1_FECollection>(order, mesh.SpaceDimension());
|
||||
|
||||
feSpace = std::make_unique<mfem::FiniteElementSpace>(&mesh, feCollection.get());
|
||||
lambdaFeSpace = std::make_unique<mfem::FiniteElementSpace>(&mesh, feCollection.get(), 1); // Scalar space for lambda
|
||||
|
||||
compositeIntegrator = std::make_unique<polyMFEMUtils::CompositeNonlinearIntegrator>();
|
||||
nonlinearForm = std::make_unique<mfem::NonlinearForm>(feSpace.get());
|
||||
|
||||
C = std::make_unique<mfem::LinearForm>(feSpace.get());
|
||||
|
||||
u = std::make_unique<mfem::GridFunction>(feSpace.get());
|
||||
|
||||
feCollection(std::make_unique<mfem::H1_FECollection>(order, mesh.SpaceDimension())),
|
||||
feSpace(std::make_unique<mfem::FiniteElementSpace>(&mesh, feCollection.get())),
|
||||
lambdaFeSpace(std::make_unique<mfem::FiniteElementSpace>(&mesh, feCollection.get(), 1)), // Scalar space for lambda
|
||||
compositeIntegrator(std::make_unique<polyMFEMUtils::CompositeNonlinearIntegrator>()),
|
||||
nonlinearForm(std::make_unique<mfem::NonlinearForm>(feSpace.get())),
|
||||
C(std::make_unique<mfem::LinearForm>(feSpace.get())),
|
||||
u(std::make_unique<mfem::GridFunction>(feSpace.get())),
|
||||
diffusionCoeff(std::make_unique<mfem::VectorConstantCoefficient>([&](){
|
||||
mfem::Vector diffusionCoeffVec(mesh.SpaceDimension());
|
||||
diffusionCoeffVec = 1.0;
|
||||
return diffusionCoeffVec;
|
||||
}())),
|
||||
nonLinearSourceCoeff(std::make_unique<mfem::ConstantCoefficient>(1.0)),
|
||||
gaussianCoeff(std::make_unique<polyMFEMUtils::GaussianCoefficient>(0.1)) {
|
||||
assembleNonlinearForm();
|
||||
assembleConstraintForm();
|
||||
}
|
||||
|
||||
PolySolver::assembleNonlinearForm() {
|
||||
PolySolver::~PolySolver() {}
|
||||
|
||||
void PolySolver::assembleNonlinearForm() {
|
||||
// Add the \int_{\Omega}\nabla v\cdot\nabla\theta d\Omegaterm
|
||||
compositeIntegrator->add_integrator(
|
||||
new polyMFEMUtils::BilinearIntegratorWrapper(
|
||||
new mfem::DiffusionIntegrator(diffusionCoeff.get()),
|
||||
)
|
||||
auto wrappedDiffusionIntegrator = std::make_unique<polyMFEMUtils::BilinearIntegratorWrapper>(
|
||||
new mfem::DiffusionIntegrator(*diffusionCoeff)
|
||||
);
|
||||
compositeIntegrator->add_integrator(wrappedDiffusionIntegrator.release());
|
||||
|
||||
// Add the \int_{\Omega}v\theta^{n} d\Omega term
|
||||
compositeIntegrator->add_integrator(
|
||||
new polyMFEMUtils::NonlinearPowerIntegrator(
|
||||
nonLinearSourceCoeff.get(),
|
||||
n
|
||||
)
|
||||
);
|
||||
auto nonLinearIntegrator = std::make_unique<polyMFEMUtils::NonlinearPowerIntegrator>(*nonLinearSourceCoeff, n);
|
||||
compositeIntegrator->add_integrator(nonLinearIntegrator.release());
|
||||
|
||||
compositeIntegrator->add_integrator(
|
||||
new polyMFEMUtils::ConstraintIntegrator(
|
||||
*gaussianCoeff
|
||||
)
|
||||
);
|
||||
// Add the \int_{\Omega}v\eta(r) d\Omega term
|
||||
auto constraintIntegrator = std::make_unique<polyMFEMUtils::ConstraintIntegrator>(*gaussianCoeff);
|
||||
compositeIntegrator->add_integrator(constraintIntegrator.release());
|
||||
|
||||
nonlinearForm->AddDomainIntegrator(compositeIntegrator.get());
|
||||
nonlinearForm->AddDomainIntegrator(compositeIntegrator.release());
|
||||
}
|
||||
|
||||
PolySolver::assembleConstraintForm() {
|
||||
C->AddDomainIntegrator(
|
||||
new mfem::DomainLFIntegrator(
|
||||
*gaussianCoeff
|
||||
)
|
||||
);
|
||||
void PolySolver::assembleConstraintForm() {
|
||||
auto constraintIntegrator = std::make_unique<mfem::DomainLFIntegrator>(*gaussianCoeff);
|
||||
C->AddDomainIntegrator(constraintIntegrator.release());
|
||||
C->Assemble();
|
||||
}
|
||||
|
||||
PolySolver::solve(){
|
||||
void PolySolver::solve(){
|
||||
// --- Set the initial guess for the solution ---
|
||||
mfem::FunctionCoefficient initCoeff (
|
||||
[this](const mfem::Vector &x) {
|
||||
@@ -86,6 +75,10 @@ PolySolver::solve(){
|
||||
int lambdaDofOffset = feSpace->GetTrueVSize(); // Get the size of θ space
|
||||
int totalTrueDofs = lambdaDofOffset + lambdaFeSpace->GetTrueVSize();
|
||||
|
||||
std::cout << "Total True Dofs: " << totalTrueDofs << std::endl;
|
||||
std::cout << "Lambda Dof Offset: " << lambdaDofOffset << std::endl;
|
||||
std::cout << "Lambda True Dofs: " << lambdaFeSpace->GetTrueVSize() << std::endl;
|
||||
std::cout << "U True Dofs: " << feSpace->GetTrueVSize() << std::endl;
|
||||
if (totalTrueDofs != lambdaDofOffset + 1) {
|
||||
throw std::runtime_error("The total number of true dofs is not equal to the sum of the lambda offset and the lambda space size");
|
||||
}
|
||||
@@ -93,7 +86,8 @@ PolySolver::solve(){
|
||||
mfem::Vector U(totalTrueDofs);
|
||||
U = 0.0;
|
||||
|
||||
u->GetTrueDofs(U.GetBlock(0));
|
||||
mfem::Vector u_view(U.GetData(), lambdaDofOffset);
|
||||
u->GetTrueDofs(u_view);
|
||||
|
||||
// --- Setup the Newton Solver ---
|
||||
mfem::NewtonSolver newtonSolver;
|
||||
@@ -113,7 +107,7 @@ PolySolver::solve(){
|
||||
// TODO: Change numeric tolerance to grab from the tol module
|
||||
|
||||
// --- Setup the Augmented Operator ---
|
||||
polyMFEMUtils::AugmentedOperator aug_op(nonlinearForm.get(), C.get(), lambdaDofOffset);
|
||||
polyMFEMUtils::AugmentedOperator aug_op(*nonlinearForm, *C, lambdaDofOffset);
|
||||
newtonSolver.SetOperator(aug_op);
|
||||
|
||||
// --- Create the RHS of the augmented system ---
|
||||
@@ -136,7 +130,8 @@ PolySolver::solve(){
|
||||
newtonSolver.Mult(B, U);
|
||||
|
||||
// --- Extract the Solution ---
|
||||
u->Distribute(U.GetBlock(0));
|
||||
mfem::Vector u_sol_view(U.GetData(), lambdaDofOffset);
|
||||
u->SetData(u_sol_view);
|
||||
double lambda = U[lambdaDofOffset];
|
||||
|
||||
std::cout << "λ = " << lambda << std::endl;
|
||||
|
||||
Reference in New Issue
Block a user