fix(PolytropeOperator): seperated boundary aware and unaware operators for M, Q, and D

residual calculation needs to be done when boundary degrees of freedom have not been removed (since their removal takes place in the Mult step in order to introduce the proper restoring force). Whereas jacobian calculation needs to always work from the boundary aware operators (these are sparse matrices)

The other thing to note here is that this seems contrary to a matrix free design. While true it is common practive to assemble linear terms since they are cheap. We still never assemble the non linear matrix form.
This commit is contained in:
2025-05-22 11:30:24 -04:00
parent bd4aebedce
commit f5dea85db1
2 changed files with 53 additions and 41 deletions

View File

@@ -54,24 +54,34 @@ void PolytropeOperator::finalize(const mfem::Vector &initTheta) {
return;
}
m_M -> EliminateTestEssentialBC(m_theta_ess_tdofs.first);
m_M -> EliminateTrialEssentialBC(m_phi_ess_tdofs.first);
m_Mmat = std::make_unique<mfem::SparseMatrix>(m_M->SpMat());
m_Qmat = std::make_unique<mfem::SparseMatrix>(m_Q->SpMat());
m_Dmat = std::make_unique<mfem::SparseMatrix>(m_D->SpMat());
m_Q -> EliminateTestEssentialBC(m_phi_ess_tdofs.first);
m_Q -> EliminateTrialEssentialBC(m_theta_ess_tdofs.first);
// Remove the essential dofs from the constant matrices
for (const auto& dof: m_theta_ess_tdofs.first) {
m_Mmat->EliminateRow(dof);
m_Qmat->EliminateCol(dof);
}
m_D -> EliminateEssentialBC(m_phi_ess_tdofs.first);
for (const auto& dof: m_phi_ess_tdofs.first) {
m_Mmat->EliminateCol(dof);
m_Qmat->EliminateRow(dof);
m_Dmat->EliminateRowCol(dof);
}
m_negM_op = std::make_unique<mfem::ScaledOperator>(m_M.get(), -1.0);
m_negQ_op = std::make_unique<mfem::ScaledOperator>(m_Q.get(), -1.0);
m_negM_mat = std::make_unique<mfem::ScaledOperator>(m_Mmat.get(), -1.0);
m_negQ_mat = std::make_unique<mfem::ScaledOperator>(m_Qmat.get(), -1.0);
m_schurCompliment = std::make_unique<SchurCompliment>(*m_Q, *m_D, *m_M);
m_schurCompliment = std::make_unique<SchurCompliment>(*m_Qmat, *m_Dmat, *m_Mmat);
// Set up the constant parts of the jacobian now
// We use the assembled matrices with their boundary conditions already removed for the jacobian
m_jacobian = std::make_unique<mfem::BlockOperator>(m_blockOffsets);
m_jacobian->SetBlock(0, 1, m_negM_op.get()); //<- -M (constant)
m_jacobian->SetBlock(1, 0, m_negQ_op.get()); //<- -Q (constant)
m_jacobian->SetBlock(1, 1, m_D.get()); //<- D (constant)
m_jacobian->SetBlock(0, 1, m_negM_mat.get()); //<- -M (constant)
m_jacobian->SetBlock(1, 0, m_negQ_mat.get()); //<- -Q (constant)
m_jacobian->SetBlock(1, 1, m_Dmat.get()); //<- D (constant)
m_invSchurCompliment = std::make_unique<GMRESInverter>(*m_schurCompliment);
@@ -240,9 +250,9 @@ void GMRESInverter::Mult(const mfem::Vector &x, mfem::Vector &y) const {
SchurCompliment::SchurCompliment(
const mfem::MixedBilinearForm &QOp,
const mfem::BilinearForm &DOp,
const mfem::MixedBilinearForm &MOp,
const mfem::SparseMatrix &QOp,
const mfem::SparseMatrix &DOp,
const mfem::SparseMatrix &MOp,
const mfem::Solver &GradInvOp) :
mfem::Operator(DOp.Height(), DOp.Width())
{
@@ -252,9 +262,9 @@ mfem::Operator(DOp.Height(), DOp.Width())
}
SchurCompliment::SchurCompliment(
const mfem::MixedBilinearForm &QOp,
const mfem::BilinearForm &DOp,
const mfem::MixedBilinearForm &MOp) :
const mfem::SparseMatrix &QOp,
const mfem::SparseMatrix &DOp,
const mfem::SparseMatrix &MOp) :
mfem::Operator(DOp.Height(), DOp.Width())
{
updateConstantTerms(QOp, DOp, MOp);
@@ -262,7 +272,7 @@ mfem::Operator(DOp.Height(), DOp.Width())
m_nTheta = m_MOp->Height();
}
void SchurCompliment::SetOperator(const mfem::MixedBilinearForm &QOp, const mfem::BilinearForm &DOp, const mfem::MixedBilinearForm &MOp, const mfem::Solver &GradInvOp) {
void SchurCompliment::SetOperator(const mfem::SparseMatrix &QOp, const mfem::SparseMatrix &DOp, const mfem::SparseMatrix &MOp, const mfem::Solver &GradInvOp) {
updateConstantTerms(QOp, DOp, MOp);
updateInverseNonlinearJacobian(GradInvOp);
}
@@ -271,7 +281,7 @@ void SchurCompliment::updateInverseNonlinearJacobian(const mfem::Solver &gradInv
m_GradInvOp = &gradInv;
}
void SchurCompliment::updateConstantTerms(const mfem::MixedBilinearForm &QOp, const mfem::BilinearForm &DOp, const mfem::MixedBilinearForm &MOp) {
void SchurCompliment::updateConstantTerms(const mfem::SparseMatrix &QOp, const mfem::SparseMatrix &DOp, const mfem::SparseMatrix &MOp) {
m_QOp = &QOp;
m_DOp = &DOp;
m_MOp = &MOp;