SERiF 0.0.1a
3+1D Stellar Structure and Evolution
Loading...
Searching...
No Matches
polySolver.cpp
Go to the documentation of this file.
1/* ***********************************************************************
2//
3// Copyright (C) 2025 -- The 4D-STAR Collaboration
4// File Author: Emily Boudreaux
5// Last Modified: April 21, 2025
6//
7// 4DSSE is free software; you can use it and/or modify
8// it under the terms and restrictions the GNU General Library Public
9// License version 3 (GPLv3) as published by the Free Software Foundation.
10//
11// 4DSSE is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14// See the GNU Library General Public License for more details.
15//
16// You should have received a copy of the GNU Library General Public License
17// along with this software; if not, write to the Free Software
18// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19//
20// *********************************************************************** */
21#include "polySolver.h"
22
23#include <memory>
24#include <stdexcept>
25#include <string>
26#include <utility>
27
28#include "mfem.hpp"
29
30#include "4DSTARTypes.h"
31#include "config.h"
32#include "integrators.h"
33#include "mfem.hpp"
34#include "polytropeOperator.h"
35#include "polyCoeff.h"
36#include "probe.h"
37#include "resourceManager.h"
39#include "utilities.h"
40#include "quill/LogMacros.h"
41
42
43namespace serif::polytrope {
44
45namespace laneEmden {
46
47 double a (const int k, const double n) { // NOLINT(*-no-recursion)
48 if ( k == 0 ) { return 1; }
49 if ( k == 1 ) { return 0; }
50 else { return -(c(k-2, n)/(std::pow(k, 2)+k)); }
51
52 }
53
54 double c(const int m, const double n) { // NOLINT(*-no-recursion)
55 if ( m == 0 ) { return std::pow(a(0, n), n); }
56 else {
57 double termOne = 1.0/(m*a(0, n));
58 double acc = 0;
59 for (int k = 1; k <= m; k++) {
60 acc += (k*n-m+k)*a(k, n)*c(m-k, n);
61 }
62 return termOne*acc;
63 }
64 }
65
66 double thetaSeriesExpansion(const double xi, const double n, const int order) {
67 double acc = 0;
68 for (int k = 0; k < order; k++) {
69 acc += a(k, n) * std::pow(xi, k);
70 }
71 return acc;
72 }
73} // namespace laneEmden
74
75
76PolySolver::PolySolver(mfem::Mesh& mesh, const double n, const double order)
77 : m_config(serif::config::Config::getInstance()), // Updated
78 m_logManager(serif::probe::LogManager::getInstance()),
79 m_logger(m_logManager.getLogger("log")),
81 m_feOrder(order),
82 m_mesh(mesh) {
83
84 // Use feOrder - 1 for the RT space to satisfy Brezzi-Babuska condition
85 // for the H1 and RT [H(div)] spaces
86 m_fecH1 = std::make_unique<mfem::H1_FECollection>(m_feOrder, m_mesh.SpaceDimension());
87 m_fecRT = std::make_unique<mfem::RT_FECollection>(m_feOrder - 1, m_mesh.SpaceDimension());
88
89 m_feTheta = std::make_unique<mfem::FiniteElementSpace>(&m_mesh, m_fecH1.get());
90 m_fePhi = std::make_unique<mfem::FiniteElementSpace>(&m_mesh, m_fecRT.get());
91
92 m_theta = std::make_unique<mfem::GridFunction>(m_feTheta.get());
93 m_phi = std::make_unique<mfem::GridFunction>(m_fePhi.get());
94
96}
97
98PolySolver::PolySolver(const double n, const double order)
99 : PolySolver(prepareMesh(n), n, order){}
100
101mfem::Mesh& PolySolver::prepareMesh(const double n) {
102 if (n > 4.99 || n < 0.0) {
103 throw std::runtime_error("The polytropic index n must be less than 5.0 and greater than 0.0. Currently it is " + std::to_string(n));
104 }
106 const serif::resource::types::Resource& genericResource = rm.getResource("mesh:polySphere");
107 const auto &meshIO = std::get<std::unique_ptr<serif::mesh::MeshIO>>(genericResource);
108 meshIO->LinearRescale(polycoeff::x1(n)); // Assumes polycoeff is now serif::polytrope::polycoeff
109 return meshIO->GetMesh();
110}
111
112PolySolver::~PolySolver() = default;
113
115 mfem::Array<int> blockOffsets = computeBlockOffsets();
116
117 const std::unique_ptr<formBundle> forms = buildIndividualForms(blockOffsets);
118
119 // const double penalty_param = m_config.get<double>("Poly::Solver::ZeroDerivativePenalty", 1.0);
120 // mfem::Array<int> thetaCenterDofs, phiCenterDofs;
121 // std::tie(thetaCenterDofs, phiCenterDofs) = findCenterElement();
122 // mfem::SparseMatrix& D_mat = forms->D->SpMat();
123 //
124 // for (int i = 0; i < phiCenterDofs.Size(); ++i)
125 // {
126 // const int dof_idx = phiCenterDofs[i];
127 // if (dof_idx >= 0 && dof_idx < D_mat.Height()) {
128 // D_mat(dof_idx, dof_idx) += penalty_param;
129 // }
130 // }
131
132 // --- Build the BlockOperator ---
133 m_polytropOperator = std::make_unique<PolytropeOperator>(
134 std::move(forms->M),
135 std::move(forms->Q),
136 std::move(forms->D),
137 std::move(forms->S),
138 std::move(forms->f),
139 blockOffsets);
140}
141
142mfem::Array<int> PolySolver::computeBlockOffsets() const {
143 mfem::Array<int> blockOffsets;
144 blockOffsets.SetSize(3);
145 blockOffsets[0] = 0;
146 blockOffsets[1] = m_feTheta->GetVSize(); // Get actual number of dofs *before* applying BCs
147 blockOffsets[2] = m_fePhi->GetVSize();
148 blockOffsets.PartialSum(); // Cumulative sum to get the offsets
149 return blockOffsets;
150}
151
152std::unique_ptr<formBundle> PolySolver::buildIndividualForms(const mfem::Array<int> &blockOffsets) {
153 // --- Assemble the MixedBilinear and Bilinear forms (M, D, and Q) ---
154 auto forms = std::make_unique<formBundle>(
155 std::make_unique<mfem::MixedBilinearForm>(m_fePhi.get(), m_feTheta.get()),
156 std::make_unique<mfem::MixedBilinearForm>(m_feTheta.get(), m_fePhi.get()),
157 std::make_unique<mfem::BilinearForm>(m_fePhi.get()),
158 std::make_unique<mfem::BilinearForm>(m_feTheta.get()),
159 std::make_unique<mfem::NonlinearForm>(m_feTheta.get())
160 );
161
162 // --- Add the integrators to the forms ---
163 forms->M->AddDomainIntegrator(new mfem::MixedVectorWeakDivergenceIntegrator()); // M ∫∇ψ^θ·N^φ dV
164 forms->Q->AddDomainIntegrator(new mfem::MixedVectorGradientIntegrator()); // Q ∫ψ^φ·∇N^θ dV
165 forms->D->AddDomainIntegrator(new mfem::VectorFEMassIntegrator()); // D ∫ψ^φ·N^φ dV
166 forms->S->AddDomainIntegrator(new mfem::DiffusionIntegrator()); // S ∫∇ψ^θ·∇N^θ dV
167 forms->f->AddDomainIntegrator(new polyMFEMUtils::NonlinearPowerIntegrator(m_polytropicIndex)); // Assumes polyMFEMUtils is now serif::polytrope::polyMFEMUtils
168
169 // --- Assemble and Finalize the forms ---
170 assembleAndFinalizeForm(forms->M);
171 assembleAndFinalizeForm(forms->Q);
172 assembleAndFinalizeForm(forms->D);
173 assembleAndFinalizeForm(forms->S);
174
175 // Note: The NonlinearForm does not need to / cannot be finalized, as it is not a matrix form. Rather, the operator
176 // will evaluate the nonlinear form during the solve phase.
177
178
179 return forms;
180}
181
183 // This constructs / ensures the matrix representation for each form
184 // Assemble => Computes the local element matrices across the domain. Adds these to the global matrix . Adds these to the global matrix.
185 // Finalize => Builds the sparsity pattern and allows the SparseMatrix representation to be extracted (CSR).
186 f->Assemble();
187 f->Finalize();
188}
189
190void PolySolver::solve() const {
191 // --- Set the initial guess for the solution ---
194
195 // --- Cast the GridFunctions to mfem::Vector ---
196 const auto thetaVec = static_cast<mfem::Vector>(*m_theta); // NOLINT(*-slicing)
197 const auto phiVec = static_cast<mfem::Vector>(*m_phi); // NOLINT(*-slicing)
198
199 // --- Finalize the operator ---
200 // Finalize with the initial state of theta for the initial jacobian calculation
201 m_polytropOperator->finalize(thetaVec);
202
203 // --- Broadcast initial condition to the full state vector ---
204 const mfem::Array<int>& full_block_offsets = m_polytropOperator->get_block_offsets();
205 mfem::Vector x_full(full_block_offsets.Last());
206 mfem::BlockVector x_full_block(x_full, full_block_offsets);
207 x_full_block.GetBlock(0) = thetaVec; // NOLINT(*-slicing)
208 x_full_block.GetBlock(1) = phiVec; // NOLINT(*-slicing)
209
210 // --- Extract only the free DOFs from the full state vector ---
211 const mfem::Array<int>& freeDofs = m_polytropOperator->get_free_dofs();
212 mfem::Vector x_free(m_polytropOperator->get_reduced_system_size());
213 x_full.GetSubVector(freeDofs, x_free); // Extract the free DOFs from the full vector
214
215 // --- Initialize RHS ---
216 mfem::Vector zero_rhs(m_polytropOperator->get_reduced_system_size());
217 zero_rhs = 0.0;
218
219 // --- Setup and run the Newton solver ---
220 const solverBundle sb = setupNewtonSolver();
221 sb.newton.Mult(zero_rhs, x_free);
222
223 // --- Reconstruct the full state vector from the reduced solution ---
224 mfem::BlockVector solution = m_polytropOperator->reconstruct_full_block_state_vector(x_free);
225
226 // --- Save and view an approximate 1D solution ---
227 saveAndViewSolution(solution);
228}
229
231 mfem::Array<int> theta_ess_tdof_list;
232 mfem::Array<int> phi_ess_tdof_list;
233
234 mfem::Array<int> thetaCenterDofs, phiCenterDofs; // phiCenterDofs are not used
235 mfem::Array<double> thetaCenterVals, phiCenterVals;
236 std::tie(thetaCenterDofs, phiCenterDofs) = findCenterElement();
237 thetaCenterVals.SetSize(thetaCenterDofs.Size());
238 // phiCenterVals.SetSize(phiCenterDofs.Size());
239 //
240 // phiCenterVals = 0.0;
241 thetaCenterVals = 1.0;
242
243 mfem::Array<int> ess_brd(m_mesh.bdr_attributes.Max());
244 ess_brd = 1;
245
246 mfem::Array<double> thetaSurfaceVals, phiSurfaceVals;
247 m_feTheta->GetEssentialTrueDofs(ess_brd, theta_ess_tdof_list);
248 m_fePhi->GetEssentialTrueDofs(ess_brd, phi_ess_tdof_list);
249
250 thetaSurfaceVals.SetSize(theta_ess_tdof_list.Size());
251 thetaSurfaceVals = 0.0;
252 phiSurfaceVals.SetSize(phi_ess_tdof_list.Size());
253 phiSurfaceVals = polycoeff::thetaSurfaceFlux(m_polytropicIndex); // Assumes polycoeff is now serif::polytrope::polycoeff
254
255 // combine the essential dofs with the center dofs
256 theta_ess_tdof_list.Append(thetaCenterDofs);
257 thetaSurfaceVals.Append(thetaCenterVals);
258
259 // phi_ess_tdof_list.Append(phiCenterDofs);
260 // phiSurfaceVals.Append(phiCenterVals);
261
262 serif::types::MFEMArrayPair thetaPair = std::make_pair(theta_ess_tdof_list, thetaSurfaceVals);
263 serif::types::MFEMArrayPair phiPair = std::make_pair(phi_ess_tdof_list, phiSurfaceVals);
264 serif::types::MFEMArrayPairSet pairSet = std::make_pair(thetaPair, phiPair);
265
266 return pairSet;
267}
268
269std::pair<mfem::Array<int>, mfem::Array<int>> PolySolver::findCenterElement() const {
270 mfem::Array<int> thetaCenterDofs;
271 mfem::Array<int> phiCenterDofs;
272
273 // --- 1. Find the index of the single mesh vertex at the origin ---
274 int center_vertex_idx = -1;
275 constexpr double tol = 1e-9; // A small tolerance for floating point comparison
276
277 for (int i = 0; i < m_mesh.GetNV(); ++i) {
278 const double* vertex_coords = m_mesh.GetVertex(i);
279 if (std::abs(vertex_coords[0]) < tol &&
280 std::abs(vertex_coords[1]) < tol &&
281 std::abs(vertex_coords[2]) < tol) {
282
283 center_vertex_idx = i;
284 break; // Found it, assume there's only one.
285 }
286 }
287
288 if (center_vertex_idx == -1) {
289 MFEM_ABORT("Could not find the center vertex at [0,0,0]. Check mesh construction.");
290 }
291
292 // --- 2. Get Theta (H1) DoFs associated ONLY with that vertex ---
293 // CORRECTED: Use GetVertexDofs, not GetVDofs.
294 m_feTheta->GetVertexDofs(center_vertex_idx, thetaCenterDofs);
295
296
297 mfem::Array<int> central_element_ids;
298
299 // PERF: could probably move this to a member variable and populate during construction
300 mfem::Table* vertex_to_elements_table = m_mesh.GetVertexToElementTable();
301 vertex_to_elements_table->Finalize();
302 mfem::Array<int> element_ids;
303 vertex_to_elements_table->GetRow(center_vertex_idx, element_ids);
304 delete vertex_to_elements_table;
305
306 for (int i = 0; i < element_ids.Size(); ++i) {
307 int element_id = element_ids[i];
308 mfem::Array<int> tempDofs;
309 m_fePhi->GetElementDofs(element_id, tempDofs);
310
311 // decode negative dofs to their true, physical, dof indices
312 for (int j = 0; j < tempDofs.Size(); ++j) {
313 int dof = tempDofs[j];
314 if (dof < 0) {
315 dof = -dof - 1; // Convert to positive index
316 }
317 phiCenterDofs.Append(dof);
318 }
319 }
320
321
322 phiCenterDofs.Sort();
323 phiCenterDofs.Unique();
324
325 return std::make_pair(thetaCenterDofs, phiCenterDofs);
326}
327
329 // --- Set the initial guess for the solution ---
330 mfem::FunctionCoefficient thetaInitGuess (
331 [this](const mfem::Vector &x) {
332 const double r = x.Norml2();
333 // const double radius = Probe::getMeshRadius(*m_mesh);
334 // const double u = 1/radius;
335
336 // return (-1.0/radius) * r + 1;
337 // return -std::pow((u*r), 2)+1.0; // The series expansion is a better guess; however, this is cheaper and ensures that the value at the surface is very close to zero in a way that the series expansion does not
339 }
340 );
341
342 mfem::VectorFunctionCoefficient phiSurfaceVectors (m_mesh.SpaceDimension(),
343 [this](const mfem::Vector &x, mfem::Vector &y) {
344 const double r = x.Norml2();
345 mfem::Vector xh(x);
346 xh /= r; // Normalize the vector
347 y.SetSize(m_mesh.SpaceDimension());
348 y = xh;
349 y *= polycoeff::thetaSurfaceFlux(m_polytropicIndex); // Assumes polycoeff is now serif::polytrope::polycoeff
350 }
351 );
352 // We want to apply specific boundary conditions to the surface
353 mfem::Array<int> ess_brd(m_mesh.bdr_attributes.Max());
354 ess_brd = 1;
355
356 // θ = 0 at surface
357 mfem::ConstantCoefficient surfacePotential(0);
358
359 m_theta->ProjectCoefficient(thetaInitGuess);
360 m_theta->ProjectBdrCoefficient(surfacePotential, ess_brd);
361
362 mfem::GradientGridFunctionCoefficient phiInitGuess (m_theta.get());
363 m_phi->ProjectCoefficient(phiInitGuess);
364
365 // Note that this will not result in perfect boundary conditions
366 // because it must maintain H(div) continuity, this is
367 // why inhomogenous boundary conditions enforcement is needed for φ
368 // This manifests in PolytropeOperator::Mult where we do not
369 // just zero out the essential dof elements in the residuals vector
370 // for φ; rather, we need to set this to something which will push the
371 // solver towards a more consistent answer (x_φ - target)
372 m_phi->ProjectBdrCoefficientNormal(phiSurfaceVectors, ess_brd);
373
374 auto [thetaCenterDofs, phiCenterDofs] = findCenterElement();
375
376 for (int i = 0; i < phiCenterDofs.Size(); ++i)
377 {
378 (*m_phi)(phiCenterDofs[i]) = 0.0;
379 }
380
381 if (m_config.get<bool>("Poly:Solver:ViewInitialGuess", false)) {
384 }
385
386}
387
388void PolySolver::saveAndViewSolution(const mfem::BlockVector& state_vector) const {
389 mfem::BlockVector x_block(const_cast<mfem::BlockVector&>(state_vector), m_polytropOperator->get_block_offsets());
390 mfem::Vector& x_theta = x_block.GetBlock(0);
391 mfem::Vector& x_phi = x_block.GetBlock(1);
392
393 if (m_config.get<bool>("Poly:Output:View", false)) {
394 serif::probe::glVisView(x_theta, *m_feTheta, "θ Solution");
395 serif::probe::glVisView(x_phi, *m_fePhi, "ɸ Solution");
396 }
397
398 // --- Extract the Solution ---
399 if (m_config.get<bool>("Poly:Output:1D:Save", true)) {
400 const auto solutionPath = m_config.get<std::string>("Poly:Output:1D:Path", "polytropeSolution_1D.csv");
401 auto derivSolPath = "d" + solutionPath;
402
403 const auto rayCoLatitude = m_config.get<double>("Poly:Output:1D:RayCoLatitude", 0.0);
404 const auto rayLongitude = m_config.get<double>("Poly:Output:1D:RayLongitude", 0.0);
405 const auto raySamples = m_config.get<int>("Poly:Output:1D:RaySamples", 100);
406
407 const std::vector rayDirection = {rayCoLatitude, rayLongitude};
408
409 serif::probe::getRaySolution(x_theta, *m_feTheta, rayDirection, raySamples, solutionPath);
410 // Probe::getRaySolution(x_phi, *m_fePhi, rayDirection, raySamples, derivSolPath);
411 }
412}
413
415 const serif::types::MFEMArrayPairSet ess_tdof_pair_set = getEssentialTrueDof();
416 m_polytropOperator->set_essential_true_dofs(ess_tdof_pair_set);
417}
418
419void PolySolver::LoadSolverUserParams(double &newtonRelTol, double &newtonAbsTol, int &newtonMaxIter, int &newtonPrintLevel,
420 double &gmresRelTol, double &gmresAbsTol, int &gmresMaxIter, int &gmresPrintLevel) const {
421 newtonRelTol = m_config.get<double>("Poly:Solver:Newton:RelTol", 1.e-4);
422 newtonAbsTol = m_config.get<double>("Poly:Solver:Newton:AbsTol", 1.e-6);
423 newtonMaxIter = m_config.get<int>("Poly:Solver:Newton:MaxIter", 10);
424 newtonPrintLevel = m_config.get<int>("Poly:Solver:Newton:PrintLevel", 3);
425
426 gmresRelTol = m_config.get<double>("Poly:Solver:GMRES:RelTol", 1.e-12);
427 gmresAbsTol = m_config.get<double>("Poly:Solver:GMRES:AbsTol", 1.e-12);
428 gmresMaxIter = m_config.get<int>("Poly:Solver:GMRES:MaxIter", 200);
429 gmresPrintLevel = m_config.get<int>("Poly:Solver:GMRES:PrintLevel", -1);
430
431 LOG_DEBUG(m_logger, "Newton Solver (relTol: {:0.2E}, absTol: {:0.2E}, maxIter: {}, printLevel: {})", newtonRelTol, newtonAbsTol, newtonMaxIter, newtonPrintLevel);
432 LOG_DEBUG(m_logger, "GMRES Solver (relTol: {:0.2E}, absTol: {:0.2E}, maxIter: {}, printLevel: {})", gmresRelTol, gmresAbsTol, gmresMaxIter, gmresPrintLevel);
433}
434
435void PolySolver::GetDofCoordinates(const mfem::FiniteElementSpace &fes, const std::string& filename) {
436 mfem::Mesh *mesh = fes.GetMesh();
438 std::ofstream outputFile(filename, std::ios::out | std::ios::trunc);
439 outputFile << "dof,R,r,x,y,z" << '\n';
440
441 const int nElements = mesh->GetNE();
442
443 mfem::Vector coords;
444 mfem::IntegrationPoint ipZero;
445 double p[3] = {0.0, 0.0, 0.0};
446 int actual_idx;
447 ipZero.Set3(p);
448 for (int i = 0; i < nElements; i++) {
449 mfem::Array<int> elemDofs;
450 fes.GetElementDofs(i, elemDofs);
451 mfem::ElementTransformation* T = mesh->GetElementTransformation(i);
452 mfem::Vector physCoord(3);
453 T->Transform(ipZero, physCoord);
454 for (int dofID = 0; dofID < elemDofs.Size(); dofID++) {
455 if (elemDofs[dofID] < 0) {
456 actual_idx = -elemDofs[dofID] - 1;
457 } else {
458 actual_idx = elemDofs[dofID];
459 }
460 outputFile << actual_idx;
461 if (dofID != elemDofs.Size() - 1) {
462 outputFile << "|";
463 } else {
464 outputFile << ",";
465 }
466 }
467 outputFile << r << "," << physCoord.Norml2() << "," << physCoord[0] << "," << physCoord[1] << "," << physCoord[2] << '\n';
468 }
469 outputFile.close();
470}
471
473 // --- Load configuration parameters ---
474 double newtonRelTol, newtonAbsTol, gmresRelTol, gmresAbsTol;
475 int newtonMaxIter, newtonPrintLevel, gmresMaxIter, gmresPrintLevel;
476 LoadSolverUserParams(newtonRelTol, newtonAbsTol, newtonMaxIter, newtonPrintLevel, gmresRelTol, gmresAbsTol,
477 gmresMaxIter, gmresPrintLevel);
478
479 solverBundle solver; // Use this solver bundle to ensure lifetime safety
480 solver.solver.SetRelTol(gmresRelTol);
481 solver.solver.SetAbsTol(gmresAbsTol);
482 solver.solver.SetMaxIter(gmresMaxIter);
483 solver.solver.SetPrintLevel(gmresPrintLevel);
484
485 // solver.solver.SetPreconditioner(m_polytropOperator->GetPreconditioner());
486 // --- Set up the Newton solver ---
487 solver.newton.SetRelTol(newtonRelTol);
488 solver.newton.SetAbsTol(newtonAbsTol);
489 solver.newton.SetMaxIter(newtonMaxIter);
490 solver.newton.SetPrintLevel(newtonPrintLevel);
491 solver.newton.SetOperator(*m_polytropOperator);
492
493 // --- Created the linear solver which is used to invert the jacobian ---
494 solver.newton.SetSolver(solver.solver);
495
496 return solver;
497}
498
499} // namespace serif::polytrope
500
void saveAndViewSolution(const mfem::BlockVector &state_vector) const
Saves the 1D radial solution and optionally displays the 2D/3D solution using GLVis.
~PolySolver()
Destructor for PolySolver.
double m_polytropicIndex
The polytropic index .
Definition polySolver.h:290
std::unique_ptr< mfem::H1_FECollection > m_fecH1
Finite Element Collection for (H1 elements).
Definition polySolver.h:295
serif::types::MFEMArrayPairSet getEssentialTrueDof() const
Computes the essential true degrees of freedom (DOFs) and their values for boundary conditions.
void solve() const
Solves the polytropic system.
PolySolver(const double n, const double order)
double m_feOrder
The polynomial order for H1 elements ( ). RT elements for are of order m_feOrder - 1.
Definition polySolver.h:291
std::unique_ptr< mfem::GridFunction > m_phi
Grid function for the vector flux .
Definition polySolver.h:303
static void GetDofCoordinates(const mfem::FiniteElementSpace &fes, const std::string &filename)
Utility function to get and save the coordinates of degrees of freedom for a finite element space.
static void assembleAndFinalizeForm(auto &f)
Assemble and finalize a given MFEM form.
mfem::Array< int > computeBlockOffsets() const
Compute the block offsets for the operator. These are the offsets that define which dofs belong to wh...
solverBundle setupNewtonSolver() const
Sets up the Newton solver and its associated linear solver (GMRES).
quill::Logger * m_logger
Pointer to the specific logger instance for this class.
Definition polySolver.h:287
std::unique_ptr< PolytropeOperator > m_polytropOperator
The main nonlinear operator for the mixed system.
Definition polySolver.h:306
void assembleBlockSystem()
Assembles the block system operator m_polytropOperator.
void LoadSolverUserParams(double &newtonRelTol, double &newtonAbsTol, int &newtonMaxIter, int &newtonPrintLevel, double &gmresRelTol, double &gmresAbsTol, int &gmresMaxIter, int &gmresPrintLevel) const
Loads Newton and GMRES solver parameters from the configuration.
mfem::Mesh & m_mesh
Reference to the computational mesh (owned by ResourceManager).
Definition polySolver.h:294
void setOperatorEssentialTrueDofs() const
Sets the essential true DOFs on the PolytropeOperator.
std::unique_ptr< mfem::FiniteElementSpace > m_fePhi
Finite Element Space for .
Definition polySolver.h:299
std::unique_ptr< formBundle > buildIndividualForms(const mfem::Array< int > &blockOffsets)
Build the individual forms for the block operator (M, Q, D, S, and f).
static mfem::Mesh & prepareMesh(double n)
Prepares the mesh for the simulation.
std::pair< mfem::Array< int >, mfem::Array< int > > findCenterElement() const
Finds the degrees of freedom (DOFs) associated with the geometric center (origin) of the mesh.
std::unique_ptr< mfem::GridFunction > m_theta
Grid function for the scalar potential .
Definition polySolver.h:302
void setInitialGuess() const
Sets the initial guess for the solution variables and .
std::unique_ptr< mfem::FiniteElementSpace > m_feTheta
Finite Element Space for .
Definition polySolver.h:298
serif::probe::LogManager & m_logManager
Reference to the global log manager instance.
Definition polySolver.h:286
std::unique_ptr< mfem::RT_FECollection > m_fecRT
Finite Element Collection for (Raviart-Thomas elements).
Definition polySolver.h:296
serif::config::Config & m_config
Reference to the global configuration manager instance.
Definition polySolver.h:285
A class for nonlinear power integrator.
Definition integrators.h:43
const types::Resource & getResource(const std::string &name) const
Gets a resource by name.
static ResourceManager & getInstance()
Gets the singleton instance of the ResourceManager.
A collection of utilities for working with MFEM and solving the lane-emden equation.
Namespace for Lane-Emden equation related utility functions.
double thetaSeriesExpansion(const double xi, const double n, const int order)
double a(const int k, const double n)
Computes the coefficient for the Lane-Emden series expansion.
double c(const int m, const double n)
Computes the auxiliary coefficient used in determining .
double thetaSurfaceFlux(const double n)
Definition polyCoeff.cpp:54
double x1(const double n)
Definition polyCoeff.cpp:45
The Probe namespace contains utility functions for debugging and logging.
Definition probe.cpp:45
double getMeshRadius(mfem::Mesh &mesh)
Definition probe.cpp:91
void glVisView(mfem::GridFunction &u, mfem::Mesh &mesh, const std::string &windowTitle, const std::string &keyset)
Visualize a solution using GLVis.
Definition probe.cpp:57
std::pair< std::vector< double >, std::vector< double > > getRaySolution(mfem::GridFunction &u, mfem::Mesh &mesh, const std::vector< double > &rayDirection, int numSamples, std::string filename)
Definition probe.cpp:108
std::variant< std::unique_ptr< opat::OPAT >, std::unique_ptr< serif::mesh::MeshIO >, std::unique_ptr< serif::eos::EOSio > > Resource
A variant type that can hold different types of resources.
std::pair< mfem::Array< int >, mfem::Array< double > > MFEMArrayPair
Definition 4DSTARTypes.h:27
std::pair< MFEMArrayPair, MFEMArrayPair > MFEMArrayPairSet
Definition 4DSTARTypes.h:28
Defines types and functions for managing resources.
Structure to manage the lifetime of MFEM solver objects.
Definition polySolver.h:117
mfem::GMRESSolver solver
The linear solver (e.g., GMRES). Must be declared first.
Definition polySolver.h:118
mfem::NewtonSolver newton
The nonlinear solver (e.g., Newton). Must be declared second.
Definition polySolver.h:119