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

Open-Sn / opensn / 18928565313

22 Oct 2025 07:55PM UTC coverage: 74.771%. Remained the same
18928565313

push

github

web-flow
Merge pull request #807 from wdhawkins/clang-tidy-init-variables

Fixing clang-tidy init-variables warnings

132 of 179 new or added lines in 52 files covered. (73.74%)

184 existing lines in 3 files now uncovered.

18203 of 24345 relevant lines covered (74.77%)

53868061.69 hits per line

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

75.91
/modules/diffusion/diffusion_mip_solver.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_mip_solver.h"
5
#include "modules/linear_boltzmann_solvers/lbs_problem/acceleration/acceleration.h"
6
#include "modules/linear_boltzmann_solvers/lbs_problem/lbs_structs.h"
7
#include "framework/mesh/mesh_continuum/mesh_continuum.h"
8
#include "framework/math/spatial_discretization/finite_element/finite_element_data.h"
9
#include "framework/math/spatial_discretization/spatial_discretization.h"
10
#include "framework/math/spatial_discretization/finite_element/unit_cell_matrices.h"
11
#include "framework/math/functions/function.h"
12
#include "framework/runtime.h"
13
#include "framework/logging/log.h"
14
#include "framework/utils/timer.h"
15
#include <utility>
16

17
namespace opensn
18
{
19

20
DiffusionMIPSolver::DiffusionMIPSolver(std::string name,
68✔
21
                                       const opensn::SpatialDiscretization& sdm,
22
                                       const UnknownManager& uk_man,
23
                                       std::map<uint64_t, BoundaryCondition> bcs,
24
                                       MatID2XSMap map_mat_id_2_xs,
25
                                       const std::vector<UnitCellMatrices>& unit_cell_matrices,
26
                                       const bool suppress_bcs,
27
                                       const bool verbose)
68✔
28
  : DiffusionSolver(std::move(name),
29
                    sdm,
30
                    uk_man,
31
                    std::move(bcs),
32
                    std::move(map_mat_id_2_xs),
33
                    unit_cell_matrices,
34
                    false,
35
                    suppress_bcs,
36
                    verbose)
136✔
37
{
38
  if (sdm_.GetType() != SpatialDiscretizationType::PIECEWISE_LINEAR_DISCONTINUOUS)
68✔
39
    throw std::logic_error("acceleration::DiffusionMIPSolver can only be used with PWLD.");
×
40
}
68✔
41

42
void
43
DiffusionMIPSolver::AssembleAand_b_wQpoints(const std::vector<double>& q_vector)
1✔
44
{
45
  const std::string fname = "acceleration::DiffusionMIPSolver::"
1✔
46
                            "AssembleAand_b_wQpoints";
1✔
47
  if (A_ == nullptr or rhs_ == nullptr or ksp_ == nullptr)
1✔
48
    throw std::logic_error(fname + ": Some or all PETSc elements are null. "
×
49
                                   "Check that Initialize has been called.");
×
50
  if (options.verbose)
1✔
51
    log.Log() << program_timer.GetTimeString() << " Starting assembly";
3✔
52

53
  const size_t num_groups = uk_man_.unknowns.front().num_components;
1✔
54

55
  VecSet(rhs_, 0.0);
1✔
56

57
  for (const auto& cell : grid_->local_cells)
101✔
58
  {
59
    const size_t num_faces = cell.faces.size();
100✔
60
    const auto& cell_mapping = sdm_.GetCellMapping(cell);
100✔
61
    const auto num_nodes = cell_mapping.GetNumNodes();
100✔
62
    const auto cc_nodes = cell_mapping.GetNodeLocations();
100✔
63
    const auto fe_vol_data = cell_mapping.MakeVolumetricFiniteElementData();
100✔
64

65
    const auto& xs = mat_id_2_xs_map_.at(cell.block_id);
100✔
66

67
    DenseMatrix<double> cell_A(num_nodes, num_nodes);
100✔
68
    Vector<double> cell_rhs(num_nodes);
100✔
69
    Vector<PetscInt> cell_idxs(num_nodes);
100✔
70
    // For component/group
71
    for (size_t g = 0; g < num_groups; ++g)
200✔
72
    {
73
      cell_A.Set(0.);
100✔
74
      cell_rhs.Set(0.);
100✔
75
      for (size_t i = 0; i < num_nodes; ++i)
500✔
76
        cell_idxs(i) = static_cast<PetscInt>(sdm_.MapDOF(cell, i, uk_man_, 0, g));
400✔
77

78
      // Get coefficient and nodal src
79
      const double Dg = xs.Dg[g];
100✔
80
      const double sigr_g = xs.sigR[g];
100✔
81

82
      std::vector<double> qg(num_nodes, 0.0);
100✔
83
      for (size_t j = 0; j < num_nodes; ++j)
500✔
84
        qg[j] = q_vector[sdm_.MapDOFLocal(cell, j, uk_man_, 0, g)];
400✔
85

86
      // Assemble continuous terms
87
      for (size_t i = 0; i < num_nodes; ++i)
500✔
88
      {
89
        double entry_rhs_i = 0.0; // entry may accumulate over j
90
        for (size_t j = 0; j < num_nodes; ++j)
2,000✔
91
        {
92
          double entry_aij = 0.0;
1,600✔
93
          for (size_t qp : fe_vol_data.GetQuadraturePointIndices())
20,800✔
94
          {
95
            entry_aij += Dg * fe_vol_data.ShapeGrad(i, qp).Dot(fe_vol_data.ShapeGrad(j, qp)) *
19,200✔
96
                         fe_vol_data.JxW(qp);
19,200✔
97

98
            entry_aij += sigr_g * fe_vol_data.ShapeValue(i, qp) * fe_vol_data.ShapeValue(j, qp) *
19,200✔
99
                         fe_vol_data.JxW(qp);
19,200✔
100

101
            if (not source_function_)
19,200✔
102
              entry_rhs_i += fe_vol_data.ShapeValue(i, qp) * fe_vol_data.ShapeValue(j, qp) *
×
103
                             fe_vol_data.JxW(qp) * qg[j];
×
104
          } // for qp
105
          cell_A(i, j) += entry_aij;
1,600✔
106
        } // for j
107

108
        if (source_function_)
400✔
109
        {
110
          for (size_t qp : fe_vol_data.GetQuadraturePointIndices())
5,200✔
111
            entry_rhs_i += source_function_(fe_vol_data.QPointXYZ(qp)) *
4,800✔
112
                           fe_vol_data.ShapeValue(i, qp) * fe_vol_data.JxW(qp);
4,800✔
113
        }
114

115
        cell_rhs(i) += entry_rhs_i;
400✔
116
      } // for i
117

118
      // Assemble face terms
119
      for (size_t f = 0; f < num_faces; ++f)
500✔
120
      {
121
        const auto& face = cell.faces[f];
400✔
122
        const auto& n_f = face.normal;
400✔
123
        const auto num_face_nodes = cell_mapping.GetNumFaceNodes(f);
400✔
124
        const auto fe_srf_data = cell_mapping.MakeSurfaceFiniteElementData(f);
400✔
125

126
        const double hm = HPerpendicular(cell, f);
400✔
127

128
        if (face.has_neighbor)
400✔
129
        {
130
          const auto& adj_cell = grid_->cells[face.neighbor_id];
360✔
131
          const auto& adj_cell_mapping = sdm_.GetCellMapping(adj_cell);
360✔
132
          const auto ac_nodes = adj_cell_mapping.GetNodeLocations();
360✔
133
          const size_t acf = MeshContinuum::MapCellFace(cell, adj_cell, f);
360✔
134
          const double hp = HPerpendicular(adj_cell, acf);
360✔
135

136
          const auto& adj_xs = mat_id_2_xs_map_.at(adj_cell.block_id);
360✔
137
          const double adj_Dg = adj_xs.Dg[g];
360✔
138

139
          // Compute kappa
140
          double kappa = 1.0;
360✔
141
          if (cell.GetType() == CellType::SLAB)
360✔
142
            kappa = fmax(options.penalty_factor * (adj_Dg / hp + Dg / hm) * 0.5, 0.25);
×
143
          if (cell.GetType() == CellType::POLYGON)
360✔
144
            kappa = fmax(options.penalty_factor * (adj_Dg / hp + Dg / hm) * 0.5, 0.25);
360✔
145
          if (cell.GetType() == CellType::POLYHEDRON)
360✔
146
            kappa = fmax(options.penalty_factor * 2.0 * (adj_Dg / hp + Dg / hm) * 0.5, 0.25);
×
147

148
          DenseMatrix<double> adj_A(num_nodes, num_face_nodes, 0.);
360✔
149
          DenseMatrix<double> adj_AT(num_face_nodes, num_nodes, 0.);
360✔
150
          Vector<PetscInt> adj_idxs(num_face_nodes);
360✔
151
          for (size_t fj = 0; fj < num_face_nodes; ++fj)
1,080✔
152
          {
153
            const auto jp =
720✔
154
              MapFaceNodeDisc(cell, adj_cell, cc_nodes, ac_nodes, f, acf, fj); // j-plus
720✔
155
            adj_idxs(fj) = static_cast<PetscInt>(sdm_.MapDOF(adj_cell, jp, uk_man_, 0, g));
720✔
156
          }
157

158
          // Assembly penalty terms
159
          for (size_t fi = 0; fi < num_face_nodes; ++fi)
1,080✔
160
          {
161
            const int i = cell_mapping.MapFaceNode(f, fi);
720✔
162

163
            for (size_t fj = 0; fj < num_face_nodes; ++fj)
2,160✔
164
            {
165
              const int jm = cell_mapping.MapFaceNode(f, fj); // j-minus
1,440✔
166

167
              double aij = 0.0;
1,440✔
168
              for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
4,320✔
169
                aij += kappa * fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeValue(jm, qp) *
5,760✔
170
                       fe_srf_data.JxW(qp);
2,880✔
171

172
              cell_A(i, jm) += aij;
1,440✔
173
              adj_A(i, fj) -= aij;
1,440✔
174
            } // for fj
175
          } // for fi
176

177
          // Assemble gradient terms
178
          // For the following comments we use the notation:
179
          // Dk = 0.5* n dot nabla bk
180

181
          // 0.5*D* n dot (b_j^+ - b_j^-)*nabla b_i^-
182
          for (size_t i = 0; i < num_nodes; ++i)
1,800✔
183
          {
184
            for (size_t fj = 0; fj < num_face_nodes; ++fj)
4,320✔
185
            {
186
              const int jm = cell_mapping.MapFaceNode(f, fj); // j-minus
2,880✔
187

188
              Vector3 vec_aij;
2,880✔
189
              for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
8,640✔
190
                vec_aij += fe_srf_data.ShapeValue(jm, qp) * fe_srf_data.ShapeGrad(i, qp) *
5,760✔
191
                           fe_srf_data.JxW(qp);
11,520✔
192
              const double aij = -0.5 * Dg * n_f.Dot(vec_aij);
2,880✔
193

194
              cell_A(i, jm) += aij;
2,880✔
195
              adj_A(i, fj) -= aij;
2,880✔
196
            } // for fj
197
          } // for i
198

199
          // 0.5*D* n dot (b_i^+ - b_i^-)*nabla b_j^-
200
          for (size_t fi = 0; fi < num_face_nodes; ++fi)
1,080✔
201
          {
202
            const int im = cell_mapping.MapFaceNode(f, fi); // i-minus
720✔
203

204
            for (size_t j = 0; j < num_nodes; ++j)
3,600✔
205
            {
206
              Vector3 vec_aij;
2,880✔
207
              for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
8,640✔
208
                vec_aij += fe_srf_data.ShapeValue(im, qp) * fe_srf_data.ShapeGrad(j, qp) *
5,760✔
209
                           fe_srf_data.JxW(qp);
11,520✔
210
              const double aij = -0.5 * Dg * n_f.Dot(vec_aij);
2,880✔
211

212
              cell_A(im, j) += aij;
2,880✔
213
              adj_AT(fi, j) -= aij;
2,880✔
214
            } // for j
215
          } // for fi
216

217
          auto nn = static_cast<PetscInt>(num_nodes);
360✔
218
          auto nf = static_cast<PetscInt>(num_face_nodes);
360✔
219
          MatSetValues(A_, nn, cell_idxs.data(), nf, adj_idxs.data(), adj_A.data(), ADD_VALUES);
360✔
220

221
          MatSetValues(A_, nf, adj_idxs.data(), nn, cell_idxs.data(), adj_AT.data(), ADD_VALUES);
360✔
222

223
        } // internal face
1,080✔
224
        else
225
        {
226
          BoundaryCondition bc;
40✔
227
          if (bcs_.count(face.neighbor_id) > 0)
40✔
228
            bc = bcs_.at(face.neighbor_id);
40✔
229

230
          if (bc.type == BCType::DIRICHLET)
40✔
231
          {
232
            const double bc_value = bc.values[0];
40✔
233

234
            // Compute kappa
235
            double kappa = 1.0;
40✔
236
            if (cell.GetType() == CellType::SLAB)
40✔
237
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
×
238
            if (cell.GetType() == CellType::POLYGON)
40✔
239
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
40✔
240
            if (cell.GetType() == CellType::POLYHEDRON)
40✔
241
              kappa = fmax(options.penalty_factor * 2.0 * Dg / hm, 0.25);
×
242

243
            // Assembly penalty terms
244
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
120✔
245
            {
246
              const int i = cell_mapping.MapFaceNode(f, fi);
80✔
247

248
              for (size_t fj = 0; fj < num_face_nodes; ++fj)
240✔
249
              {
250
                const int jm = cell_mapping.MapFaceNode(f, fj);
160✔
251

252
                double aij = 0.0;
160✔
253
                for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
480✔
254
                  aij += kappa * fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeValue(jm, qp) *
640✔
255
                         fe_srf_data.JxW(qp);
320✔
256
                double aij_bc_value = aij * bc_value;
160✔
257

258
                if (ref_solution_function_)
160✔
259
                {
260
                  aij_bc_value = 0.0;
160✔
261
                  for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
480✔
262
                    aij_bc_value += kappa * ref_solution_function_(fe_srf_data.QPointXYZ(qp)) *
320✔
263
                                    fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeValue(jm, qp) *
640✔
264
                                    fe_srf_data.JxW(qp);
320✔
265
                }
266

267
                cell_A(i, jm) += aij;
160✔
268
                cell_rhs(i) += aij_bc_value;
160✔
269
              } // for fj
270
            } // for fi
271

272
            // Assemble gradient terms
273
            // For the following comments we use the notation:
274
            // Dk = n dot nabla bk
275

276
            // D* n dot (b_j^+ - b_j^-)*nabla b_i^-
277
            for (size_t i = 0; i < num_nodes; ++i)
200✔
278
            {
279
              for (size_t j = 0; j < num_nodes; ++j)
800✔
280
              {
281
                Vector3 vec_aij;
640✔
282
                for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
1,920✔
283
                  vec_aij += fe_srf_data.ShapeValue(j, qp) * fe_srf_data.ShapeGrad(i, qp) *
1,280✔
284
                               fe_srf_data.JxW(qp) +
2,560✔
285
                             fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeGrad(j, qp) *
2,560✔
286
                               fe_srf_data.JxW(qp);
3,840✔
287
                const double aij = -Dg * n_f.Dot(vec_aij);
640✔
288

289
                double aij_bc_value = aij * bc_value;
640✔
290

291
                if (ref_solution_function_)
640✔
292
                {
293
                  Vector3 vec_aij_mms;
640✔
294
                  for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
1,920✔
295
                    vec_aij_mms += ref_solution_function_(fe_srf_data.QPointXYZ(qp)) *
3,840✔
296
                                   (fe_srf_data.ShapeValue(j, qp) * fe_srf_data.ShapeGrad(i, qp) *
1,280✔
297
                                      fe_srf_data.JxW(qp) +
3,840✔
298
                                    fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeGrad(j, qp) *
1,280✔
299
                                      fe_srf_data.JxW(qp));
3,840✔
300
                  aij_bc_value = -Dg * n_f.Dot(vec_aij_mms);
640✔
301
                }
302

303
                cell_A(i, j) += aij;
640✔
304
                cell_rhs(i) += aij_bc_value;
640✔
305
              } // for fj
306
            } // for i
307
          } // Dirichlet BC
308
          else if (bc.type == BCType::ROBIN)
×
309
          {
310
            const double aval = bc.values[0];
×
311
            const double bval = bc.values[1];
×
312
            const double fval = bc.values[2];
×
313

314
            if (std::fabs(bval) < 1.0e-12)
×
315
              continue; // a and f assumed zero
×
316

317
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
×
318
            {
319
              const int i = cell_mapping.MapFaceNode(f, fi);
×
320

321
              if (std::fabs(aval) >= 1.0e-12)
×
322
              {
323
                for (size_t fj = 0; fj < num_face_nodes; ++fj)
×
324
                {
325
                  const int j = cell_mapping.MapFaceNode(f, fj);
×
326

327
                  double aij = 0.0;
×
328
                  for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
×
329
                    aij += fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeValue(j, qp) *
×
330
                           fe_srf_data.JxW(qp);
×
331
                  aij *= (aval / bval);
×
332

333
                  cell_A(i, j) += aij;
×
334
                } // for fj
335
              } // if a nonzero
336

337
              if (std::fabs(fval) >= 1.0e-12)
×
338
              {
339
                double rhs_val = 0.0;
×
340
                for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
×
341
                  rhs_val += fe_srf_data.ShapeValue(i, qp) * fe_srf_data.JxW(qp);
×
342
                rhs_val *= (fval / bval);
×
343

344
                cell_rhs(i) += rhs_val;
×
345
              } // if f nonzero
346
            } // for fi
347
          } // Robin BC
348
        } // boundary face
349
      } // for face
400✔
350

351
      auto nn = static_cast<PetscInt>(num_nodes);
100✔
352
      MatSetValues(A_, nn, cell_idxs.data(), nn, cell_idxs.data(), cell_A.data(), ADD_VALUES);
100✔
353
      VecSetValues(rhs_, nn, cell_idxs.data(), cell_rhs.data(), ADD_VALUES);
100✔
354
    } // for g
100✔
355
  } // for cell
300✔
356

357
  MatAssemblyBegin(A_, MAT_FINAL_ASSEMBLY);
1✔
358
  MatAssemblyEnd(A_, MAT_FINAL_ASSEMBLY);
1✔
359
  VecAssemblyBegin(rhs_);
1✔
360
  VecAssemblyEnd(rhs_);
1✔
361

362
  if (options.perform_symmetry_check)
1✔
363
  {
364
    PetscBool symmetry = PETSC_FALSE;
1✔
365
    MatIsSymmetric(A_, 1.0e-6, &symmetry);
1✔
366
    if (symmetry == PETSC_FALSE)
1✔
367
      throw std::logic_error(fname + ":Symmetry check failed");
×
368
  }
369

370
  KSPSetOperators(ksp_, A_, A_);
1✔
371

372
  if (options.verbose)
1✔
373
    log.Log() << program_timer.GetTimeString() << " Assembly completed";
3✔
374

375
  PC pc = nullptr;
1✔
376
  KSPGetPC(ksp_, &pc);
1✔
377
  PCSetUp(pc);
1✔
378

379
  KSPSetUp(ksp_);
1✔
380
}
1✔
381

382
void
383
DiffusionMIPSolver::Assemble_b_wQpoints(const std::vector<double>& q_vector)
1✔
384
{
385
  const std::string fname = "acceleration::DiffusionMIPSolver::"
1✔
386
                            "AssembleAand_b_wQpoints";
1✔
387
  if (A_ == nullptr or rhs_ == nullptr or ksp_ == nullptr)
1✔
388
    throw std::logic_error(fname + ": Some or all PETSc elements are null. "
×
389
                                   "Check that Initialize has been called.");
×
390
  if (options.verbose)
1✔
391
    log.Log() << program_timer.GetTimeString() << " Starting assembly";
3✔
392

393
  VecSet(rhs_, 0.0);
1✔
394

395
  for (const auto& cell : grid_->local_cells)
101✔
396
  {
397
    const size_t num_faces = cell.faces.size();
100✔
398
    const auto& cell_mapping = sdm_.GetCellMapping(cell);
100✔
399
    const auto num_nodes = cell_mapping.GetNumNodes();
100✔
400
    const auto fe_vol_data = cell_mapping.MakeVolumetricFiniteElementData();
100✔
401
    const size_t num_groups = uk_man_.unknowns.front().num_components;
100✔
402

403
    const auto& xs = mat_id_2_xs_map_.at(cell.block_id);
100✔
404

405
    Vector<double> cell_rhs(num_nodes);
100✔
406
    Vector<PetscInt> cell_idxs(num_nodes);
100✔
407
    // For component/group
408
    for (size_t g = 0; g < num_groups; ++g)
200✔
409
    {
410
      cell_rhs.Set(0.);
100✔
411
      for (size_t i = 0; i < num_nodes; ++i)
500✔
412
        cell_idxs(i) = static_cast<PetscInt>(sdm_.MapDOF(cell, i, uk_man_, 0, g));
400✔
413

414
      // Get coefficient and nodal src
415
      const double Dg = xs.Dg[g];
100✔
416

417
      std::vector<double> qg(num_nodes, 0.0);
100✔
418
      for (size_t j = 0; j < num_nodes; ++j)
500✔
419
        qg[j] = q_vector[sdm_.MapDOFLocal(cell, j, uk_man_, 0, g)];
400✔
420

421
      // Assemble continuous terms
422
      for (size_t i = 0; i < num_nodes; ++i)
500✔
423
      {
424
        double entry_rhs_i = 0.0; // entry may accumulate over j
400✔
425
        if (not source_function_)
400✔
426
          for (size_t j = 0; j < num_nodes; ++j)
×
427
          {
428
            for (size_t qp : fe_vol_data.GetQuadraturePointIndices())
×
429
            {
430
              entry_rhs_i += fe_vol_data.ShapeValue(i, qp) * fe_vol_data.ShapeValue(j, qp) *
×
431
                             fe_vol_data.JxW(qp) * qg[j];
×
432
            } // for qp
433
          } // for j
434
        else
435
        {
436
          for (size_t qp : fe_vol_data.GetQuadraturePointIndices())
5,200✔
437
            entry_rhs_i += source_function_(fe_vol_data.QPointXYZ(qp)) *
4,800✔
438
                           fe_vol_data.ShapeValue(i, qp) * fe_vol_data.JxW(qp);
4,800✔
439
        }
440

441
        cell_rhs(i) += entry_rhs_i;
400✔
442
      } // for i
443

444
      // Assemble face terms
445
      for (size_t f = 0; f < num_faces; ++f)
500✔
446
      {
447
        const auto& face = cell.faces[f];
400✔
448
        const auto& n_f = face.normal;
400✔
449
        const size_t num_face_nodes = cell_mapping.GetNumFaceNodes(f);
400✔
450
        const auto fe_srf_data = cell_mapping.MakeSurfaceFiniteElementData(f);
400✔
451

452
        const double hm = HPerpendicular(cell, f);
400✔
453

454
        if (not face.has_neighbor and not suppress_bcs_)
400✔
455
        {
456
          BoundaryCondition bc;
40✔
457
          if (bcs_.count(face.neighbor_id) > 0)
40✔
458
            bc = bcs_.at(face.neighbor_id);
40✔
459

460
          if (bc.type == BCType::DIRICHLET)
40✔
461
          {
462
            const double bc_value = bc.values[0];
40✔
463

464
            // Compute kappa
465
            double kappa = 1.0;
40✔
466
            if (cell.GetType() == CellType::SLAB)
40✔
467
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
×
468
            if (cell.GetType() == CellType::POLYGON)
40✔
469
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
40✔
470
            if (cell.GetType() == CellType::POLYHEDRON)
40✔
471
              kappa = fmax(options.penalty_factor * 2.0 * Dg / hm, 0.25);
×
472

473
            // Assembly penalty terms
474
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
120✔
475
            {
476
              const int i = cell_mapping.MapFaceNode(f, fi);
80✔
477

478
              for (size_t fj = 0; fj < num_face_nodes; ++fj)
240✔
479
              {
480
                const int jm = cell_mapping.MapFaceNode(f, fj);
160✔
481

482
                double aij = 0.0;
160✔
483
                for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
480✔
484
                  aij += kappa * fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeValue(jm, qp) *
640✔
485
                         fe_srf_data.JxW(qp);
320✔
486
                double aij_bc_value = aij * bc_value;
160✔
487

488
                if (ref_solution_function_)
160✔
489
                {
490
                  aij_bc_value = 0.0;
160✔
491
                  for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
480✔
492
                    aij_bc_value += kappa * source_function_(fe_srf_data.QPointXYZ(qp)) *
320✔
493
                                    fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeValue(jm, qp) *
640✔
494
                                    fe_srf_data.JxW(qp);
320✔
495
                }
496

497
                cell_rhs(i) += aij_bc_value;
160✔
498
              } // for fj
499
            } // for fi
500

501
            // Assemble gradient terms
502
            // For the following comments we use the notation:
503
            // Dk = 0.5* n dot nabla bk
504

505
            // 0.5*D* n dot (b_j^+ - b_j^-)*nabla b_i^-
506
            for (size_t i = 0; i < num_nodes; ++i)
200✔
507
            {
508
              for (size_t j = 0; j < num_nodes; ++j)
800✔
509
              {
510
                Vector3 vec_aij;
640✔
511
                for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
1,920✔
512
                  vec_aij += fe_srf_data.ShapeValue(j, qp) * fe_srf_data.ShapeGrad(i, qp) *
1,280✔
513
                               fe_srf_data.JxW(qp) +
2,560✔
514
                             fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeGrad(j, qp) *
2,560✔
515
                               fe_srf_data.JxW(qp);
3,840✔
516
                const double aij = -Dg * n_f.Dot(vec_aij);
640✔
517

518
                double aij_bc_value = aij * bc_value;
640✔
519

520
                if (ref_solution_function_)
640✔
521
                {
522
                  Vector3 vec_aij_mms;
640✔
523
                  for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
1,920✔
524
                    vec_aij_mms += ref_solution_function_(fe_srf_data.QPointXYZ(qp)) *
3,840✔
525
                                   (fe_srf_data.ShapeValue(j, qp) * fe_srf_data.ShapeGrad(i, qp) *
1,280✔
526
                                      fe_srf_data.JxW(qp) +
3,840✔
527
                                    fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeGrad(j, qp) *
1,280✔
528
                                      fe_srf_data.JxW(qp));
3,840✔
529
                  aij_bc_value = -Dg * n_f.Dot(vec_aij_mms);
640✔
530
                }
531

532
                cell_rhs(i) += aij_bc_value;
640✔
533
              } // for fj
534
            } // for i
535
          } // Dirichlet BC
536
          else if (bc.type == BCType::ROBIN)
×
537
          {
538
            const double bval = bc.values[1];
×
539
            const double fval = bc.values[2];
×
540

541
            if (std::fabs(bval) < 1.0e-12)
×
542
              continue; // a and f assumed zero
×
543

544
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
×
545
            {
546
              const int i = cell_mapping.MapFaceNode(f, fi);
×
547

548
              if (std::fabs(fval) >= 1.0e-12)
×
549
              {
550
                double rhs_val = 0.0;
×
551
                for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
×
552
                  rhs_val += fe_srf_data.ShapeValue(i, qp) * fe_srf_data.JxW(qp);
×
553
                rhs_val *= (fval / bval);
×
554

555
                cell_rhs(i) += rhs_val;
×
556
              } // if f nonzero
557
            } // for fi
558
          } // Robin BC
559
        } // boundary face
560
      } // for face
400✔
561
      auto nn = static_cast<PetscInt>(num_nodes);
100✔
562
      VecSetValues(rhs_, nn, cell_idxs.data(), cell_rhs.data(), ADD_VALUES);
100✔
563
    } // for g
100✔
564
  } // for cell
200✔
565

566
  VecAssemblyBegin(rhs_);
1✔
567
  VecAssemblyEnd(rhs_);
1✔
568

569
  KSPSetOperators(ksp_, A_, A_);
1✔
570

571
  if (options.verbose)
1✔
572
    log.Log() << program_timer.GetTimeString() << " Assembly completed";
3✔
573

574
  PC pc = nullptr;
1✔
575
  KSPGetPC(ksp_, &pc);
1✔
576
  PCSetUp(pc);
1✔
577

578
  KSPSetUp(ksp_);
1✔
579
}
1✔
580

581
void
582
DiffusionMIPSolver::AssembleAand_b(const std::vector<double>& q_vector)
67✔
583
{
584
  const std::string fname = "acceleration::DiffusionMIPSolver::"
67✔
585
                            "AssembleAand_b";
67✔
586
  if (A_ == nullptr or rhs_ == nullptr or ksp_ == nullptr)
67✔
587
    throw std::logic_error(fname + ": Some or all PETSc elements are null. "
×
588
                                   "Check that Initialize has been called.");
×
589
  if (options.verbose)
67✔
590
    log.Log() << program_timer.GetTimeString() << " Starting assembly";
12✔
591

592
  const size_t num_groups = uk_man_.unknowns.front().num_components;
67✔
593

594
  VecSet(rhs_, 0.0);
67✔
595
  for (const auto& cell : grid_->local_cells)
18,595✔
596
  {
597
    const size_t num_faces = cell.faces.size();
18,528✔
598
    const auto& cell_mapping = sdm_.GetCellMapping(cell);
18,528✔
599
    const auto num_nodes = cell_mapping.GetNumNodes();
18,528✔
600
    const auto cc_nodes = cell_mapping.GetNodeLocations();
18,528✔
601
    const auto& unit_cell_matrices = unit_cell_matrices_[cell.local_id];
18,528✔
602

603
    const auto& intV_gradshapeI_gradshapeJ = unit_cell_matrices.intV_gradshapeI_gradshapeJ;
18,528✔
604
    const auto& intV_shapeI_shapeJ = unit_cell_matrices.intV_shapeI_shapeJ;
18,528✔
605

606
    const auto& xs = mat_id_2_xs_map_.at(cell.block_id);
18,528✔
607

608
    DenseMatrix<double> cell_A(num_nodes, num_nodes);
18,528✔
609
    Vector<double> cell_rhs(num_nodes);
18,528✔
610
    Vector<PetscInt> cell_idxs(num_nodes);
18,528✔
611
    for (size_t g = 0; g < num_groups; ++g)
620,197✔
612
    {
613
      cell_A.Set(0.);
601,669✔
614
      cell_rhs.Set(0.);
601,669✔
615
      for (size_t i = 0; i < num_nodes; ++i)
3,793,607✔
616
        cell_idxs(i) = static_cast<PetscInt>(sdm_.MapDOF(cell, i, uk_man_, 0, g));
3,191,938✔
617

618
      // Get coefficient and nodal src
619
      const double Dg = xs.Dg[g];
601,669✔
620
      const double sigr_g = xs.sigR[g];
601,669✔
621

622
      std::vector<double> qg(num_nodes, 0.0);
601,669✔
623
      for (size_t j = 0; j < num_nodes; ++j)
3,793,607✔
624
        qg[j] = q_vector[sdm_.MapDOFLocal(cell, j, uk_man_, 0, g)];
3,191,938✔
625

626
      // Assemble continuous terms
627
      for (size_t i = 0; i < num_nodes; ++i)
3,793,607✔
628
      {
629
        double entry_rhs_i = 0.0;
630
        for (size_t j = 0; j < num_nodes; ++j)
24,271,814✔
631
        {
632
          const double entry_aij =
21,079,876✔
633
            Dg * intV_gradshapeI_gradshapeJ(i, j) + sigr_g * intV_shapeI_shapeJ(i, j);
21,079,876✔
634

635
          entry_rhs_i += intV_shapeI_shapeJ(i, j) * qg[j];
21,079,876✔
636

637
          cell_A(i, j) += entry_aij;
21,079,876✔
638
        } // for j
639

640
        cell_rhs(i) += entry_rhs_i;
3,191,938✔
641
      } // for i
642

643
      // Assemble face terms
644
      for (size_t f = 0; f < num_faces; ++f)
3,231,807✔
645
      {
646
        const auto& face = cell.faces[f];
2,630,138✔
647
        const auto& n_f = face.normal;
2,630,138✔
648
        const auto num_face_nodes = cell_mapping.GetNumFaceNodes(f);
2,630,138✔
649

650
        const auto& intS_shapeI_shapeJ = unit_cell_matrices.intS_shapeI_shapeJ[f];
2,630,138✔
651
        const auto& intS_shapeI_gradshapeJ = unit_cell_matrices.intS_shapeI_gradshapeJ[f];
2,630,138✔
652
        const auto& intS_shapeI = unit_cell_matrices.intS_shapeI[f];
2,630,138✔
653

654
        const double hm = HPerpendicular(cell, f);
2,630,138✔
655

656
        if (face.has_neighbor)
2,630,138✔
657
        {
658
          const auto& adj_cell = grid_->cells[face.neighbor_id];
2,399,302✔
659
          const auto& adj_cell_mapping = sdm_.GetCellMapping(adj_cell);
2,399,302✔
660
          const auto ac_nodes = adj_cell_mapping.GetNodeLocations();
2,399,302✔
661
          const size_t acf = MeshContinuum::MapCellFace(cell, adj_cell, f);
2,399,302✔
662
          const double hp = HPerpendicular(adj_cell, acf);
2,399,302✔
663

664
          const auto& adj_xs = mat_id_2_xs_map_.at(adj_cell.block_id);
2,399,302✔
665
          const double adj_Dg = adj_xs.Dg[g];
2,399,302✔
666

667
          // Compute kappa
668
          double kappa = 1.0;
2,399,302✔
669
          if (cell.GetType() == CellType::SLAB)
2,399,302✔
670
            kappa = fmax(options.penalty_factor * (adj_Dg / hp + Dg / hm) * 0.5, 0.25);
337,662✔
671
          if (cell.GetType() == CellType::POLYGON)
2,399,302✔
672
            kappa = fmax(options.penalty_factor * (adj_Dg / hp + Dg / hm) * 0.5, 0.25);
578,120✔
673
          if (cell.GetType() == CellType::POLYHEDRON)
2,399,302✔
674
            kappa = fmax(options.penalty_factor * 2.0 * (adj_Dg / hp + Dg / hm) * 0.5, 0.25);
1,483,520✔
675

676
          DenseMatrix<double> adj_A(num_nodes, num_face_nodes, 0.);
2,399,302✔
677
          DenseMatrix<double> adj_AT(num_face_nodes, num_nodes, 0.);
2,399,302✔
678
          Vector<PetscInt> adj_idxs(num_face_nodes);
2,399,302✔
679
          for (size_t fj = 0; fj < num_face_nodes; ++fj)
9,827,284✔
680
          {
681
            const auto jp =
7,427,982✔
682
              MapFaceNodeDisc(cell, adj_cell, cc_nodes, ac_nodes, f, acf, fj); // j-plus
7,427,982✔
683
            adj_idxs(fj) = static_cast<PetscInt>(sdm_.MapDOF(adj_cell, jp, uk_man_, 0, g));
7,427,982✔
684
          }
685

686
          // Assembly penalty terms
687
          for (size_t fi = 0; fi < num_face_nodes; ++fi)
9,827,284✔
688
          {
689
            const int i = cell_mapping.MapFaceNode(f, fi);
7,427,982✔
690

691
            for (size_t fj = 0; fj < num_face_nodes; ++fj)
33,814,444✔
692
            {
693
              const int jm = cell_mapping.MapFaceNode(f, fj); // j-minus
26,386,462✔
694

695
              const double aij = kappa * intS_shapeI_shapeJ(i, jm);
26,386,462✔
696

697
              cell_A(i, jm) += aij;
26,386,462✔
698
              adj_A(i, fj) -= aij;
26,386,462✔
699
            } // for fj
700
          } // for fi
701

702
          // Assemble gradient terms
703
          // For the following comments we use the notation:
704
          // Dk = 0.5* n dot nabla bk
705

706
          // 0.5*D* n dot (b_j^+ - b_j^-)*nabla b_i^-
707
          for (size_t i = 0; i < num_nodes; ++i)
17,255,266✔
708
          {
709
            for (size_t fj = 0; fj < num_face_nodes; ++fj)
67,628,888✔
710
            {
711
              const int jm = cell_mapping.MapFaceNode(f, fj); // j-minus
52,772,924✔
712

713
              const double aij = -0.5 * Dg * n_f.Dot(intS_shapeI_gradshapeJ(jm, i));
52,772,924✔
714

715
              cell_A(i, jm) += aij;
52,772,924✔
716
              adj_A(i, fj) -= aij;
52,772,924✔
717
            } // for fj
718
          } // for i
719

720
          // 0.5*D* n dot (b_i^+ - b_i^-)*nabla b_j^-
721
          for (size_t fi = 0; fi < num_face_nodes; ++fi)
9,827,284✔
722
          {
723
            const int im = cell_mapping.MapFaceNode(f, fi); // i-minus
7,427,982✔
724

725
            for (size_t j = 0; j < num_nodes; ++j)
60,200,906✔
726
            {
727
              const double aij = -0.5 * Dg * n_f.Dot(intS_shapeI_gradshapeJ(im, j));
52,772,924✔
728

729
              cell_A(im, j) += aij;
52,772,924✔
730
              adj_AT(fi, j) -= aij;
52,772,924✔
731
            } // for j
732
          } // for fi
733

734
          auto nn = static_cast<PetscInt>(num_nodes);
2,399,302✔
735
          auto nf = static_cast<PetscInt>(num_face_nodes);
2,399,302✔
736
          MatSetValues(A_, nn, cell_idxs.data(), nf, adj_idxs.data(), adj_A.data(), ADD_VALUES);
2,399,302✔
737

738
          MatSetValues(A_, nf, adj_idxs.data(), nn, cell_idxs.data(), adj_AT.data(), ADD_VALUES);
2,399,302✔
739

740
        } // internal face
7,197,906✔
741
        else
742
        {
743
          BoundaryCondition bc;
230,836✔
744
          if (bcs_.count(face.neighbor_id) > 0)
230,836✔
745
            bc = bcs_.at(face.neighbor_id);
230,836✔
746

747
          if (bc.type == BCType::DIRICHLET)
230,836✔
748
          {
749
            const double bc_value = bc.values[0];
210,956✔
750

751
            // Compute kappa
752
            double kappa = 1.0;
210,956✔
753
            if (cell.GetType() == CellType::SLAB)
210,956✔
754
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
676✔
755
            if (cell.GetType() == CellType::POLYGON)
210,956✔
756
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
21,000✔
757
            if (cell.GetType() == CellType::POLYHEDRON)
210,956✔
758
              kappa = fmax(options.penalty_factor * 2.0 * Dg / hm, 0.25);
189,280✔
759

760
            // Assembly penalty terms
761
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
1,010,752✔
762
            {
763
              const int i = cell_mapping.MapFaceNode(f, fi);
799,796✔
764

765
              for (size_t fj = 0; fj < num_face_nodes; ++fj)
3,912,952✔
766
              {
767
                const int jm = cell_mapping.MapFaceNode(f, fj);
3,113,156✔
768

769
                const double aij = kappa * intS_shapeI_shapeJ(i, jm);
3,113,156✔
770
                const double aij_bc_value = aij * bc_value;
3,113,156✔
771

772
                cell_A(i, jm) += aij;
3,113,156✔
773
                cell_rhs(i) += aij_bc_value;
3,113,156✔
774
              } // for fj
775
            } // for fi
776

777
            // Assemble gradient terms
778
            // For the following comments we use the notation:
779
            // Dk = n dot nabla bk
780

781
            // D* n dot (b_j^+ - b_j^-)*nabla b_i^-
782
            for (size_t i = 0; i < num_nodes; ++i)
1,810,548✔
783
            {
784
              for (size_t j = 0; j < num_nodes; ++j)
14,052,216✔
785
              {
786
                const double aij =
12,452,624✔
787
                  -Dg * n_f.Dot(intS_shapeI_gradshapeJ(j, i) + intS_shapeI_gradshapeJ(i, j));
12,452,624✔
788
                const double aij_bc_value = aij * bc_value;
12,452,624✔
789

790
                cell_A(i, j) += aij;
12,452,624✔
791
                cell_rhs(i) += aij_bc_value;
12,452,624✔
792
              } // for fj
793
            } // for i
794
          } // Dirichlet BC
795
          else if (bc.type == BCType::ROBIN)
19,880✔
796
          {
797
            const double aval = bc.values[0];
19,880✔
798
            const double bval = bc.values[1];
19,880✔
799
            const double fval = bc.values[2];
19,880✔
800

801
            if (std::fabs(bval) < 1.0e-12)
19,880✔
802
              continue; // a and f assumed zero
×
803

804
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
84,840✔
805
            {
806
              const int i = cell_mapping.MapFaceNode(f, fi);
64,960✔
807

808
              if (std::fabs(aval) >= 1.0e-12)
64,960✔
809
              {
810
                for (size_t fj = 0; fj < num_face_nodes; ++fj)
×
811
                {
812
                  const int j = cell_mapping.MapFaceNode(f, fj);
×
813

814
                  const double aij = (aval / bval) * intS_shapeI_shapeJ(i, j);
×
815

816
                  cell_A(i, j) += aij;
×
817
                } // for fj
818
              } // if a nonzero
819

820
              if (std::fabs(fval) >= 1.0e-12)
64,960✔
821
              {
822
                const double rhs_val = (fval / bval) * intS_shapeI(i);
×
823

824
                cell_rhs(i) += rhs_val;
×
825
              } // if f nonzero
826
            } // for fi
827
          } // Robin BC
828
        } // boundary face
829
      } // for face
830

831
      auto nn = static_cast<PetscInt>(num_nodes);
601,669✔
832
      MatSetValues(A_, nn, cell_idxs.data(), nn, cell_idxs.data(), cell_A.data(), ADD_VALUES);
601,669✔
833
      VecSetValues(rhs_, nn, cell_idxs.data(), cell_rhs.data(), ADD_VALUES);
601,669✔
834
    } // for g
601,669✔
835
  } // for cell
55,584✔
836

837
  MatAssemblyBegin(A_, MAT_FINAL_ASSEMBLY);
67✔
838
  MatAssemblyEnd(A_, MAT_FINAL_ASSEMBLY);
67✔
839
  VecAssemblyBegin(rhs_);
67✔
840
  VecAssemblyEnd(rhs_);
67✔
841

842
  if (options.verbose)
67✔
843
  {
844
    MatInfo info;
4✔
845
    MatGetInfo(A_, MAT_GLOBAL_SUM, &info);
4✔
846

847
    log.Log() << "Number of mallocs used = " << info.mallocs
12✔
848
              << "\nNumber of non-zeros allocated = " << info.nz_allocated
4✔
849
              << "\nNumber of non-zeros used = " << info.nz_used
4✔
850
              << "\nNumber of unneeded non-zeros = " << info.nz_unneeded;
8✔
851
  }
852

853
  if (options.perform_symmetry_check)
67✔
854
  {
855
    PetscBool symmetry = PETSC_FALSE;
×
856
    MatIsSymmetric(A_, 1.0e-6, &symmetry);
×
857
    if (symmetry == PETSC_FALSE)
×
858
      throw std::logic_error(fname + ":Symmetry check failed");
×
859
  }
860

861
  KSPSetOperators(ksp_, A_, A_);
67✔
862

863
  if (options.verbose)
67✔
864
    log.Log() << program_timer.GetTimeString() << " Assembly completed";
12✔
865

866
  PC pc = nullptr;
67✔
867
  KSPGetPC(ksp_, &pc);
67✔
868
  PCSetUp(pc);
67✔
869

870
  KSPSetUp(ksp_);
67✔
871
}
67✔
872

873
void
874
DiffusionMIPSolver::Assemble_b(const std::vector<double>& q_vector)
9,094✔
875
{
876
  const std::string fname = "acceleration::DiffusionMIPSolver::"
9,094✔
877
                            "Assemble_b";
9,094✔
878
  if (A_ == nullptr or rhs_ == nullptr or ksp_ == nullptr)
9,094✔
879
    throw std::logic_error(fname + ": Some or all PETSc elements are null. "
×
880
                                   "Check that Initialize has been called.");
×
881
  if (options.verbose)
9,094✔
882
    log.Log() << program_timer.GetTimeString() << " Starting assembly";
384✔
883

884
  const size_t num_groups = uk_man_.unknowns.front().num_components;
9,094✔
885

886
  VecSet(rhs_, 0.0);
9,094✔
887
  for (const auto& cell : grid_->local_cells)
1,603,168✔
888
  {
889
    const size_t num_faces = cell.faces.size();
1,594,074✔
890
    const auto& cell_mapping = sdm_.GetCellMapping(cell);
1,594,074✔
891
    const auto num_nodes = cell_mapping.GetNumNodes();
1,594,074✔
892
    const auto cc_nodes = cell_mapping.GetNodeLocations();
1,594,074✔
893
    const auto& unit_cell_matrices = unit_cell_matrices_[cell.local_id];
1,594,074✔
894

895
    const auto& intV_shapeI_shapeJ = unit_cell_matrices.intV_shapeI_shapeJ;
1,594,074✔
896

897
    const auto& xs = mat_id_2_xs_map_.at(cell.block_id);
1,594,074✔
898

899
    Vector<double> cell_rhs(num_nodes);
1,594,074✔
900
    Vector<PetscInt> cell_idxs(num_nodes);
1,594,074✔
901
    for (size_t g = 0; g < num_groups; ++g)
35,901,216✔
902
    {
903
      cell_rhs.Set(0.);
34,307,142✔
904
      for (size_t i = 0; i < num_nodes; ++i)
228,894,226✔
905
        cell_idxs(i) = static_cast<PetscInt>(sdm_.MapDOF(cell, i, uk_man_, 0, g));
194,587,084✔
906

907
      // Get coefficient and nodal src
908
      const double Dg = xs.Dg[g];
34,307,142✔
909

910
      std::vector<double> qg(num_nodes, 0.0);
34,307,142✔
911
      for (size_t j = 0; j < num_nodes; ++j)
228,894,226✔
912
        qg[j] = q_vector[sdm_.MapDOFLocal(cell, j, uk_man_, 0, g)];
194,587,084✔
913

914
      // Assemble continuous terms
915
      for (size_t i = 0; i < num_nodes; ++i)
228,894,226✔
916
      {
917
        double entry_rhs_i = 0.0;
918
        for (size_t j = 0; j < num_nodes; ++j)
1,510,398,052✔
919
          entry_rhs_i += intV_shapeI_shapeJ(i, j) * qg[j];
1,315,810,968✔
920

921
        cell_rhs(i) += entry_rhs_i;
194,587,084✔
922
      } // for i
923

924
      // Assemble face terms
925
      for (size_t f = 0; f < num_faces; ++f)
193,665,426✔
926
      {
927
        const auto& face = cell.faces[f];
159,358,284✔
928
        const auto& n_f = face.normal;
159,358,284✔
929
        const size_t num_face_nodes = cell_mapping.GetNumFaceNodes(f);
159,358,284✔
930

931
        const auto& intS_shapeI_shapeJ = unit_cell_matrices.intS_shapeI_shapeJ[f];
159,358,284✔
932
        const auto& intS_shapeI_gradshapeJ = unit_cell_matrices.intS_shapeI_gradshapeJ[f];
159,358,284✔
933
        const auto& intS_shapeI = unit_cell_matrices.intS_shapeI[f];
159,358,284✔
934

935
        const double hm = HPerpendicular(cell, f);
159,358,284✔
936

937
        if (not face.has_neighbor and not suppress_bcs_)
159,358,284✔
938
        {
939
          BoundaryCondition bc;
14,744,688✔
940
          if (bcs_.count(face.neighbor_id) > 0)
14,744,688✔
941
            bc = bcs_.at(face.neighbor_id);
14,744,688✔
942

943
          if (bc.type == BCType::DIRICHLET)
14,744,688✔
944
          {
945
            const double bc_value = bc.values[0];
13,841,808✔
946

947
            // Compute kappa
948
            double kappa = 1.0;
13,841,808✔
949
            if (cell.GetType() == CellType::SLAB)
13,841,808✔
950
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
427,768✔
951
            if (cell.GetType() == CellType::POLYGON)
13,841,808✔
952
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
1,319,160✔
953
            if (cell.GetType() == CellType::POLYHEDRON)
13,841,808✔
954
              kappa = fmax(options.penalty_factor * 2.0 * Dg / hm, 0.25);
12,094,880✔
955

956
            // Assembly penalty terms
957
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
65,287,416✔
958
            {
959
              const int i = cell_mapping.MapFaceNode(f, fi);
51,445,608✔
960

961
              for (size_t fj = 0; fj < num_face_nodes; ++fj)
250,668,096✔
962
              {
963
                const int jm = cell_mapping.MapFaceNode(f, fj);
199,222,488✔
964

965
                const double aij = kappa * intS_shapeI_shapeJ(i, jm);
199,222,488✔
966
                const double aij_bc_value = aij * bc_value;
199,222,488✔
967

968
                cell_rhs(i) += aij_bc_value;
199,222,488✔
969
              } // for fj
970
            } // for fi
971

972
            // Assemble gradient terms
973
            // For the following comments we use the notation:
974
            // Dk = n dot nabla bk
975

976
            // D* n dot (b_j^+ - b_j^-)*nabla b_i^-
977
            for (size_t i = 0; i < num_nodes; ++i)
116,733,024✔
978
            {
979
              for (size_t j = 0; j < num_nodes; ++j)
899,781,168✔
980
              {
981
                const double aij =
796,889,952✔
982
                  -Dg * n_f.Dot(intS_shapeI_gradshapeJ(j, i) + intS_shapeI_gradshapeJ(i, j));
796,889,952✔
983
                const double aij_bc_value = aij * bc_value;
796,889,952✔
984

985
                cell_rhs(i) += aij_bc_value;
796,889,952✔
986
              } // for fj
987
            } // for i
988
          } // Dirichlet BC
989
          else if (bc.type == BCType::ROBIN)
902,880✔
990
          {
991
            const double bval = bc.values[1];
902,880✔
992
            const double fval = bc.values[2];
902,880✔
993

994
            if (std::fabs(bval) < 1.0e-12)
902,880✔
995
              continue; // a and f assumed zero
×
996

997
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
3,515,040✔
998
            {
999
              const int i = cell_mapping.MapFaceNode(f, fi);
2,612,160✔
1000

1001
              if (std::fabs(fval) >= 1.0e-12)
2,612,160✔
1002
              {
1003
                const double rhs_val = (fval / bval) * intS_shapeI(i);
×
1004

1005
                cell_rhs(i) += rhs_val;
×
1006
              } // if f nonzero
1007
            } // for fi
1008
          } // Robin BC
1009
        } // boundary face
1010
      } // for face
1011

1012
      auto nn = static_cast<PetscInt>(num_nodes);
34,307,142✔
1013
      VecSetValues(rhs_, nn, cell_idxs.data(), cell_rhs.data(), ADD_VALUES);
34,307,142✔
1014
    } // for g
34,307,142✔
1015
  } // for cell
3,188,148✔
1016

1017
  VecAssemblyBegin(rhs_);
9,094✔
1018
  VecAssemblyEnd(rhs_);
9,094✔
1019

1020
  if (options.verbose)
9,094✔
1021
    log.Log() << program_timer.GetTimeString() << " Assembly completed";
384✔
1022
}
9,094✔
1023

1024
void
1025
DiffusionMIPSolver::Assemble_b(Vec petsc_q_vector)
×
1026
{
1027
  const std::string fname = "acceleration::DiffusionMIPSolver::"
×
1028
                            "Assemble_b";
×
1029
  if (A_ == nullptr or rhs_ == nullptr or ksp_ == nullptr)
×
1030
    throw std::logic_error(fname + ": Some or all PETSc elements are null. "
×
1031
                                   "Check that Initialize has been called.");
×
1032
  if (options.verbose)
×
1033
    log.Log() << program_timer.GetTimeString() << " Starting assembly";
×
1034

1035
  const size_t num_groups = uk_man_.unknowns.front().num_components;
×
1036

NEW
1037
  const double* q_vector = nullptr;
×
1038
  VecGetArrayRead(petsc_q_vector, &q_vector);
×
1039

1040
  VecSet(rhs_, 0.0);
×
1041
  for (const auto& cell : grid_->local_cells)
×
1042
  {
1043
    const size_t num_faces = cell.faces.size();
×
1044
    const auto& cell_mapping = sdm_.GetCellMapping(cell);
×
1045
    const auto num_nodes = cell_mapping.GetNumNodes();
×
1046
    const auto cc_nodes = cell_mapping.GetNodeLocations();
×
1047
    const auto& unit_cell_matrices = unit_cell_matrices_[cell.local_id];
×
1048

1049
    const auto& intV_shapeI_shapeJ = unit_cell_matrices.intV_shapeI_shapeJ;
×
1050

1051
    const auto& xs = mat_id_2_xs_map_.at(cell.block_id);
×
1052

1053
    Vector<double> cell_rhs(num_nodes);
×
1054
    Vector<PetscInt> cell_idxs(num_nodes);
×
1055
    for (size_t g = 0; g < num_groups; ++g)
×
1056
    {
1057
      cell_rhs.Set(0.);
×
1058
      for (size_t i = 0; i < num_nodes; ++i)
×
1059
        cell_idxs(i) = static_cast<PetscInt>(sdm_.MapDOF(cell, i, uk_man_, 0, g));
×
1060

1061
      // Get coefficient and nodal src
1062
      const double Dg = xs.Dg[g];
×
1063

1064
      std::vector<double> qg(num_nodes, 0.0);
×
1065
      for (size_t j = 0; j < num_nodes; ++j)
×
1066
        qg[j] = q_vector[sdm_.MapDOFLocal(cell, j, uk_man_, 0, g)];
×
1067

1068
      // Assemble continuous terms
1069
      for (size_t i = 0; i < num_nodes; ++i)
×
1070
      {
1071
        double entry_rhs_i = 0.0;
1072
        for (size_t j = 0; j < num_nodes; ++j)
×
1073
          entry_rhs_i += intV_shapeI_shapeJ(i, j) * qg[j];
×
1074

1075
        cell_rhs(i) += entry_rhs_i;
×
1076
      } // for i
1077

1078
      // Assemble face terms
1079
      for (size_t f = 0; f < num_faces; ++f)
×
1080
      {
1081
        const auto& face = cell.faces[f];
×
1082
        const auto& n_f = face.normal;
×
1083
        const size_t num_face_nodes = cell_mapping.GetNumFaceNodes(f);
×
1084

1085
        const auto& intS_shapeI_shapeJ = unit_cell_matrices.intS_shapeI_shapeJ[f];
×
1086
        const auto& intS_shapeI_gradshapeJ = unit_cell_matrices.intS_shapeI_gradshapeJ[f];
×
1087
        const auto& intS_shapeI = unit_cell_matrices.intS_shapeI[f];
×
1088

1089
        const double hm = HPerpendicular(cell, f);
×
1090

1091
        if (not face.has_neighbor and not suppress_bcs_)
×
1092
        {
1093
          BoundaryCondition bc;
×
1094
          if (bcs_.count(face.neighbor_id) > 0)
×
1095
            bc = bcs_.at(face.neighbor_id);
×
1096

1097
          if (bc.type == BCType::DIRICHLET)
×
1098
          {
1099
            const double bc_value = bc.values[0];
×
1100

1101
            // Compute kappa
1102
            double kappa = 1.0;
×
1103
            if (cell.GetType() == CellType::SLAB)
×
1104
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
×
1105
            if (cell.GetType() == CellType::POLYGON)
×
1106
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
×
1107
            if (cell.GetType() == CellType::POLYHEDRON)
×
1108
              kappa = fmax(options.penalty_factor * 2.0 * Dg / hm, 0.25);
×
1109

1110
            // Assembly penalty terms
1111
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
×
1112
            {
1113
              const int i = cell_mapping.MapFaceNode(f, fi);
×
1114

1115
              for (size_t fj = 0; fj < num_face_nodes; ++fj)
×
1116
              {
1117
                const int jm = cell_mapping.MapFaceNode(f, fj);
×
1118

1119
                const double aij = kappa * intS_shapeI_shapeJ(i, jm);
×
1120
                const double aij_bc_value = aij * bc_value;
×
1121

1122
                cell_rhs(i) += aij_bc_value;
×
1123
              } // for fj
1124
            } // for fi
1125

1126
            // Assemble gradient terms
1127
            // For the following comments we use the notation:
1128
            // Dk = n dot nabla bk
1129

1130
            // D* n dot (b_j^+ - b_j^-)*nabla b_i^-
1131
            for (size_t i = 0; i < num_nodes; ++i)
×
1132
            {
1133
              for (size_t j = 0; j < num_nodes; ++j)
×
1134
              {
1135
                const double aij =
×
1136
                  -Dg * n_f.Dot(intS_shapeI_gradshapeJ(j, i) + intS_shapeI_gradshapeJ(i, j));
×
1137
                const double aij_bc_value = aij * bc_value;
×
1138

1139
                cell_rhs(i) += aij_bc_value;
×
1140
              } // for fj
1141
            } // for i
1142
          } // Dirichlet BC
1143
          else if (bc.type == BCType::ROBIN)
×
1144
          {
1145
            const double bval = bc.values[1];
×
1146
            const double fval = bc.values[2];
×
1147

1148
            if (std::fabs(bval) < 1.0e-12)
×
1149
              continue; // a and f assumed zero
×
1150

1151
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
×
1152
            {
1153
              const int i = cell_mapping.MapFaceNode(f, fi);
×
1154

1155
              if (std::fabs(fval) >= 1.0e-12)
×
1156
              {
1157
                const double rhs_val = (fval / bval) * intS_shapeI(i);
×
1158

1159
                cell_rhs(i) += rhs_val;
×
1160
              } // if f nonzero
1161
            } // for fi
1162
          } // Robin BC
1163
        } // boundary face
1164
      } // for face
1165
      auto nn = static_cast<PetscInt>(num_nodes);
×
1166
      VecSetValues(rhs_, nn, cell_idxs.data(), cell_rhs.data(), ADD_VALUES);
×
1167
    } // for g
×
1168
  } // for cell
×
1169

1170
  VecRestoreArrayRead(petsc_q_vector, &q_vector);
×
1171

1172
  VecAssemblyBegin(rhs_);
×
1173
  VecAssemblyEnd(rhs_);
×
1174

1175
  if (options.verbose)
×
1176
    log.Log() << program_timer.GetTimeString() << " Assembly completed";
×
1177
}
×
1178

1179
double
1180
DiffusionMIPSolver::HPerpendicular(const Cell& cell, unsigned int f)
164,388,884✔
1181
{
1182
  const auto& cell_mapping = sdm_.GetCellMapping(cell);
164,388,884✔
1183
  double hp = 0.0;
164,388,884✔
1184

1185
  const auto num_faces = cell.faces.size();
164,388,884✔
1186
  const auto num_vertices = cell.vertex_ids.size();
164,388,884✔
1187

1188
  const auto volume = cell.volume;
164,388,884✔
1189
  const auto face_area = cell.faces.at(f).area;
164,388,884✔
1190

1191
  /**Lambda to compute surface area.*/
1192
  auto ComputeSurfaceArea = [&cell, &num_faces]()
273,244,204✔
1193
  {
1194
    double surface_area = 0.0;
108,855,320✔
1195
    for (size_t fr = 0; fr < num_faces; ++fr)
761,987,240✔
1196
      surface_area += cell.faces[fr].area;
653,131,920✔
1197

1198
    return surface_area;
108,855,320✔
1199
  };
164,388,884✔
1200

1201
  if (cell.GetType() == CellType::SLAB)
164,388,884✔
1202
  {
1203
    hp = volume / 2.0;
13,775,084✔
1204
  }
1205
  else if (cell.GetType() == CellType::POLYGON)
150,613,800✔
1206
  {
1207
    if (num_faces == 3)
41,758,480✔
1208
      hp = 2.0 * volume / face_area;
×
1209
    else if (num_faces == 4)
41,758,480✔
1210
      hp = volume / face_area;
41,758,480✔
1211
    else // Nv > 4
1212
    {
1213
      const auto surface_area = ComputeSurfaceArea();
×
1214

1215
      if (num_faces % 2 == 0)
×
1216
        hp = 4.0 * volume / surface_area;
×
1217
      else
1218
      {
1219
        hp = 2.0 * volume / surface_area;
×
1220
        hp +=
×
1221
          sqrt(2.0 * volume /
×
1222
               (static_cast<double>(num_faces) * sin(2.0 * M_PI / static_cast<double>(num_faces))));
×
1223
      }
1224
    }
1225
  }
1226
  else if (cell.GetType() == CellType::POLYHEDRON)
108,855,320✔
1227
  {
1228
    const auto surface_area = ComputeSurfaceArea();
108,855,320✔
1229

1230
    if (num_faces == 4) // Tet
108,855,320✔
1231
      hp = 3 * volume / surface_area;
×
1232
    else if (num_faces == 6 and num_vertices == 8) // Hex
108,855,320✔
1233
      hp = volume / surface_area;
108,855,320✔
1234
    else // Polyhedron
1235
      hp = 6 * volume / surface_area;
×
1236
  } // Polyhedron
1237
  else
1238
    throw std::logic_error("acceleration::DiffusionMIPSolver::HPerpendicular: "
×
1239
                           "Unsupported cell type in call to HPerpendicular");
×
1240

1241
  return hp;
164,388,884✔
1242
}
1243

1244
int
1245
DiffusionMIPSolver::MapFaceNodeDisc(const Cell& cur_cell,
7,428,702✔
1246
                                    const Cell& adj_cell,
1247
                                    const std::vector<Vector3>& cc_node_locs,
1248
                                    const std::vector<Vector3>& ac_node_locs,
1249
                                    size_t ccf,
1250
                                    size_t acf,
1251
                                    size_t ccfi,
1252
                                    double epsilon)
1253
{
1254
  const auto& cur_cell_mapping = sdm_.GetCellMapping(cur_cell);
7,428,702✔
1255
  const auto& adj_cell_mapping = sdm_.GetCellMapping(adj_cell);
7,428,702✔
1256

1257
  const int i = cur_cell_mapping.MapFaceNode(ccf, ccfi);
7,428,702✔
1258
  const auto& node_i_loc = cc_node_locs[i];
7,428,702✔
1259

1260
  const size_t adj_face_num_nodes = adj_cell_mapping.GetNumFaceNodes(acf);
7,428,702✔
1261

1262
  for (size_t fj = 0; fj < adj_face_num_nodes; ++fj)
16,908,302✔
1263
  {
1264
    const int j = adj_cell_mapping.MapFaceNode(acf, fj);
16,908,302✔
1265
    if ((node_i_loc - ac_node_locs[j]).NormSquare() < epsilon)
16,908,302✔
1266
      return j;
7,428,702✔
1267
  }
1268

1269
  throw std::logic_error("acceleration::DiffusionMIPSolver::MapFaceNodeDisc: Mapping failure.");
×
1270
}
1271

1272
} // 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