• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Open-Sn / opensn / 22249939997

20 Feb 2026 06:11PM UTC coverage: 74.156% (-0.2%) from 74.335%
22249939997

push

github

web-flow
Merge pull request #937 from andrsd/issue/90-num-precursors

Number of precursors is `unsigned int`

4 of 7 new or added lines in 5 files covered. (57.14%)

527 existing lines in 19 files now uncovered.

19997 of 26966 relevant lines covered (74.16%)

67202602.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.29
/modules/diffusion/diffusion.cc
1
// SPDX-FileCopyrightText: 2024 The OpenSn Authors <https://open-sn.github.io/opensn/>
2
// SPDX-License-Identifier: MIT
3

4
#include "modules/diffusion/diffusion.h"
5
#include "framework/math/spatial_discretization/spatial_discretization.h"
6
#include "framework/mesh/mesh_continuum/mesh_continuum.h"
7
#include "framework/math/petsc_utils/petsc_utils.h"
8
#include "framework/logging/log.h"
9
#include "framework/runtime.h"
10

11
namespace opensn
12
{
13

14
DiffusionSolver::DiffusionSolver(std::string name,
69✔
15
                                 const opensn::SpatialDiscretization& sdm,
16
                                 const UnknownManager& uk_man,
17
                                 std::map<uint64_t, BoundaryCondition> bcs,
18
                                 MatID2XSMap map_mat_id_2_xs,
19
                                 const std::vector<UnitCellMatrices>& unit_cell_matrices,
20
                                 const bool suppress_bcs,
21
                                 const bool requires_ghosts,
22
                                 const bool verbose)
69✔
23
  : name_(std::move(name)),
69✔
24
    grid_(sdm.GetGrid()),
69✔
25
    sdm_(sdm),
69✔
26
    uk_man_(uk_man),
69✔
27
    bcs_(std::move(bcs)),
69✔
28
    mat_id_2_xs_map_(std::move(map_mat_id_2_xs)),
69✔
29
    unit_cell_matrices_(unit_cell_matrices),
69✔
30
    num_local_dofs_(static_cast<PetscInt>(sdm_.GetNumLocalDOFs(uk_man_))),
69✔
31
    num_global_dofs_(static_cast<PetscInt>(sdm_.GetNumGlobalDOFs(uk_man_))),
69✔
32
    A_(nullptr),
69✔
33
    rhs_(nullptr),
69✔
34
    ksp_(nullptr),
69✔
35
    requires_ghosts_(requires_ghosts),
69✔
36
    suppress_bcs_(suppress_bcs)
69✔
37
{
38
  options.verbose = verbose;
69✔
39
}
69✔
40

41
DiffusionSolver::~DiffusionSolver()
414✔
42
{
43
  OpenSnPETScCall(MatDestroy(&A_));
44
  OpenSnPETScCall(VecDestroy(&rhs_));
45
  OpenSnPETScCall(KSPDestroy(&ksp_));
46
}
138✔
47

69✔
48
std::string
69✔
49
DiffusionSolver::GetName() const
69✔
50
{
×
51
  return name_;
×
52
}
53

54
const Vec&
55
DiffusionSolver::GetRHS() const
×
56
{
57
  return rhs_;
×
58
}
59

60
const UnknownManager&
61
DiffusionSolver::GetUnknownStructure() const
21,604✔
62
{
63
  return uk_man_;
21,604✔
64
}
65

66
const SpatialDiscretization&
67
DiffusionSolver::GetSpatialDiscretization() const
13,972✔
68
{
69
  return sdm_;
13,972✔
70
}
71

72
std::pair<size_t, size_t>
73
DiffusionSolver::GetNumPhiIterativeUnknowns()
×
74
{
75
  return {sdm_.GetNumLocalDOFs(uk_man_), sdm_.GetNumGlobalDOFs(uk_man_)};
×
76
}
77

78
void
79
DiffusionSolver::AddToRHS(const std::vector<double>& values)
128✔
80
{
81
  const auto num_local_dofs = sdm_.GetNumLocalDOFs(uk_man_);
128✔
82
  if (num_local_dofs != values.size())
128✔
83
    throw std::invalid_argument("Vector size mismatch.");
×
84

85
  PetscScalar* rhs_ptr = nullptr;
128✔
86
  OpenSnPETScCall(VecGetArray(rhs_, &rhs_ptr));
128✔
87
  for (size_t i = 0; i < num_local_dofs; ++i)
2,688,128✔
88
    rhs_ptr[i] += values[i];
2,688,000✔
89
  OpenSnPETScCall(VecRestoreArray(rhs_, &rhs_ptr));
128✔
90
}
128✔
91

92
void
93
DiffusionSolver::AddToMatrix(const std::vector<PetscInt>& rows,
4✔
94
                             const std::vector<PetscInt>& cols,
95
                             const std::vector<double>& vals)
96
{
97
  if (rows.size() != cols.size() or rows.size() != vals.size())
4✔
98
    throw std::invalid_argument("The number of row entries, column entries, and value "
×
99
                                "entries do not agree.");
×
100
  for (int i = 0; i < vals.size(); ++i)
4✔
101
    OpenSnPETScCall(MatSetValue(A_, rows[i], cols[i], vals[i], ADD_VALUES));
×
102
  OpenSnPETScCall(MatAssemblyBegin(A_, MAT_FLUSH_ASSEMBLY));
4✔
103
  OpenSnPETScCall(MatAssemblyEnd(A_, MAT_FLUSH_ASSEMBLY));
4✔
104
}
4✔
105

106
void
107
DiffusionSolver::Initialize()
69✔
108
{
109
  if (options.verbose)
69✔
110
    log.Log() << name_ << ": Initializing PETSc items";
12✔
111

112
  if (options.verbose)
69✔
113
    log.Log() << name_ << ": Global number of DOFs=" << num_global_dofs_;
12✔
114

115
  opensn::mpi_comm.barrier();
69✔
116
  log.Log() << "Sparsity pattern";
138✔
117
  opensn::mpi_comm.barrier();
69✔
118
  // Create Matrix
119
  std::vector<int64_t> nodal_nnz_in_diag;
69✔
120
  std::vector<int64_t> nodal_nnz_off_diag;
69✔
121
  sdm_.BuildSparsityPattern(nodal_nnz_in_diag, nodal_nnz_off_diag, uk_man_);
69✔
122
  opensn::mpi_comm.barrier();
69✔
123
  log.Log() << "Done Sparsity pattern";
138✔
124
  opensn::mpi_comm.barrier();
69✔
125
  A_ = CreateSquareMatrix(num_local_dofs_, num_global_dofs_);
69✔
126
  InitMatrixSparsity(A_, nodal_nnz_in_diag, nodal_nnz_off_diag);
69✔
127
  opensn::mpi_comm.barrier();
69✔
128
  log.Log() << "Done matrix creation";
138✔
129
  opensn::mpi_comm.barrier();
69✔
130

131
  // Create RHS
132
  if (not requires_ghosts_)
69✔
133
    rhs_ = CreateVector(num_local_dofs_, num_global_dofs_);
64✔
134
  else
135
  {
136
    auto ghost_ids = sdm_.GetGhostDOFIndices(uk_man_);
5✔
137
    std::vector<int64_t> ghids(ghost_ids.begin(), ghost_ids.end());
5✔
138
    rhs_ = CreateVectorWithGhosts(num_local_dofs_,
5✔
139
                                  num_global_dofs_,
5✔
140
                                  static_cast<int64_t>(sdm_.GetNumGhostDOFs(uk_man_)),
5✔
141
                                  ghids);
142
  }
5✔
143

144
  opensn::mpi_comm.barrier();
69✔
145
  log.Log() << "Done vector creation";
138✔
146
  opensn::mpi_comm.barrier();
69✔
147

148
  // Create KSP
149
  OpenSnPETScCall(KSPCreate(opensn::mpi_comm, &ksp_));
69✔
150
  OpenSnPETScCall(KSPSetOptionsPrefix(ksp_, name_.c_str()));
69✔
151
  OpenSnPETScCall(KSPSetType(ksp_, KSPCG));
69✔
152

153
  OpenSnPETScCall(
69✔
154
    KSPSetTolerances(ksp_, 1.0e-50, options.residual_tolerance, 1.0e50, options.max_iters));
155

156
  // Set Pre-conditioner
157
  PC pc = nullptr;
69✔
158
  OpenSnPETScCall(KSPGetPC(ksp_, &pc));
69✔
159
  //  PCSetType(pc, PCGAMG);
160
  OpenSnPETScCall(PCSetType(pc, PCHYPRE));
69✔
161

162
  OpenSnPETScCall(PCHYPRESetType(pc, "boomeramg"));
69✔
163
  std::vector<std::string> pc_options = {"pc_hypre_boomeramg_agg_nl 1",
69✔
164
                                         "pc_hypre_boomeramg_P_max 4",
165
                                         "pc_hypre_boomeramg_grid_sweeps_coarse 1",
166
                                         "pc_hypre_boomeramg_max_levels 25",
167
                                         "pc_hypre_boomeramg_relax_type_all symmetric-SOR/Jacobi",
168
                                         "pc_hypre_boomeramg_coarsen_type HMIS",
169
                                         "pc_hypre_boomeramg_interp_type ext+i"};
69✔
170

171
  if (grid_->GetDimension() == 2)
69✔
172
    pc_options.emplace_back("pc_hypre_boomeramg_strong_threshold 0.6");
38✔
173
  else if (grid_->GetDimension() == 3)
31✔
174
    pc_options.emplace_back("pc_hypre_boomeramg_strong_threshold 0.8");
16✔
175

176
  for (const auto& option : pc_options)
606✔
177
    OpenSnPETScCall(PetscOptionsInsertString(nullptr, ("-" + name_ + option).c_str()));
537✔
178

179
  OpenSnPETScCall(PetscOptionsInsertString(nullptr, options.additional_options_string.c_str()));
69✔
180

181
  OpenSnPETScCall(PCSetFromOptions(pc));
69✔
182
  OpenSnPETScCall(KSPSetFromOptions(ksp_));
69✔
183
}
69✔
184

185
void
186
DiffusionSolver::Solve(std::vector<double>& solution, bool use_initial_guess)
9,102✔
187
{
188
  const std::string fname = "acceleration::DiffusionMIPSolver::Solve";
9,102✔
189
  Vec x = nullptr;
9,102✔
190
  OpenSnPETScCall(VecDuplicate(rhs_, &x));
9,102✔
191
  OpenSnPETScCall(VecSet(x, 0.0));
9,102✔
192

193
  if (not use_initial_guess)
9,102✔
194
    OpenSnPETScCall(KSPSetInitialGuessNonzero(ksp_, PETSC_FALSE));
6,550✔
195
  else
196
    OpenSnPETScCall(KSPSetInitialGuessNonzero(ksp_, PETSC_TRUE));
2,552✔
197

198
  OpenSnPETScCall(KSPSetTolerances(
9,102✔
199
    ksp_, options.residual_tolerance, options.residual_tolerance, 1.0e50, options.max_iters));
200

201
  if (options.perform_symmetry_check)
9,102✔
202
  {
203
    PetscBool symmetry = PETSC_FALSE;
4✔
204
    OpenSnPETScCall(MatIsSymmetric(A_, 1.0e-6, &symmetry));
4✔
205
    if (symmetry == PETSC_FALSE)
4✔
UNCOV
206
      throw std::logic_error(fname + ":Symmetry check failed");
×
207
  }
208

209
  if (options.verbose)
9,102✔
210
  {
211
    OpenSnPETScCall(KSPMonitorSet(ksp_, &KSPMonitorRelativeToRHS, nullptr, nullptr));
132✔
212

213
    double rhs_norm = 0.0;
132✔
214
    OpenSnPETScCall(VecNorm(rhs_, NORM_2, &rhs_norm));
132✔
215
    log.Log() << "RHS-norm " << rhs_norm;
396✔
216
  }
217

218
  if (use_initial_guess)
9,102✔
219
  {
220
    double* x_raw = nullptr;
2,552✔
221
    OpenSnPETScCall(VecGetArray(x, &x_raw));
2,552✔
222
    size_t k = 0;
2,552✔
223
    for (const auto& value : solution)
10,447,352✔
224
      x_raw[k++] = value;
10,444,800✔
225
    OpenSnPETScCall(VecRestoreArray(x, &x_raw));
2,552✔
226
  }
227

228
  // Solve
229
  OpenSnPETScCall(KSPSolve(ksp_, rhs_, x));
9,102✔
230

231
  // Print convergence info
232
  if (options.verbose)
9,102✔
233
  {
234
    double sol_norm = 0.0;
132✔
235
    OpenSnPETScCall(VecNorm(x, NORM_2, &sol_norm));
132✔
236
    log.Log() << "Solution-norm " << sol_norm;
396✔
237

238
    KSPConvergedReason reason = KSP_CONVERGED_ITERATING;
132✔
239
    OpenSnPETScCall(KSPGetConvergedReason(ksp_, &reason));
132✔
240

241
    log.Log() << "Convergence Reason: " << GetPETScConvergedReasonstring(reason);
396✔
242
  }
243

244
  // Transfer petsc solution to vector
245
  if (requires_ghosts_)
9,102✔
246
  {
247
    CommunicateGhostEntries(x);
130✔
248
    sdm_.LocalizePETScVectorWithGhosts(x, solution, uk_man_);
130✔
249
  }
250
  else
251
    sdm_.LocalizePETScVector(x, solution, uk_man_);
8,972✔
252

253
  // Cleanup x
254
  OpenSnPETScCall(VecDestroy(&x));
9,102✔
255
}
9,102✔
256

257
void
UNCOV
258
DiffusionSolver::Solve(Vec petsc_solution, bool use_initial_guess)
×
259
{
260
  const std::string fname = "acceleration::DiffusionMIPSolver::Solve";
×
261
  Vec x = nullptr;
×
262
  OpenSnPETScCall(VecDuplicate(rhs_, &x));
×
UNCOV
263
  OpenSnPETScCall(VecSet(x, 0.0));
×
264

265
  if (not use_initial_guess)
×
UNCOV
266
    OpenSnPETScCall(KSPSetInitialGuessNonzero(ksp_, PETSC_FALSE));
×
267
  else
UNCOV
268
    OpenSnPETScCall(KSPSetInitialGuessNonzero(ksp_, PETSC_TRUE));
×
269

270
  OpenSnPETScCall(KSPSetTolerances(
×
271
    ksp_, options.residual_tolerance, options.residual_tolerance, 1.0e50, options.max_iters));
272

UNCOV
273
  if (options.perform_symmetry_check)
×
274
  {
275
    PetscBool symmetry = PETSC_FALSE;
×
276
    OpenSnPETScCall(MatIsSymmetric(A_, 1.0e-6, &symmetry));
×
277
    if (symmetry == PETSC_FALSE)
×
UNCOV
278
      throw std::logic_error(fname + ":Symmetry check failed");
×
279
  }
280

UNCOV
281
  if (options.verbose)
×
282
  {
UNCOV
283
    OpenSnPETScCall(KSPMonitorSet(ksp_, &KSPMonitorRelativeToRHS, nullptr, nullptr));
×
284

285
    double rhs_norm = 0.0;
×
286
    OpenSnPETScCall(VecNorm(rhs_, NORM_2, &rhs_norm));
×
UNCOV
287
    log.Log() << "RHS-norm " << rhs_norm;
×
288
  }
289

UNCOV
290
  if (use_initial_guess)
×
291
  {
UNCOV
292
    OpenSnPETScCall(VecCopy(petsc_solution, x));
×
293
  }
294

295
  // Solve
UNCOV
296
  OpenSnPETScCall(KSPSolve(ksp_, rhs_, x));
×
297

298
  // Print convergence info
UNCOV
299
  if (options.verbose)
×
300
  {
301
    double sol_norm = 0.0;
×
302
    OpenSnPETScCall(VecNorm(x, NORM_2, &sol_norm));
×
UNCOV
303
    log.Log() << "Solution-norm " << sol_norm;
×
304

305
    KSPConvergedReason reason = KSP_CONVERGED_ITERATING;
×
UNCOV
306
    OpenSnPETScCall(KSPGetConvergedReason(ksp_, &reason));
×
307

UNCOV
308
    log.Log() << "Convergence Reason: " << GetPETScConvergedReasonstring(reason);
×
309
  }
310

311
  // Transfer petsc solution to vector
UNCOV
312
  OpenSnPETScCall(VecCopy(x, petsc_solution));
×
313

314
  // Cleanup x
315
  OpenSnPETScCall(VecDestroy(&x));
×
UNCOV
316
}
×
317

318
} // namespace opensn
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc