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

Open-Sn / opensn / 18300593117

06 Oct 2025 10:47PM UTC coverage: 74.862% (-0.2%) from 75.031%
18300593117

push

github

web-flow
Merge pull request #759 from wdhawkins/performance

Sweep performance optimizations

294 of 302 new or added lines in 15 files covered. (97.35%)

334 existing lines in 80 files now uncovered.

17788 of 23761 relevant lines covered (74.86%)

61852783.95 hits per line

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

75.98
/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),
68✔
29
                    sdm,
30
                    uk_man,
31
                    std::move(bcs),
68✔
32
                    std::move(map_mat_id_2_xs),
68✔
33
                    unit_cell_matrices,
34
                    false,
35
                    suppress_bcs,
36
                    verbose)
204✔
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::"
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";
1✔
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 size_t 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) = sdm_.MapDOF(cell, i, uk_man_, 0, g);
800✔
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
400✔
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 size_t 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 =
154
              MapFaceNodeDisc(cell, adj_cell, cc_nodes, ac_nodes, f, acf, fj); // j-plus
720✔
155
            adj_idxs(fj) = sdm_.MapDOF(adj_cell, jp, uk_man_, 0, g);
1,440✔
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) *
2,880✔
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) *
11,520✔
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) *
11,520✔
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
          MatSetValues(A_,
360✔
218
                       num_nodes,
219
                       cell_idxs.data(),
360✔
220
                       num_face_nodes,
221
                       adj_idxs.data(),
360✔
222
                       adj_A.data(),
360✔
223
                       ADD_VALUES);
224

225
          MatSetValues(A_,
360✔
226
                       num_face_nodes,
227
                       adj_idxs.data(),
360✔
228
                       num_nodes,
229
                       cell_idxs.data(),
360✔
230
                       adj_AT.data(),
360✔
231
                       ADD_VALUES);
232

233
        } // internal face
360✔
234
        else
235
        {
236
          BoundaryCondition bc;
40✔
237
          if (bcs_.count(face.neighbor_id) > 0)
40✔
238
            bc = bcs_.at(face.neighbor_id);
40✔
239

240
          if (bc.type == BCType::DIRICHLET)
40✔
241
          {
242
            const double bc_value = bc.values[0];
40✔
243

244
            // Compute kappa
245
            double kappa = 1.0;
40✔
246
            if (cell.GetType() == CellType::SLAB)
40✔
247
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
×
248
            if (cell.GetType() == CellType::POLYGON)
40✔
249
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
40✔
250
            if (cell.GetType() == CellType::POLYHEDRON)
40✔
251
              kappa = fmax(options.penalty_factor * 2.0 * Dg / hm, 0.25);
×
252

253
            // Assembly penalty terms
254
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
120✔
255
            {
256
              const int i = cell_mapping.MapFaceNode(f, fi);
80✔
257

258
              for (size_t fj = 0; fj < num_face_nodes; ++fj)
240✔
259
              {
260
                const int jm = cell_mapping.MapFaceNode(f, fj);
160✔
261

262
                double aij = 0.0;
160✔
263
                for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
480✔
264
                  aij += kappa * fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeValue(jm, qp) *
320✔
265
                         fe_srf_data.JxW(qp);
320✔
266
                double aij_bc_value = aij * bc_value;
160✔
267

268
                if (ref_solution_function_)
160✔
269
                {
270
                  aij_bc_value = 0.0;
160✔
271
                  for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
480✔
272
                    aij_bc_value += kappa * ref_solution_function_(fe_srf_data.QPointXYZ(qp)) *
320✔
273
                                    fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeValue(jm, qp) *
320✔
274
                                    fe_srf_data.JxW(qp);
320✔
275
                }
276

277
                cell_A(i, jm) += aij;
160✔
278
                cell_rhs(i) += aij_bc_value;
160✔
279
              } // for fj
280
            } // for fi
281

282
            // Assemble gradient terms
283
            // For the following comments we use the notation:
284
            // Dk = n dot nabla bk
285

286
            // D* n dot (b_j^+ - b_j^-)*nabla b_i^-
287
            for (size_t i = 0; i < num_nodes; ++i)
200✔
288
            {
289
              for (size_t j = 0; j < num_nodes; ++j)
800✔
290
              {
291
                Vector3 vec_aij;
640✔
292
                for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
1,920✔
293
                  vec_aij += fe_srf_data.ShapeValue(j, qp) * fe_srf_data.ShapeGrad(i, qp) *
1,280✔
294
                               fe_srf_data.JxW(qp) +
2,560✔
295
                             fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeGrad(j, qp) *
2,560✔
296
                               fe_srf_data.JxW(qp);
3,840✔
297
                const double aij = -Dg * n_f.Dot(vec_aij);
640✔
298

299
                double aij_bc_value = aij * bc_value;
640✔
300

301
                if (ref_solution_function_)
640✔
302
                {
303
                  Vector3 vec_aij_mms;
640✔
304
                  for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
1,920✔
UNCOV
305
                    vec_aij_mms += ref_solution_function_(fe_srf_data.QPointXYZ(qp)) *
×
306
                                   (fe_srf_data.ShapeValue(j, qp) * fe_srf_data.ShapeGrad(i, qp) *
1,280✔
307
                                      fe_srf_data.JxW(qp) +
2,560✔
308
                                    fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeGrad(j, qp) *
2,560✔
309
                                      fe_srf_data.JxW(qp));
3,840✔
310
                  aij_bc_value = -Dg * n_f.Dot(vec_aij_mms);
640✔
311
                }
312

313
                cell_A(i, j) += aij;
640✔
314
                cell_rhs(i) += aij_bc_value;
640✔
315
              } // for fj
316
            } // for i
317
          } // Dirichlet BC
318
          else if (bc.type == BCType::ROBIN)
×
319
          {
320
            const double aval = bc.values[0];
×
321
            const double bval = bc.values[1];
×
322
            const double fval = bc.values[2];
×
323

324
            if (std::fabs(bval) < 1.0e-12)
×
325
              continue; // a and f assumed zero
×
326

327
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
×
328
            {
329
              const int i = cell_mapping.MapFaceNode(f, fi);
×
330

331
              if (std::fabs(aval) >= 1.0e-12)
×
332
              {
333
                for (size_t fj = 0; fj < num_face_nodes; ++fj)
×
334
                {
335
                  const int j = cell_mapping.MapFaceNode(f, fj);
×
336

337
                  double aij = 0.0;
×
338
                  for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
×
339
                    aij += fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeValue(j, qp) *
×
340
                           fe_srf_data.JxW(qp);
×
341
                  aij *= (aval / bval);
×
342

343
                  cell_A(i, j) += aij;
×
344
                } // for fj
345
              } // if a nonzero
346

347
              if (std::fabs(fval) >= 1.0e-12)
×
348
              {
349
                double rhs_val = 0.0;
×
350
                for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
×
351
                  rhs_val += fe_srf_data.ShapeValue(i, qp) * fe_srf_data.JxW(qp);
×
352
                rhs_val *= (fval / bval);
×
353

354
                cell_rhs(i) += rhs_val;
×
355
              } // if f nonzero
356
            } // for fi
357
          } // Robin BC
358
        } // boundary face
359
      } // for face
400✔
360

361
      MatSetValues(
100✔
362
        A_, num_nodes, cell_idxs.data(), num_nodes, cell_idxs.data(), cell_A.data(), ADD_VALUES);
100✔
363
      VecSetValues(rhs_, num_nodes, cell_idxs.data(), cell_rhs.data(), ADD_VALUES);
100✔
364
    } // for g
100✔
365
  } // for cell
100✔
366

367
  MatAssemblyBegin(A_, MAT_FINAL_ASSEMBLY);
1✔
368
  MatAssemblyEnd(A_, MAT_FINAL_ASSEMBLY);
1✔
369
  VecAssemblyBegin(rhs_);
1✔
370
  VecAssemblyEnd(rhs_);
1✔
371

372
  if (options.perform_symmetry_check)
1✔
373
  {
374
    PetscBool symmetry = PETSC_FALSE;
1✔
375
    MatIsSymmetric(A_, 1.0e-6, &symmetry);
1✔
376
    if (symmetry == PETSC_FALSE)
1✔
377
      throw std::logic_error(fname + ":Symmetry check failed");
×
378
  }
379

380
  KSPSetOperators(ksp_, A_, A_);
1✔
381

382
  if (options.verbose)
1✔
383
    log.Log() << program_timer.GetTimeString() << " Assembly completed";
1✔
384

385
  PC pc;
386
  KSPGetPC(ksp_, &pc);
1✔
387
  PCSetUp(pc);
1✔
388

389
  KSPSetUp(ksp_);
1✔
390
}
1✔
391

392
void
393
DiffusionMIPSolver::Assemble_b_wQpoints(const std::vector<double>& q_vector)
1✔
394
{
395
  const std::string fname = "acceleration::DiffusionMIPSolver::"
396
                            "AssembleAand_b_wQpoints";
1✔
397
  if (A_ == nullptr or rhs_ == nullptr or ksp_ == nullptr)
1✔
398
    throw std::logic_error(fname + ": Some or all PETSc elements are null. "
×
399
                                   "Check that Initialize has been called.");
×
400
  if (options.verbose)
1✔
401
    log.Log() << program_timer.GetTimeString() << " Starting assembly";
1✔
402

403
  VecSet(rhs_, 0.0);
1✔
404

405
  for (const auto& cell : grid_->local_cells)
101✔
406
  {
407
    const size_t num_faces = cell.faces.size();
100✔
408
    const auto& cell_mapping = sdm_.GetCellMapping(cell);
100✔
409
    const size_t num_nodes = cell_mapping.GetNumNodes();
100✔
410
    const auto fe_vol_data = cell_mapping.MakeVolumetricFiniteElementData();
100✔
411
    const size_t num_groups = uk_man_.unknowns.front().num_components;
100✔
412

413
    const auto& xs = mat_id_2_xs_map_.at(cell.block_id);
100✔
414

415
    Vector<double> cell_rhs(num_nodes);
100✔
416
    Vector<PetscInt> cell_idxs(num_nodes);
100✔
417
    // For component/group
418
    for (size_t g = 0; g < num_groups; ++g)
200✔
419
    {
420
      cell_rhs.Set(0.);
100✔
421
      for (size_t i = 0; i < num_nodes; ++i)
500✔
422
        cell_idxs(i) = sdm_.MapDOF(cell, i, uk_man_, 0, g);
800✔
423

424
      // Get coefficient and nodal src
425
      const double Dg = xs.Dg[g];
100✔
426

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

431
      // Assemble continuous terms
432
      for (size_t i = 0; i < num_nodes; ++i)
500✔
433
      {
434
        double entry_rhs_i = 0.0; // entry may accumulate over j
400✔
435
        if (not source_function_)
400✔
436
          for (size_t j = 0; j < num_nodes; ++j)
×
437
          {
438
            for (size_t qp : fe_vol_data.GetQuadraturePointIndices())
×
439
            {
440
              entry_rhs_i += fe_vol_data.ShapeValue(i, qp) * fe_vol_data.ShapeValue(j, qp) *
×
441
                             fe_vol_data.JxW(qp) * qg[j];
×
442
            } // for qp
443
          } // for j
444
        else
445
        {
446
          for (size_t qp : fe_vol_data.GetQuadraturePointIndices())
5,200✔
447
            entry_rhs_i += source_function_(fe_vol_data.QPointXYZ(qp)) *
4,800✔
448
                           fe_vol_data.ShapeValue(i, qp) * fe_vol_data.JxW(qp);
4,800✔
449
        }
450

451
        cell_rhs(i) += entry_rhs_i;
400✔
452
      } // for i
453

454
      // Assemble face terms
455
      for (size_t f = 0; f < num_faces; ++f)
500✔
456
      {
457
        const auto& face = cell.faces[f];
400✔
458
        const auto& n_f = face.normal;
400✔
459
        const size_t num_face_nodes = cell_mapping.GetNumFaceNodes(f);
400✔
460
        const auto fe_srf_data = cell_mapping.MakeSurfaceFiniteElementData(f);
400✔
461

462
        const double hm = HPerpendicular(cell, f);
400✔
463

464
        if (not face.has_neighbor and not suppress_bcs_)
400✔
465
        {
466
          BoundaryCondition bc;
40✔
467
          if (bcs_.count(face.neighbor_id) > 0)
40✔
468
            bc = bcs_.at(face.neighbor_id);
40✔
469

470
          if (bc.type == BCType::DIRICHLET)
40✔
471
          {
472
            const double bc_value = bc.values[0];
40✔
473

474
            // Compute kappa
475
            double kappa = 1.0;
40✔
476
            if (cell.GetType() == CellType::SLAB)
40✔
477
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
×
478
            if (cell.GetType() == CellType::POLYGON)
40✔
479
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
40✔
480
            if (cell.GetType() == CellType::POLYHEDRON)
40✔
481
              kappa = fmax(options.penalty_factor * 2.0 * Dg / hm, 0.25);
×
482

483
            // Assembly penalty terms
484
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
120✔
485
            {
486
              const int i = cell_mapping.MapFaceNode(f, fi);
80✔
487

488
              for (size_t fj = 0; fj < num_face_nodes; ++fj)
240✔
489
              {
490
                const int jm = cell_mapping.MapFaceNode(f, fj);
160✔
491

492
                double aij = 0.0;
160✔
493
                for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
480✔
494
                  aij += kappa * fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeValue(jm, qp) *
320✔
495
                         fe_srf_data.JxW(qp);
320✔
496
                double aij_bc_value = aij * bc_value;
160✔
497

498
                if (ref_solution_function_)
160✔
499
                {
500
                  aij_bc_value = 0.0;
160✔
501
                  for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
480✔
502
                    aij_bc_value += kappa * source_function_(fe_srf_data.QPointXYZ(qp)) *
320✔
503
                                    fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeValue(jm, qp) *
320✔
504
                                    fe_srf_data.JxW(qp);
320✔
505
                }
506

507
                cell_rhs(i) += aij_bc_value;
160✔
508
              } // for fj
509
            } // for fi
510

511
            // Assemble gradient terms
512
            // For the following comments we use the notation:
513
            // Dk = 0.5* n dot nabla bk
514

515
            // 0.5*D* n dot (b_j^+ - b_j^-)*nabla b_i^-
516
            for (size_t i = 0; i < num_nodes; ++i)
200✔
517
            {
518
              for (size_t j = 0; j < num_nodes; ++j)
800✔
519
              {
520
                Vector3 vec_aij;
640✔
521
                for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
1,920✔
522
                  vec_aij += fe_srf_data.ShapeValue(j, qp) * fe_srf_data.ShapeGrad(i, qp) *
1,280✔
523
                               fe_srf_data.JxW(qp) +
2,560✔
524
                             fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeGrad(j, qp) *
2,560✔
525
                               fe_srf_data.JxW(qp);
3,840✔
526
                const double aij = -Dg * n_f.Dot(vec_aij);
640✔
527

528
                double aij_bc_value = aij * bc_value;
640✔
529

530
                if (ref_solution_function_)
640✔
531
                {
532
                  Vector3 vec_aij_mms;
640✔
533
                  for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
1,920✔
UNCOV
534
                    vec_aij_mms += ref_solution_function_(fe_srf_data.QPointXYZ(qp)) *
×
535
                                   (fe_srf_data.ShapeValue(j, qp) * fe_srf_data.ShapeGrad(i, qp) *
1,280✔
536
                                      fe_srf_data.JxW(qp) +
2,560✔
537
                                    fe_srf_data.ShapeValue(i, qp) * fe_srf_data.ShapeGrad(j, qp) *
2,560✔
538
                                      fe_srf_data.JxW(qp));
3,840✔
539
                  aij_bc_value = -Dg * n_f.Dot(vec_aij_mms);
640✔
540
                }
541

542
                cell_rhs(i) += aij_bc_value;
640✔
543
              } // for fj
544
            } // for i
545
          } // Dirichlet BC
546
          else if (bc.type == BCType::ROBIN)
×
547
          {
548
            const double bval = bc.values[1];
×
549
            const double fval = bc.values[2];
×
550

551
            if (std::fabs(bval) < 1.0e-12)
×
552
              continue; // a and f assumed zero
×
553

554
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
×
555
            {
556
              const int i = cell_mapping.MapFaceNode(f, fi);
×
557

558
              if (std::fabs(fval) >= 1.0e-12)
×
559
              {
560
                double rhs_val = 0.0;
×
561
                for (size_t qp : fe_srf_data.GetQuadraturePointIndices())
×
562
                  rhs_val += fe_srf_data.ShapeValue(i, qp) * fe_srf_data.JxW(qp);
×
563
                rhs_val *= (fval / bval);
×
564

565
                cell_rhs(i) += rhs_val;
×
566
              } // if f nonzero
567
            } // for fi
568
          } // Robin BC
569
        } // boundary face
570
      } // for face
400✔
571
      VecSetValues(rhs_, num_nodes, cell_idxs.data(), cell_rhs.data(), ADD_VALUES);
100✔
572
    } // for g
100✔
573
  } // for cell
100✔
574

575
  VecAssemblyBegin(rhs_);
1✔
576
  VecAssemblyEnd(rhs_);
1✔
577

578
  KSPSetOperators(ksp_, A_, A_);
1✔
579

580
  if (options.verbose)
1✔
581
    log.Log() << program_timer.GetTimeString() << " Assembly completed";
1✔
582

583
  PC pc;
584
  KSPGetPC(ksp_, &pc);
1✔
585
  PCSetUp(pc);
1✔
586

587
  KSPSetUp(ksp_);
1✔
588
}
1✔
589

590
void
591
DiffusionMIPSolver::AssembleAand_b(const std::vector<double>& q_vector)
67✔
592
{
593
  const std::string fname = "acceleration::DiffusionMIPSolver::"
594
                            "AssembleAand_b";
67✔
595
  if (A_ == nullptr or rhs_ == nullptr or ksp_ == nullptr)
67✔
596
    throw std::logic_error(fname + ": Some or all PETSc elements are null. "
×
597
                                   "Check that Initialize has been called.");
×
598
  if (options.verbose)
67✔
599
    log.Log() << program_timer.GetTimeString() << " Starting assembly";
4✔
600

601
  const size_t num_groups = uk_man_.unknowns.front().num_components;
67✔
602

603
  VecSet(rhs_, 0.0);
67✔
604
  for (const auto& cell : grid_->local_cells)
18,595✔
605
  {
606
    const size_t num_faces = cell.faces.size();
18,528✔
607
    const auto& cell_mapping = sdm_.GetCellMapping(cell);
18,528✔
608
    const size_t num_nodes = cell_mapping.GetNumNodes();
18,528✔
609
    const auto cc_nodes = cell_mapping.GetNodeLocations();
18,528✔
610
    const auto& unit_cell_matrices = unit_cell_matrices_[cell.local_id];
18,528✔
611

612
    const auto& intV_gradshapeI_gradshapeJ = unit_cell_matrices.intV_gradshapeI_gradshapeJ;
18,528✔
613
    const auto& intV_shapeI_shapeJ = unit_cell_matrices.intV_shapeI_shapeJ;
18,528✔
614

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

617
    DenseMatrix<double> cell_A(num_nodes, num_nodes);
18,528✔
618
    Vector<double> cell_rhs(num_nodes);
18,528✔
619
    Vector<PetscInt> cell_idxs(num_nodes);
18,528✔
620
    for (size_t g = 0; g < num_groups; ++g)
620,197✔
621
    {
622
      cell_A.Set(0.);
601,669✔
623
      cell_rhs.Set(0.);
601,669✔
624
      for (size_t i = 0; i < num_nodes; ++i)
3,793,607✔
625
        cell_idxs(i) = sdm_.MapDOF(cell, i, uk_man_, 0, g);
6,383,876✔
626

627
      // Get coefficient and nodal src
628
      const double Dg = xs.Dg[g];
601,669✔
629
      const double sigr_g = xs.sigR[g];
601,669✔
630

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

635
      // Assemble continuous terms
636
      for (size_t i = 0; i < num_nodes; ++i)
3,793,607✔
637
      {
638
        double entry_rhs_i = 0.0;
3,191,938✔
639
        for (size_t j = 0; j < num_nodes; ++j)
24,271,814✔
640
        {
641
          const double entry_aij =
642
            Dg * intV_gradshapeI_gradshapeJ(i, j) + sigr_g * intV_shapeI_shapeJ(i, j);
42,159,752✔
643

644
          entry_rhs_i += intV_shapeI_shapeJ(i, j) * qg[j];
42,159,752✔
645

646
          cell_A(i, j) += entry_aij;
21,079,876✔
647
        } // for j
648

649
        cell_rhs(i) += entry_rhs_i;
3,191,938✔
650
      } // for i
651

652
      // Assemble face terms
653
      for (size_t f = 0; f < num_faces; ++f)
3,231,807✔
654
      {
655
        const auto& face = cell.faces[f];
2,630,138✔
656
        const auto& n_f = face.normal;
2,630,138✔
657
        const size_t num_face_nodes = cell_mapping.GetNumFaceNodes(f);
2,630,138✔
658

659
        const auto& intS_shapeI_shapeJ = unit_cell_matrices.intS_shapeI_shapeJ[f];
2,630,138✔
660
        const auto& intS_shapeI_gradshapeJ = unit_cell_matrices.intS_shapeI_gradshapeJ[f];
2,630,138✔
661
        const auto& intS_shapeI = unit_cell_matrices.intS_shapeI[f];
2,630,138✔
662

663
        const double hm = HPerpendicular(cell, f);
2,630,138✔
664

665
        if (face.has_neighbor)
2,630,138✔
666
        {
667
          const auto& adj_cell = grid_->cells[face.neighbor_id];
2,399,302✔
668
          const auto& adj_cell_mapping = sdm_.GetCellMapping(adj_cell);
2,399,302✔
669
          const auto ac_nodes = adj_cell_mapping.GetNodeLocations();
2,399,302✔
670
          const size_t acf = MeshContinuum::MapCellFace(cell, adj_cell, f);
2,399,302✔
671
          const double hp = HPerpendicular(adj_cell, acf);
2,399,302✔
672

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

676
          // Compute kappa
677
          double kappa = 1.0;
2,399,302✔
678
          if (cell.GetType() == CellType::SLAB)
2,399,302✔
679
            kappa = fmax(options.penalty_factor * (adj_Dg / hp + Dg / hm) * 0.5, 0.25);
337,662✔
680
          if (cell.GetType() == CellType::POLYGON)
2,399,302✔
681
            kappa = fmax(options.penalty_factor * (adj_Dg / hp + Dg / hm) * 0.5, 0.25);
578,120✔
682
          if (cell.GetType() == CellType::POLYHEDRON)
2,399,302✔
683
            kappa = fmax(options.penalty_factor * 2.0 * (adj_Dg / hp + Dg / hm) * 0.5, 0.25);
1,483,520✔
684

685
          DenseMatrix<double> adj_A(num_nodes, num_face_nodes, 0.);
2,399,302✔
686
          DenseMatrix<double> adj_AT(num_face_nodes, num_nodes, 0.);
2,399,302✔
687
          Vector<PetscInt> adj_idxs(num_face_nodes);
2,399,302✔
688
          for (size_t fj = 0; fj < num_face_nodes; ++fj)
9,827,284✔
689
          {
690
            const auto jp =
691
              MapFaceNodeDisc(cell, adj_cell, cc_nodes, ac_nodes, f, acf, fj); // j-plus
7,427,982✔
692
            adj_idxs(fj) = sdm_.MapDOF(adj_cell, jp, uk_man_, 0, g);
14,855,964✔
693
          }
694

695
          // Assembly penalty terms
696
          for (size_t fi = 0; fi < num_face_nodes; ++fi)
9,827,284✔
697
          {
698
            const int i = cell_mapping.MapFaceNode(f, fi);
7,427,982✔
699

700
            for (size_t fj = 0; fj < num_face_nodes; ++fj)
33,814,444✔
701
            {
702
              const int jm = cell_mapping.MapFaceNode(f, fj); // j-minus
26,386,462✔
703

704
              const double aij = kappa * intS_shapeI_shapeJ(i, jm);
52,772,924✔
705

706
              cell_A(i, jm) += aij;
26,386,462✔
707
              adj_A(i, fj) -= aij;
26,386,462✔
708
            } // for fj
709
          } // for fi
710

711
          // Assemble gradient terms
712
          // For the following comments we use the notation:
713
          // Dk = 0.5* n dot nabla bk
714

715
          // 0.5*D* n dot (b_j^+ - b_j^-)*nabla b_i^-
716
          for (size_t i = 0; i < num_nodes; ++i)
17,255,266✔
717
          {
718
            for (size_t fj = 0; fj < num_face_nodes; ++fj)
67,628,888✔
719
            {
720
              const int jm = cell_mapping.MapFaceNode(f, fj); // j-minus
52,772,924✔
721

722
              const double aij = -0.5 * Dg * n_f.Dot(intS_shapeI_gradshapeJ(jm, i));
105,545,848✔
723

724
              cell_A(i, jm) += aij;
52,772,924✔
725
              adj_A(i, fj) -= aij;
52,772,924✔
726
            } // for fj
727
          } // for i
728

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

734
            for (size_t j = 0; j < num_nodes; ++j)
60,200,906✔
735
            {
736
              const double aij = -0.5 * Dg * n_f.Dot(intS_shapeI_gradshapeJ(im, j));
105,545,848✔
737

738
              cell_A(im, j) += aij;
52,772,924✔
739
              adj_AT(fi, j) -= aij;
52,772,924✔
740
            } // for j
741
          } // for fi
742

743
          MatSetValues(A_,
2,399,302✔
744
                       num_nodes,
745
                       cell_idxs.data(),
2,399,302✔
746
                       num_face_nodes,
747
                       adj_idxs.data(),
2,399,302✔
748
                       adj_A.data(),
2,399,302✔
749
                       ADD_VALUES);
750

751
          MatSetValues(A_,
2,399,302✔
752
                       num_face_nodes,
753
                       adj_idxs.data(),
2,399,302✔
754
                       num_nodes,
755
                       cell_idxs.data(),
2,399,302✔
756
                       adj_AT.data(),
2,399,302✔
757
                       ADD_VALUES);
758

759
        } // internal face
2,399,302✔
760
        else
761
        {
762
          BoundaryCondition bc;
230,836✔
763
          if (bcs_.count(face.neighbor_id) > 0)
230,836✔
764
            bc = bcs_.at(face.neighbor_id);
230,836✔
765

766
          if (bc.type == BCType::DIRICHLET)
230,836✔
767
          {
768
            const double bc_value = bc.values[0];
210,956✔
769

770
            // Compute kappa
771
            double kappa = 1.0;
210,956✔
772
            if (cell.GetType() == CellType::SLAB)
210,956✔
773
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
676✔
774
            if (cell.GetType() == CellType::POLYGON)
210,956✔
775
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
21,000✔
776
            if (cell.GetType() == CellType::POLYHEDRON)
210,956✔
777
              kappa = fmax(options.penalty_factor * 2.0 * Dg / hm, 0.25);
189,280✔
778

779
            // Assembly penalty terms
780
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
1,010,752✔
781
            {
782
              const int i = cell_mapping.MapFaceNode(f, fi);
799,796✔
783

784
              for (size_t fj = 0; fj < num_face_nodes; ++fj)
3,912,952✔
785
              {
786
                const int jm = cell_mapping.MapFaceNode(f, fj);
3,113,156✔
787

788
                const double aij = kappa * intS_shapeI_shapeJ(i, jm);
3,113,156✔
789
                const double aij_bc_value = aij * bc_value;
3,113,156✔
790

791
                cell_A(i, jm) += aij;
3,113,156✔
792
                cell_rhs(i) += aij_bc_value;
3,113,156✔
793
              } // for fj
794
            } // for fi
795

796
            // Assemble gradient terms
797
            // For the following comments we use the notation:
798
            // Dk = n dot nabla bk
799

800
            // D* n dot (b_j^+ - b_j^-)*nabla b_i^-
801
            for (size_t i = 0; i < num_nodes; ++i)
1,810,548✔
802
            {
803
              for (size_t j = 0; j < num_nodes; ++j)
14,052,216✔
804
              {
805
                const double aij =
806
                  -Dg * n_f.Dot(intS_shapeI_gradshapeJ(j, i) + intS_shapeI_gradshapeJ(i, j));
37,357,872✔
807
                const double aij_bc_value = aij * bc_value;
12,452,624✔
808

809
                cell_A(i, j) += aij;
12,452,624✔
810
                cell_rhs(i) += aij_bc_value;
12,452,624✔
811
              } // for fj
812
            } // for i
813
          } // Dirichlet BC
814
          else if (bc.type == BCType::ROBIN)
19,880✔
815
          {
816
            const double aval = bc.values[0];
19,880✔
817
            const double bval = bc.values[1];
19,880✔
818
            const double fval = bc.values[2];
19,880✔
819

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

823
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
84,840✔
824
            {
825
              const int i = cell_mapping.MapFaceNode(f, fi);
64,960✔
826

827
              if (std::fabs(aval) >= 1.0e-12)
64,960✔
828
              {
829
                for (size_t fj = 0; fj < num_face_nodes; ++fj)
×
830
                {
831
                  const int j = cell_mapping.MapFaceNode(f, fj);
×
832

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

835
                  cell_A(i, j) += aij;
×
836
                } // for fj
837
              } // if a nonzero
838

839
              if (std::fabs(fval) >= 1.0e-12)
64,960✔
840
              {
841
                const double rhs_val = (fval / bval) * intS_shapeI(i);
×
842

843
                cell_rhs(i) += rhs_val;
×
844
              } // if f nonzero
845
            } // for fi
846
          } // Robin BC
847
        } // boundary face
848
      } // for face
849

850
      MatSetValues(
601,669✔
851
        A_, num_nodes, cell_idxs.data(), num_nodes, cell_idxs.data(), cell_A.data(), ADD_VALUES);
601,669✔
852
      VecSetValues(rhs_, num_nodes, cell_idxs.data(), cell_rhs.data(), ADD_VALUES);
601,669✔
853
    } // for g
601,669✔
854
  } // for cell
18,528✔
855

856
  MatAssemblyBegin(A_, MAT_FINAL_ASSEMBLY);
67✔
857
  MatAssemblyEnd(A_, MAT_FINAL_ASSEMBLY);
67✔
858
  VecAssemblyBegin(rhs_);
67✔
859
  VecAssemblyEnd(rhs_);
67✔
860

861
  if (options.verbose)
67✔
862
  {
863
    MatInfo info;
864
    MatGetInfo(A_, MAT_GLOBAL_SUM, &info);
4✔
865

866
    log.Log() << "Number of mallocs used = " << info.mallocs
8✔
867
              << "\nNumber of non-zeros allocated = " << info.nz_allocated
4✔
868
              << "\nNumber of non-zeros used = " << info.nz_used
4✔
869
              << "\nNumber of unneeded non-zeros = " << info.nz_unneeded;
4✔
870
  }
871

872
  if (options.perform_symmetry_check)
67✔
873
  {
874
    PetscBool symmetry = PETSC_FALSE;
×
875
    MatIsSymmetric(A_, 1.0e-6, &symmetry);
×
876
    if (symmetry == PETSC_FALSE)
×
877
      throw std::logic_error(fname + ":Symmetry check failed");
×
878
  }
879

880
  KSPSetOperators(ksp_, A_, A_);
67✔
881

882
  if (options.verbose)
67✔
883
    log.Log() << program_timer.GetTimeString() << " Assembly completed";
4✔
884

885
  PC pc;
886
  KSPGetPC(ksp_, &pc);
67✔
887
  PCSetUp(pc);
67✔
888

889
  KSPSetUp(ksp_);
67✔
890
}
67✔
891

892
void
893
DiffusionMIPSolver::Assemble_b(const std::vector<double>& q_vector)
9,094✔
894
{
895
  const std::string fname = "acceleration::DiffusionMIPSolver::"
896
                            "Assemble_b";
9,094✔
897
  if (A_ == nullptr or rhs_ == nullptr or ksp_ == nullptr)
9,094✔
898
    throw std::logic_error(fname + ": Some or all PETSc elements are null. "
×
899
                                   "Check that Initialize has been called.");
×
900
  if (options.verbose)
9,094✔
901
    log.Log() << program_timer.GetTimeString() << " Starting assembly";
128✔
902

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

905
  VecSet(rhs_, 0.0);
9,094✔
906
  for (const auto& cell : grid_->local_cells)
1,603,168✔
907
  {
908
    const size_t num_faces = cell.faces.size();
1,594,074✔
909
    const auto& cell_mapping = sdm_.GetCellMapping(cell);
1,594,074✔
910
    const size_t num_nodes = cell_mapping.GetNumNodes();
1,594,074✔
911
    const auto cc_nodes = cell_mapping.GetNodeLocations();
1,594,074✔
912
    const auto& unit_cell_matrices = unit_cell_matrices_[cell.local_id];
1,594,074✔
913

914
    const auto& intV_shapeI_shapeJ = unit_cell_matrices.intV_shapeI_shapeJ;
1,594,074✔
915

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

918
    Vector<double> cell_rhs(num_nodes);
1,594,074✔
919
    Vector<PetscInt> cell_idxs(num_nodes);
1,594,074✔
920
    for (size_t g = 0; g < num_groups; ++g)
35,901,216✔
921
    {
922
      cell_rhs.Set(0.);
34,307,142✔
923
      for (size_t i = 0; i < num_nodes; ++i)
228,894,226✔
924
        cell_idxs(i) = sdm_.MapDOF(cell, i, uk_man_, 0, g);
389,174,168✔
925

926
      // Get coefficient and nodal src
927
      const double Dg = xs.Dg[g];
34,307,142✔
928

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

933
      // Assemble continuous terms
934
      for (size_t i = 0; i < num_nodes; ++i)
228,894,226✔
935
      {
936
        double entry_rhs_i = 0.0;
194,587,084✔
937
        for (size_t j = 0; j < num_nodes; ++j)
1,510,398,052✔
938
          entry_rhs_i += intV_shapeI_shapeJ(i, j) * qg[j];
2,147,483,647✔
939

940
        cell_rhs(i) += entry_rhs_i;
194,587,084✔
941
      } // for i
942

943
      // Assemble face terms
944
      for (size_t f = 0; f < num_faces; ++f)
193,665,426✔
945
      {
946
        const auto& face = cell.faces[f];
159,358,284✔
947
        const auto& n_f = face.normal;
159,358,284✔
948
        const size_t num_face_nodes = cell_mapping.GetNumFaceNodes(f);
159,358,284✔
949

950
        const auto& intS_shapeI_shapeJ = unit_cell_matrices.intS_shapeI_shapeJ[f];
159,358,284✔
951
        const auto& intS_shapeI_gradshapeJ = unit_cell_matrices.intS_shapeI_gradshapeJ[f];
159,358,284✔
952
        const auto& intS_shapeI = unit_cell_matrices.intS_shapeI[f];
159,358,284✔
953

954
        const double hm = HPerpendicular(cell, f);
159,358,284✔
955

956
        if (not face.has_neighbor and not suppress_bcs_)
159,358,284✔
957
        {
958
          BoundaryCondition bc;
14,744,688✔
959
          if (bcs_.count(face.neighbor_id) > 0)
14,744,688✔
960
            bc = bcs_.at(face.neighbor_id);
14,744,688✔
961

962
          if (bc.type == BCType::DIRICHLET)
14,744,688✔
963
          {
964
            const double bc_value = bc.values[0];
13,841,808✔
965

966
            // Compute kappa
967
            double kappa = 1.0;
13,841,808✔
968
            if (cell.GetType() == CellType::SLAB)
13,841,808✔
969
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
427,768✔
970
            if (cell.GetType() == CellType::POLYGON)
13,841,808✔
971
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
1,319,160✔
972
            if (cell.GetType() == CellType::POLYHEDRON)
13,841,808✔
973
              kappa = fmax(options.penalty_factor * 2.0 * Dg / hm, 0.25);
12,094,880✔
974

975
            // Assembly penalty terms
976
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
65,287,416✔
977
            {
978
              const int i = cell_mapping.MapFaceNode(f, fi);
51,445,608✔
979

980
              for (size_t fj = 0; fj < num_face_nodes; ++fj)
250,668,096✔
981
              {
982
                const int jm = cell_mapping.MapFaceNode(f, fj);
199,222,488✔
983

984
                const double aij = kappa * intS_shapeI_shapeJ(i, jm);
199,222,488✔
985
                const double aij_bc_value = aij * bc_value;
199,222,488✔
986

987
                cell_rhs(i) += aij_bc_value;
199,222,488✔
988
              } // for fj
989
            } // for fi
990

991
            // Assemble gradient terms
992
            // For the following comments we use the notation:
993
            // Dk = n dot nabla bk
994

995
            // D* n dot (b_j^+ - b_j^-)*nabla b_i^-
996
            for (size_t i = 0; i < num_nodes; ++i)
116,733,024✔
997
            {
998
              for (size_t j = 0; j < num_nodes; ++j)
899,781,168✔
999
              {
1000
                const double aij =
1001
                  -Dg * n_f.Dot(intS_shapeI_gradshapeJ(j, i) + intS_shapeI_gradshapeJ(i, j));
2,147,483,647✔
1002
                const double aij_bc_value = aij * bc_value;
796,889,952✔
1003

1004
                cell_rhs(i) += aij_bc_value;
796,889,952✔
1005
              } // for fj
1006
            } // for i
1007
          } // Dirichlet BC
1008
          else if (bc.type == BCType::ROBIN)
902,880✔
1009
          {
1010
            const double bval = bc.values[1];
902,880✔
1011
            const double fval = bc.values[2];
902,880✔
1012

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

1016
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
3,515,040✔
1017
            {
1018
              const int i = cell_mapping.MapFaceNode(f, fi);
2,612,160✔
1019

1020
              if (std::fabs(fval) >= 1.0e-12)
2,612,160✔
1021
              {
1022
                const double rhs_val = (fval / bval) * intS_shapeI(i);
×
1023

1024
                cell_rhs(i) += rhs_val;
×
1025
              } // if f nonzero
1026
            } // for fi
1027
          } // Robin BC
1028
        } // boundary face
1029
      } // for face
1030

1031
      VecSetValues(rhs_, num_nodes, cell_idxs.data(), cell_rhs.data(), ADD_VALUES);
34,307,142✔
1032
    } // for g
34,307,142✔
1033
  } // for cell
1,594,074✔
1034

1035
  VecAssemblyBegin(rhs_);
9,094✔
1036
  VecAssemblyEnd(rhs_);
9,094✔
1037

1038
  if (options.verbose)
9,094✔
1039
    log.Log() << program_timer.GetTimeString() << " Assembly completed";
128✔
1040
}
9,094✔
1041

1042
void
1043
DiffusionMIPSolver::Assemble_b(Vec petsc_q_vector)
×
1044
{
1045
  const std::string fname = "acceleration::DiffusionMIPSolver::"
1046
                            "Assemble_b";
×
1047
  if (A_ == nullptr or rhs_ == nullptr or ksp_ == nullptr)
×
1048
    throw std::logic_error(fname + ": Some or all PETSc elements are null. "
×
1049
                                   "Check that Initialize has been called.");
×
1050
  if (options.verbose)
×
1051
    log.Log() << program_timer.GetTimeString() << " Starting assembly";
×
1052

1053
  const size_t num_groups = uk_man_.unknowns.front().num_components;
×
1054

1055
  const double* q_vector;
1056
  VecGetArrayRead(petsc_q_vector, &q_vector);
×
1057

1058
  VecSet(rhs_, 0.0);
×
1059
  for (const auto& cell : grid_->local_cells)
×
1060
  {
1061
    const size_t num_faces = cell.faces.size();
×
1062
    const auto& cell_mapping = sdm_.GetCellMapping(cell);
×
1063
    const size_t num_nodes = cell_mapping.GetNumNodes();
×
1064
    const auto cc_nodes = cell_mapping.GetNodeLocations();
×
1065
    const auto& unit_cell_matrices = unit_cell_matrices_[cell.local_id];
×
1066

1067
    const auto& intV_shapeI_shapeJ = unit_cell_matrices.intV_shapeI_shapeJ;
×
1068

1069
    const auto& xs = mat_id_2_xs_map_.at(cell.block_id);
×
1070

1071
    Vector<double> cell_rhs(num_nodes);
×
1072
    Vector<PetscInt> cell_idxs(num_nodes);
×
1073
    for (size_t g = 0; g < num_groups; ++g)
×
1074
    {
1075
      cell_rhs.Set(0.);
×
1076
      for (size_t i = 0; i < num_nodes; ++i)
×
1077
        cell_idxs(i) = sdm_.MapDOF(cell, i, uk_man_, 0, g);
×
1078

1079
      // Get coefficient and nodal src
1080
      const double Dg = xs.Dg[g];
×
1081

1082
      std::vector<double> qg(num_nodes, 0.0);
×
1083
      for (size_t j = 0; j < num_nodes; ++j)
×
1084
        qg[j] = q_vector[sdm_.MapDOFLocal(cell, j, uk_man_, 0, g)];
×
1085

1086
      // Assemble continuous terms
1087
      for (size_t i = 0; i < num_nodes; ++i)
×
1088
      {
UNCOV
1089
        double entry_rhs_i = 0.0;
×
1090
        for (size_t j = 0; j < num_nodes; ++j)
×
1091
          entry_rhs_i += intV_shapeI_shapeJ(i, j) * qg[j];
×
1092

1093
        cell_rhs(i) += entry_rhs_i;
×
1094
      } // for i
1095

1096
      // Assemble face terms
1097
      for (size_t f = 0; f < num_faces; ++f)
×
1098
      {
1099
        const auto& face = cell.faces[f];
×
1100
        const auto& n_f = face.normal;
×
1101
        const size_t num_face_nodes = cell_mapping.GetNumFaceNodes(f);
×
1102

1103
        const auto& intS_shapeI_shapeJ = unit_cell_matrices.intS_shapeI_shapeJ[f];
×
1104
        const auto& intS_shapeI_gradshapeJ = unit_cell_matrices.intS_shapeI_gradshapeJ[f];
×
1105
        const auto& intS_shapeI = unit_cell_matrices.intS_shapeI[f];
×
1106

1107
        const double hm = HPerpendicular(cell, f);
×
1108

1109
        if (not face.has_neighbor and not suppress_bcs_)
×
1110
        {
1111
          BoundaryCondition bc;
×
1112
          if (bcs_.count(face.neighbor_id) > 0)
×
1113
            bc = bcs_.at(face.neighbor_id);
×
1114

1115
          if (bc.type == BCType::DIRICHLET)
×
1116
          {
1117
            const double bc_value = bc.values[0];
×
1118

1119
            // Compute kappa
1120
            double kappa = 1.0;
×
1121
            if (cell.GetType() == CellType::SLAB)
×
1122
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
×
1123
            if (cell.GetType() == CellType::POLYGON)
×
1124
              kappa = fmax(options.penalty_factor * Dg / hm, 0.25);
×
1125
            if (cell.GetType() == CellType::POLYHEDRON)
×
1126
              kappa = fmax(options.penalty_factor * 2.0 * Dg / hm, 0.25);
×
1127

1128
            // Assembly penalty terms
1129
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
×
1130
            {
1131
              const int i = cell_mapping.MapFaceNode(f, fi);
×
1132

1133
              for (size_t fj = 0; fj < num_face_nodes; ++fj)
×
1134
              {
1135
                const int jm = cell_mapping.MapFaceNode(f, fj);
×
1136

1137
                const double aij = kappa * intS_shapeI_shapeJ(i, jm);
×
1138
                const double aij_bc_value = aij * bc_value;
×
1139

1140
                cell_rhs(i) += aij_bc_value;
×
1141
              } // for fj
1142
            } // for fi
1143

1144
            // Assemble gradient terms
1145
            // For the following comments we use the notation:
1146
            // Dk = n dot nabla bk
1147

1148
            // D* n dot (b_j^+ - b_j^-)*nabla b_i^-
1149
            for (size_t i = 0; i < num_nodes; ++i)
×
1150
            {
1151
              for (size_t j = 0; j < num_nodes; ++j)
×
1152
              {
1153
                const double aij =
1154
                  -Dg * n_f.Dot(intS_shapeI_gradshapeJ(j, i) + intS_shapeI_gradshapeJ(i, j));
×
1155
                const double aij_bc_value = aij * bc_value;
×
1156

1157
                cell_rhs(i) += aij_bc_value;
×
1158
              } // for fj
1159
            } // for i
1160
          } // Dirichlet BC
1161
          else if (bc.type == BCType::ROBIN)
×
1162
          {
1163
            const double bval = bc.values[1];
×
1164
            const double fval = bc.values[2];
×
1165

1166
            if (std::fabs(bval) < 1.0e-12)
×
1167
              continue; // a and f assumed zero
×
1168

1169
            for (size_t fi = 0; fi < num_face_nodes; ++fi)
×
1170
            {
1171
              const int i = cell_mapping.MapFaceNode(f, fi);
×
1172

1173
              if (std::fabs(fval) >= 1.0e-12)
×
1174
              {
1175
                const double rhs_val = (fval / bval) * intS_shapeI(i);
×
1176

1177
                cell_rhs(i) += rhs_val;
×
1178
              } // if f nonzero
1179
            } // for fi
1180
          } // Robin BC
1181
        } // boundary face
1182
      } // for face
1183
      VecSetValues(rhs_, num_nodes, cell_idxs.data(), cell_rhs.data(), ADD_VALUES);
×
1184
    } // for g
×
1185
  } // for cell
×
1186

1187
  VecRestoreArrayRead(petsc_q_vector, &q_vector);
×
1188

1189
  VecAssemblyBegin(rhs_);
×
1190
  VecAssemblyEnd(rhs_);
×
1191

1192
  if (options.verbose)
×
1193
    log.Log() << program_timer.GetTimeString() << " Assembly completed";
×
1194
}
×
1195

1196
double
1197
DiffusionMIPSolver::HPerpendicular(const Cell& cell, unsigned int f)
164,388,884✔
1198
{
1199
  const auto& cell_mapping = sdm_.GetCellMapping(cell);
164,388,884✔
1200
  double hp;
1201

1202
  const auto num_faces = cell.faces.size();
164,388,884✔
1203
  const auto num_vertices = cell.vertex_ids.size();
164,388,884✔
1204

1205
  const auto volume = cell.volume;
164,388,884✔
1206
  const auto face_area = cell.faces.at(f).area;
164,388,884✔
1207

1208
  /**Lambda to compute surface area.*/
1209
  auto ComputeSurfaceArea = [&cell, &num_faces]()
108,855,320✔
1210
  {
1211
    double surface_area = 0.0;
108,855,320✔
1212
    for (size_t fr = 0; fr < num_faces; ++fr)
761,987,240✔
1213
      surface_area += cell.faces[fr].area;
653,131,920✔
1214

1215
    return surface_area;
108,855,320✔
1216
  };
164,388,884✔
1217

1218
  if (cell.GetType() == CellType::SLAB)
164,388,884✔
1219
  {
1220
    hp = volume / 2.0;
13,775,084✔
1221
  }
1222
  else if (cell.GetType() == CellType::POLYGON)
150,613,800✔
1223
  {
1224
    if (num_faces == 3)
41,758,480✔
1225
      hp = 2.0 * volume / face_area;
×
1226
    else if (num_faces == 4)
41,758,480✔
1227
      hp = volume / face_area;
41,758,480✔
1228
    else // Nv > 4
1229
    {
1230
      const auto surface_area = ComputeSurfaceArea();
×
1231

1232
      if (num_faces % 2 == 0)
×
1233
        hp = 4.0 * volume / surface_area;
×
1234
      else
1235
      {
1236
        hp = 2.0 * volume / surface_area;
×
1237
        hp +=
×
1238
          sqrt(2.0 * volume /
×
1239
               (static_cast<double>(num_faces) * sin(2.0 * M_PI / static_cast<double>(num_faces))));
×
1240
      }
1241
    }
1242
  }
1243
  else if (cell.GetType() == CellType::POLYHEDRON)
108,855,320✔
1244
  {
1245
    const auto surface_area = ComputeSurfaceArea();
108,855,320✔
1246

1247
    if (num_faces == 4) // Tet
108,855,320✔
1248
      hp = 3 * volume / surface_area;
×
1249
    else if (num_faces == 6 and num_vertices == 8) // Hex
108,855,320✔
1250
      hp = volume / surface_area;
108,855,320✔
1251
    else // Polyhedron
1252
      hp = 6 * volume / surface_area;
×
1253
  } // Polyhedron
1254
  else
1255
    throw std::logic_error("acceleration::DiffusionMIPSolver::HPerpendicular: "
1256
                           "Unsupported cell type in call to HPerpendicular");
×
1257

1258
  return hp;
164,388,884✔
1259
}
1260

1261
int
1262
DiffusionMIPSolver::MapFaceNodeDisc(const Cell& cur_cell,
7,428,702✔
1263
                                    const Cell& adj_cell,
1264
                                    const std::vector<Vector3>& cc_node_locs,
1265
                                    const std::vector<Vector3>& ac_node_locs,
1266
                                    size_t ccf,
1267
                                    size_t acf,
1268
                                    size_t ccfi,
1269
                                    double epsilon)
1270
{
1271
  const auto& cur_cell_mapping = sdm_.GetCellMapping(cur_cell);
7,428,702✔
1272
  const auto& adj_cell_mapping = sdm_.GetCellMapping(adj_cell);
7,428,702✔
1273

1274
  const int i = cur_cell_mapping.MapFaceNode(ccf, ccfi);
7,428,702✔
1275
  const auto& node_i_loc = cc_node_locs[i];
7,428,702✔
1276

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

1279
  for (size_t fj = 0; fj < adj_face_num_nodes; ++fj)
16,908,302✔
1280
  {
1281
    const int j = adj_cell_mapping.MapFaceNode(acf, fj);
16,908,302✔
1282
    if ((node_i_loc - ac_node_locs[j]).NormSquare() < epsilon)
16,908,302✔
1283
      return j;
7,428,702✔
1284
  }
1285

1286
  throw std::logic_error("acceleration::DiffusionMIPSolver::MapFaceNodeDisc: Mapping failure.");
×
1287
}
1288

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