fix(poly): fixed numerous bugs related to inconsistent system sizing with the reduced operator
this has restored the symmetry which we relied on before.
This commit is contained in:
@@ -36,6 +36,7 @@
|
||||
#include "probe.h"
|
||||
#include "resourceManager.h"
|
||||
#include "resourceManagerTypes.h"
|
||||
#include "utilities.h"
|
||||
#include "quill/LogMacros.h"
|
||||
|
||||
|
||||
@@ -113,6 +114,19 @@ void PolySolver::assembleBlockSystem() {
|
||||
|
||||
const std::unique_ptr<formBundle> forms = buildIndividualForms(blockOffsets);
|
||||
|
||||
// const double penalty_param = m_config.get<double>("Poly::Solver::ZeroDerivativePenalty", 1e10);
|
||||
// mfem::Array<int> thetaCenterDofs, phiCenterDofs;
|
||||
// std::tie(thetaCenterDofs, phiCenterDofs) = findCenterElement();
|
||||
// mfem::SparseMatrix& D_mat = forms->D->SpMat();
|
||||
//
|
||||
// for (int i = 0; i < phiCenterDofs.Size(); ++i)
|
||||
// {
|
||||
// const int dof_idx = phiCenterDofs[i];
|
||||
// if (dof_idx >= 0 && dof_idx < D_mat.Height()) {
|
||||
// D_mat(dof_idx, dof_idx) += penalty_param;
|
||||
// }
|
||||
// }
|
||||
|
||||
// --- Build the BlockOperator ---
|
||||
m_polytropOperator = std::make_unique<PolytropeOperator>(
|
||||
std::move(forms->M),
|
||||
@@ -173,8 +187,9 @@ void PolySolver::assembleAndFinalizeForm(auto &f) {
|
||||
void PolySolver::solve() const {
|
||||
// --- Set the initial guess for the solution ---
|
||||
setInitialGuess();
|
||||
|
||||
setOperatorEssentialTrueDofs();
|
||||
|
||||
// --- Cast the GridFunctions to mfem::Vector ---
|
||||
const auto thetaVec = static_cast<mfem::Vector>(*m_theta); // NOLINT(*-slicing)
|
||||
const auto phiVec = static_cast<mfem::Vector>(*m_phi); // NOLINT(*-slicing)
|
||||
|
||||
@@ -182,23 +197,31 @@ void PolySolver::solve() const {
|
||||
// Finalize with the initial state of theta for the initial jacobian calculation
|
||||
m_polytropOperator->finalize(thetaVec);
|
||||
|
||||
// It's safer to get the offsets directly from the operator after finalization
|
||||
const mfem::Array<int>& block_offsets = m_polytropOperator->get_reduced_block_offsets(); // Assuming a getter exists or accessing member if public/friend
|
||||
mfem::BlockVector state_vector(block_offsets);
|
||||
state_vector.GetBlock(0) = thetaVec; // NOLINT(*-slicing)
|
||||
state_vector.GetBlock(1) = phiVec; // NOLINT(*-slicing)
|
||||
// --- Broadcast initial condition to the full state vector ---
|
||||
const mfem::Array<int>& full_block_offsets = m_polytropOperator->get_block_offsets();
|
||||
mfem::Vector x_full(full_block_offsets.Last());
|
||||
mfem::BlockVector x_full_block(x_full, full_block_offsets);
|
||||
x_full_block.GetBlock(0) = thetaVec; // NOLINT(*-slicing)
|
||||
x_full_block.GetBlock(1) = phiVec; // NOLINT(*-slicing)
|
||||
|
||||
// --- Extract only the free DOFs from the full state vector ---
|
||||
const mfem::Array<int>& freeDofs = m_polytropOperator->get_free_dofs();
|
||||
mfem::Vector x_free(m_polytropOperator->get_reduced_system_size());
|
||||
x_full.GetSubVector(freeDofs, x_free); // Extract the free DOFs from the full vector
|
||||
|
||||
// --- Initialize RHS ---
|
||||
mfem::Vector zero_rhs(m_polytropOperator->get_reduced_system_size());
|
||||
zero_rhs = 0.0;
|
||||
|
||||
// --- Setup and run the Newton solver ---
|
||||
const solverBundle sb = setupNewtonSolver();
|
||||
sb.newton.Mult(zero_rhs, state_vector);
|
||||
sb.newton.Mult(zero_rhs, x_free);
|
||||
|
||||
// TODO: Need some system here to reconstruct the full system vector from what MFEM's Newton Solver
|
||||
// will return, since that will end up being the vector for the reduced system.
|
||||
// --- Reconstruct the full state vector from the reduced solution ---
|
||||
mfem::BlockVector solution = m_polytropOperator->reconstruct_full_block_state_vector(x_free);
|
||||
|
||||
// --- Save and view an approximate 1D solution ---
|
||||
saveAndViewSolution(state_vector);
|
||||
saveAndViewSolution(solution);
|
||||
}
|
||||
|
||||
SSE::MFEMArrayPairSet PolySolver::getEssentialTrueDof() const {
|
||||
@@ -206,10 +229,12 @@ SSE::MFEMArrayPairSet PolySolver::getEssentialTrueDof() const {
|
||||
mfem::Array<int> phi_ess_tdof_list;
|
||||
|
||||
mfem::Array<int> thetaCenterDofs, phiCenterDofs; // phiCenterDofs are not used
|
||||
mfem::Array<double> thetaCenterVals;
|
||||
mfem::Array<double> thetaCenterVals, phiCenterVals;
|
||||
std::tie(thetaCenterDofs, phiCenterDofs) = findCenterElement();
|
||||
thetaCenterVals.SetSize(thetaCenterDofs.Size());
|
||||
// phiCenterVals.SetSize(phiCenterDofs.Size());
|
||||
|
||||
// phiCenterVals = 0.0;
|
||||
thetaCenterVals = 1.0;
|
||||
|
||||
mfem::Array<int> ess_brd(m_mesh.bdr_attributes.Max());
|
||||
@@ -228,6 +253,9 @@ SSE::MFEMArrayPairSet PolySolver::getEssentialTrueDof() const {
|
||||
theta_ess_tdof_list.Append(thetaCenterDofs);
|
||||
thetaSurfaceVals.Append(thetaCenterVals);
|
||||
|
||||
// phi_ess_tdof_list.Append(phiCenterDofs);
|
||||
// phiSurfaceVals.Append(phiCenterVals);
|
||||
|
||||
SSE::MFEMArrayPair thetaPair = std::make_pair(theta_ess_tdof_list, thetaSurfaceVals);
|
||||
SSE::MFEMArrayPair phiPair = std::make_pair(phi_ess_tdof_list, phiSurfaceVals);
|
||||
SSE::MFEMArrayPairSet pairSet = std::make_pair(thetaPair, phiPair);
|
||||
@@ -238,21 +266,59 @@ SSE::MFEMArrayPairSet PolySolver::getEssentialTrueDof() const {
|
||||
std::pair<mfem::Array<int>, mfem::Array<int>> PolySolver::findCenterElement() const {
|
||||
mfem::Array<int> thetaCenterDofs;
|
||||
mfem::Array<int> phiCenterDofs;
|
||||
mfem::DenseMatrix centerPoint(m_mesh.SpaceDimension(), 1);
|
||||
centerPoint(0, 0) = 0.0;
|
||||
centerPoint(1, 0) = 0.0;
|
||||
centerPoint(2, 0) = 0.0;
|
||||
|
||||
mfem::Array<int> elementIDs;
|
||||
mfem::Array<mfem::IntegrationPoint> ips;
|
||||
m_mesh.FindPoints(centerPoint, elementIDs, ips);
|
||||
mfem::Array<int> tempDofs;
|
||||
for (int i = 0; i < elementIDs.Size(); i++) {
|
||||
m_feTheta->GetElementDofs(elementIDs[i], tempDofs);
|
||||
thetaCenterDofs.Append(tempDofs);
|
||||
m_fePhi->GetElementDofs(elementIDs[i], tempDofs);
|
||||
phiCenterDofs.Append(tempDofs);
|
||||
// --- 1. Find the index of the single mesh vertex at the origin ---
|
||||
int center_vertex_idx = -1;
|
||||
constexpr double tol = 1e-9; // A small tolerance for floating point comparison
|
||||
|
||||
for (int i = 0; i < m_mesh.GetNV(); ++i) {
|
||||
const double* vertex_coords = m_mesh.GetVertex(i);
|
||||
if (std::abs(vertex_coords[0]) < tol &&
|
||||
std::abs(vertex_coords[1]) < tol &&
|
||||
std::abs(vertex_coords[2]) < tol) {
|
||||
|
||||
center_vertex_idx = i;
|
||||
break; // Found it, assume there's only one.
|
||||
}
|
||||
}
|
||||
|
||||
if (center_vertex_idx == -1) {
|
||||
MFEM_ABORT("Could not find the center vertex at [0,0,0]. Check mesh construction.");
|
||||
}
|
||||
|
||||
// --- 2. Get Theta (H1) DoFs associated ONLY with that vertex ---
|
||||
// CORRECTED: Use GetVertexDofs, not GetVDofs.
|
||||
m_feTheta->GetVertexDofs(center_vertex_idx, thetaCenterDofs);
|
||||
|
||||
|
||||
mfem::Array<int> central_element_ids;
|
||||
|
||||
// PERF: could probably move this to a member variable and populate during construction
|
||||
mfem::Table* vertex_to_elements_table = m_mesh.GetVertexToElementTable();
|
||||
vertex_to_elements_table->Finalize();
|
||||
mfem::Array<int> element_ids;
|
||||
vertex_to_elements_table->GetRow(center_vertex_idx, element_ids);
|
||||
delete vertex_to_elements_table;
|
||||
|
||||
for (int i = 0; i < element_ids.Size(); ++i) {
|
||||
int element_id = element_ids[i];
|
||||
mfem::Array<int> tempDofs;
|
||||
m_fePhi->GetElementDofs(element_id, tempDofs);
|
||||
|
||||
// decode negative dofs to their true, physical, dof indices
|
||||
for (int j = 0; j < tempDofs.Size(); ++j) {
|
||||
int dof = tempDofs[j];
|
||||
if (dof < 0) {
|
||||
dof = -dof - 1; // Convert to positive index
|
||||
}
|
||||
phiCenterDofs.Append(dof);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
phiCenterDofs.Sort();
|
||||
phiCenterDofs.Unique();
|
||||
|
||||
return std::make_pair(thetaCenterDofs, phiCenterDofs);
|
||||
}
|
||||
|
||||
@@ -302,10 +368,18 @@ void PolySolver::setInitialGuess() const {
|
||||
// solver towards a more consistent answer (x_φ - target)
|
||||
m_phi->ProjectBdrCoefficientNormal(phiSurfaceVectors, ess_brd);
|
||||
|
||||
auto [thetaCenterDofs, phiCenterDofs] = findCenterElement();
|
||||
|
||||
for (int i = 0; i < phiCenterDofs.Size(); ++i)
|
||||
{
|
||||
(*m_phi)(phiCenterDofs[i]) = 0.0;
|
||||
}
|
||||
|
||||
if (m_config.get<bool>("Poly:Solver:ViewInitialGuess", false)) {
|
||||
Probe::glVisView(*m_theta, m_mesh, "θ init");
|
||||
Probe::glVisView(*m_phi, m_mesh, "φ init");
|
||||
}
|
||||
std::cout << "HERE" << std::endl;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user