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

CSMMLab / KiT-RT / #95

28 May 2025 02:06AM UTC coverage: 46.655% (-11.1%) from 57.728%
#95

push

travis-ci

web-flow
Release 2025 (#44)

* New neural models (#30)

* extend kitrt script

* added new neural models

* extend to m3 models

* added M3_2D models

* added M2 and M4 models

* configure ml optimizer for high order models

* added configuration for high order models

* add option for rotation postprcessing in neural networks. remove unneccessary python scripts

* started rotational symmetric postprocessing

* added rotational invariance postprocessing for m2 and m1 models

* fix post merge bugs

* created hohlraum mesh

* add hohlraum tes case

* add hohlraum test case

* add hohlraum cfg filees

* fixed hohlraum testcase

* add hohlraum cfg files

* changed hohlraum cfg

* changed hohlraum testcase to isotropic inflow source boundary condition

* added ghost cell bonudary for hohlraum testcase

* update readme and linesource mesh creator

* added proper scaling for linesource reference solution

* regularized newton debugging

* Data generator with reduced objective functional (#33)

* added reduced optimizer for sampling

* remove old debugging comments

* mesh acceleration (#38)

* added new ansatz (#36)

* added new ansatz

* debug new ansatz

* branch should be abandoned here

* debug new ansatz

* fix scaling error new ansatz

* fix config errors

* temporarily fixed dynamic ansatz rotation bug

* fix inheritance error for new ansatz

* mesh acceleration

* add structured hohlraum

* Mesh acc (#41)

* mesh acceleration

* added floor value for starmap moment methods

* enable accelleration

* delete minimum value starmap

* Update README.md

* Spherical harmonics nn (#40)

* added new ansatz

* debug new ansatz

* branch should be abandoned here

* debug new ansatz

* fix scaling error new ansatz

* fix config errors

* temporarily fixed dynamic ansatz rotation bug

* fix inheritance error for new ansatz

* mesh acceleration

* add structured hohlraum

* added sph... (continued)

767 of 3019 new or added lines in 51 files covered. (25.41%)

131 existing lines in 8 files now uncovered.

4422 of 9478 relevant lines covered (46.66%)

57163.05 hits per line

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

76.34
/src/solvers/pnsolver.cpp
1
#include "solvers/pnsolver.hpp"
2
#include "common/config.hpp"
3
#include "common/globalconstants.hpp"
4
#include "common/io.hpp"
5
#include "common/mesh.hpp"
6
#include "fluxes/numericalflux.hpp"
7
#include "problems/problembase.hpp"
8
#include "toolboxes/errormessages.hpp"
9
#include "toolboxes/textprocessingtoolbox.hpp"
10
// externals
11
#include "spdlog/spdlog.h"
12

13
#include <iostream>
14

15
PNSolver::PNSolver( Config* settings ) : SolverBase( settings ) {
8✔
16
    _polyDegreeBasis = settings->GetMaxMomentDegree();
8✔
17
    _nSystem         = GlobalIndex( int( _polyDegreeBasis ), int( _polyDegreeBasis ) ) + 1;
8✔
18

19
    // Initialize System Matrices
20
    _Ax = SymMatrix( _nSystem );
8✔
21
    _Ay = SymMatrix( _nSystem );
8✔
22
    _Az = SymMatrix( _nSystem );
8✔
23

24
    _AxPlus  = Matrix( _nSystem, _nSystem, 0 );
8✔
25
    _AxMinus = Matrix( _nSystem, _nSystem, 0 );
8✔
26
    _AxAbs   = Matrix( _nSystem, _nSystem, 0 );
8✔
27
    _AyPlus  = Matrix( _nSystem, _nSystem, 0 );
8✔
28
    _AyMinus = Matrix( _nSystem, _nSystem, 0 );
8✔
29
    _AyAbs   = Matrix( _nSystem, _nSystem, 0 );
8✔
30
    _AzPlus  = Matrix( _nSystem, _nSystem, 0 );
8✔
31
    _AzMinus = Matrix( _nSystem, _nSystem, 0 );
8✔
32
    _AzAbs   = Matrix( _nSystem, _nSystem, 0 );
8✔
33

34
    // Limiter variables
35
    _solDx   = VectorVector( _nCells, Vector( _nSystem, 0.0 ) );
8✔
36
    _solDy   = VectorVector( _nCells, Vector( _nSystem, 0.0 ) );
8✔
37
    _limiter = VectorVector( _nCells, Vector( _nSystem, 0.0 ) );
8✔
38

39
    // Initialize Scatter Matrix
40
    _scatterMatDiag = Vector( _nSystem, 0 );
8✔
41

42
    // Fill System Matrices
43
    ComputeSystemMatrices();
8✔
44

45
    // Compute Decomposition in positive and negative (eigenvalue) parts of flux jacobians
46
    ComputeFluxComponents();
8✔
47

48
    // Compute diagonal of the scatter matrix (it's a diagonal matrix)
49
    ComputeScatterMatrix();
8✔
50

51
    // AdaptTimeStep();
52

53
    if( settings->GetCleanFluxMat() ) CleanFluxMatrices();
8✔
54

55
    // Compute moments of initial condition
56
    // TODO
57
}
8✔
58

59
void PNSolver::IterPreprocessing( unsigned /*idx_iter*/ ) {
16✔
60

61
    // ------ Compute slope limiters and cell gradients ---
62

63
    if( _reconsOrder > 1 ) {
16✔
64
        _mesh->ComputeSlopes( _nSystem, _solDx, _solDy, _sol );
×
65
        _mesh->ComputeLimiter( _nSystem, _solDx, _solDy, _sol, _limiter );
×
66
    }
67
}
16✔
68

69
void PNSolver::ComputeScalarFlux() {
88✔
70
    double firstMomentScaleFactor = 4 * M_PI;
88✔
71
    if( _settings->GetProblemName() == PROBLEM_Aircavity1D || _settings->GetProblemName() == PROBLEM_Linesource1D ||
264✔
72
        _settings->GetProblemName() == PROBLEM_Checkerboard1D || _settings->GetProblemName() == PROBLEM_Meltingcube1D ) {
264✔
73
        firstMomentScaleFactor = 2.0;
×
74
    }
75
#pragma omp parallel for
88✔
76
    for( unsigned idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
77
        _scalarFluxNew[idx_cell] = _sol[idx_cell][0] * firstMomentScaleFactor;
78
    }
79
}
88✔
80

81
void PNSolver::FluxUpdate() {
16✔
82

83
    // Loop over all spatial cells
84
    if( _settings->GetProblemName() == PROBLEM_Aircavity1D || _settings->GetProblemName() == PROBLEM_Linesource1D ||
48✔
85
        _settings->GetProblemName() == PROBLEM_Checkerboard1D || _settings->GetProblemName() == PROBLEM_Meltingcube1D ) {
48✔
86
        FluxUpdatePseudo1D();
×
87
    }
88
    else {
89
        FluxUpdatePseudo2D();
16✔
90
    }
91
}
16✔
92

93
void PNSolver::FluxUpdatePseudo1D() {
×
94
#pragma omp parallel for
×
95
    for( unsigned idx_cell = 0; idx_cell < _nCells; idx_cell++ ) {
96
        Vector solL( _nSystem, 0.0 );
97
        Vector solR( _nSystem, 0.0 );
98
        // Dirichlet cells stay at IC, farfield assumption
99
        if( _boundaryCells[idx_cell] == BOUNDARY_TYPE::DIRICHLET ) continue;
100

101
        // Reset temporary variable psiNew
102
        for( unsigned idx_sys = 0; idx_sys < _nSystem; idx_sys++ ) {
103
            _solNew[idx_cell][idx_sys] = 0.0;
104
        }
105

106
        // Loop over all neighbor cells (edges) of cell j and compute numerical fluxes
107
        for( unsigned idx_neighbor = 0; idx_neighbor < _neighbors[idx_cell].size(); idx_neighbor++ ) {
108

109
            // Compute flux contribution and store in psiNew to save memory
110
            if( _boundaryCells[idx_cell] == BOUNDARY_TYPE::NEUMANN && _neighbors[idx_cell][idx_neighbor] == _nCells )
111
                _solNew[idx_cell] += _g->Flux1D( _AzPlus, _AzMinus, _sol[idx_cell], _sol[idx_cell], _normals[idx_cell][idx_neighbor] );
112
            else {
113
                unsigned int nbr_glob = _neighbors[idx_cell][idx_neighbor];    // global idx of neighbor cell
114
                switch( _reconsOrder ) {
115
                    // first order solver
116
                    case 1:
117
                        _solNew[idx_cell] += _g->Flux1D(
118
                            _AzPlus, _AzMinus, _sol[idx_cell], _sol[_neighbors[idx_cell][idx_neighbor]], _normals[idx_cell][idx_neighbor] );
119
                        break;
120
                    // second order solver
121
                    case 2:
122
                        // left status of interface
123
                        for( unsigned idx_sys = 0; idx_sys < _nSystem; idx_sys++ ) {
124
                            solL[idx_sys] =
125
                                _sol[idx_cell][idx_sys] +
126
                                _limiter[idx_cell][idx_sys] *
127
                                    ( _solDx[idx_cell][idx_sys] * ( _interfaceMidPoints[idx_cell][idx_neighbor][0] - _cellMidPoints[idx_cell][0] ) +
128
                                      _solDy[idx_cell][idx_sys] * ( _interfaceMidPoints[idx_cell][idx_neighbor][1] - _cellMidPoints[idx_cell][1] ) );
129
                            solR[idx_sys] =
130
                                _sol[nbr_glob][idx_sys] +
131
                                _limiter[nbr_glob][idx_sys] *
132
                                    ( _solDx[nbr_glob][idx_sys] * ( _interfaceMidPoints[idx_cell][idx_neighbor][0] - _cellMidPoints[nbr_glob][0] ) +
133
                                      _solDy[nbr_glob][idx_sys] * ( _interfaceMidPoints[idx_cell][idx_neighbor][1] - _cellMidPoints[nbr_glob][1] ) );
134
                        }
135
                        // flux evaluation
136
                        _solNew[idx_cell] += _g->Flux1D( _AzPlus, _AzMinus, solL, solR, _normals[idx_cell][idx_neighbor] );
137
                        break;
138
                    // default: first order solver
139
                    default: ErrorMessages::Error( "Reconstruction order not supported.", CURRENT_FUNCTION ); break;
140
                }
141
            }
142
        }
143
    }
144
}
145

146
void PNSolver::FluxUpdatePseudo2D() {
16✔
147
#pragma omp parallel for
16✔
148
    for( unsigned idx_cell = 0; idx_cell < _nCells; idx_cell++ ) {
149
        Vector solL( _nSystem, 0.0 );
150
        Vector solR( _nSystem, 0.0 );
151
        // Dirichlet cells stay at IC, farfield assumption
152
        if( _boundaryCells[idx_cell] == BOUNDARY_TYPE::DIRICHLET ) continue;
153

154
        // Reset temporary variable psiNew
155
        for( unsigned idx_sys = 0; idx_sys < _nSystem; idx_sys++ ) {
156
            _solNew[idx_cell][idx_sys] = 0.0;
157
        }
158

159
        // Loop over all neighbor cells (edges) of cell j and compute numerical fluxes
160
        for( unsigned idx_neighbor = 0; idx_neighbor < _neighbors[idx_cell].size(); idx_neighbor++ ) {
161

162
            // Compute flux contribution and store in psiNew to save memory
163
            if( _boundaryCells[idx_cell] == BOUNDARY_TYPE::NEUMANN && _neighbors[idx_cell][idx_neighbor] == _nCells )
164
                _solNew[idx_cell] += _g->Flux(
165
                    _AxPlus, _AxMinus, _AyPlus, _AyMinus, _AzPlus, _AzMinus, _sol[idx_cell], _sol[idx_cell], _normals[idx_cell][idx_neighbor] );
166
            else {
167
                unsigned int nbr_glob = _neighbors[idx_cell][idx_neighbor];    // global idx of neighbor cell
168
                switch( _reconsOrder ) {
169
                    // first order solver
170
                    case 1:
171
                        _solNew[idx_cell] += _g->Flux( _AxPlus,
172
                                                       _AxMinus,
173
                                                       _AyPlus,
174
                                                       _AyMinus,
175
                                                       _AzPlus,
176
                                                       _AzMinus,
177
                                                       _sol[idx_cell],
178
                                                       _sol[_neighbors[idx_cell][idx_neighbor]],
179
                                                       _normals[idx_cell][idx_neighbor] );
180
                        break;
181
                    // second order solver
182
                    case 2:
183
                        // left status of interface
184
                        for( unsigned idx_sys = 0; idx_sys < _nSystem; idx_sys++ ) {
185
                            solL[idx_sys] =
186
                                _sol[idx_cell][idx_sys] +
187
                                _limiter[idx_cell][idx_sys] *
188
                                    ( _solDx[idx_cell][idx_sys] * ( _interfaceMidPoints[idx_cell][idx_neighbor][0] - _cellMidPoints[idx_cell][0] ) +
189
                                      _solDy[idx_cell][idx_sys] * ( _interfaceMidPoints[idx_cell][idx_neighbor][1] - _cellMidPoints[idx_cell][1] ) );
190
                            solR[idx_sys] =
191
                                _sol[nbr_glob][idx_sys] +
192
                                _limiter[nbr_glob][idx_sys] *
193
                                    ( _solDx[nbr_glob][idx_sys] * ( _interfaceMidPoints[idx_cell][idx_neighbor][0] - _cellMidPoints[nbr_glob][0] ) +
194
                                      _solDy[nbr_glob][idx_sys] * ( _interfaceMidPoints[idx_cell][idx_neighbor][1] - _cellMidPoints[nbr_glob][1] ) );
195
                        }
196
                        // flux evaluation
197
                        _solNew[idx_cell] +=
198
                            _g->Flux( _AxPlus, _AxMinus, _AyPlus, _AyMinus, _AzPlus, _AzMinus, solL, solR, _normals[idx_cell][idx_neighbor] );
199
                        break;
200
                        // default: first order solver
201
                    default: ErrorMessages::Error( "Reconstruction order not supported.", CURRENT_FUNCTION ); break;
202
                }
203
            }
204
        }
205
    }
206
}
16✔
207

208
void PNSolver::FVMUpdate( unsigned idx_iter ) {
16✔
209
    if( _Q.size() == 1u && _sigmaT.size() == 1u && _sigmaS.size() == 1u ) {    // Physics constant in time
16✔
210
// Loop over all spatial cells
211
#pragma omp parallel for
16✔
212
        for( unsigned idx_cell = 0; idx_cell < _nCells; idx_cell++ ) {
213
            // Dirichlet cells stay at IC, farfield assumption
214
            if( _boundaryCells[idx_cell] == BOUNDARY_TYPE::DIRICHLET ) continue;
215
            // Flux update
216

217
            for( unsigned idx_sys = 0; idx_sys < _nSystem; idx_sys++ ) {
218
                _solNew[idx_cell][idx_sys] = _sol[idx_cell][idx_sys] -
219
                                             ( _dT / _areas[idx_cell] ) * _solNew[idx_cell][idx_sys] /* cell averaged flux */
220
                                             - _dT * _sol[idx_cell][idx_sys] *
221
                                                   ( _sigmaS[0][idx_cell] * _scatterMatDiag[idx_sys] /* scattering influence */
222
                                                     + _sigmaT[0][idx_cell] );                       /* total xs influence  */
223
            }
224
            // Source Term
225
            _solNew[idx_cell] += _dT * _Q[0][idx_cell];
226
        }
227
    }
228
    else {
229
        // Loop over all spatial cells
NEW
230
#pragma omp parallel for
×
231
        for( unsigned idx_cell = 0; idx_cell < _nCells; idx_cell++ ) {
232
            // Dirichlet cells stay at IC, farfield assumption
233
            if( _boundaryCells[idx_cell] == BOUNDARY_TYPE::DIRICHLET ) continue;
234
            // Flux update
235
            for( unsigned idx_sys = 0; idx_sys < _nSystem; idx_sys++ ) {
236
                _solNew[idx_cell][idx_sys] = _sol[idx_cell][idx_sys] -
237
                                             ( _dT / _areas[idx_cell] ) * _solNew[idx_cell][idx_sys] /* cell averaged flux */
238
                                             - _dT * _sol[idx_cell][idx_sys] *
239
                                                   ( _sigmaS[idx_iter][idx_cell] * _scatterMatDiag[idx_sys] /* scattering influence */
240
                                                     + _sigmaT[idx_iter][idx_cell] );                       /* total xs influence  */
241
            }
242
            // Source Term
243
            _solNew[idx_cell] += _dT * _Q[idx_iter][idx_cell];
244
        }
245
    }
246
}
16✔
247

248
void PNSolver::ComputeSystemMatrices() {
8✔
249
    int idx_col      = 0;
8✔
250
    unsigned idx_row = 0;
8✔
251

252
    // loop over columns of A
253
    for( int idx_lOrder = 0; idx_lOrder <= int( _polyDegreeBasis ); idx_lOrder++ ) {     // index of legendre polynom
52✔
254
        for( int idx_kOrder = -idx_lOrder; idx_kOrder <= idx_lOrder; idx_kOrder++ ) {    // second index of legendre function
336✔
255
            idx_row = unsigned( GlobalIndex( idx_lOrder, idx_kOrder ) );
292✔
256

257
            // flux matrix in direction x
258
            {
259
                if( idx_kOrder != -1 ) {
292✔
260

261
                    if( CheckIndex( idx_lOrder - 1, kMinus( idx_kOrder ) ) ) {
256✔
262
                        idx_col                             = GlobalIndex( idx_lOrder - 1, kMinus( idx_kOrder ) );
240✔
263
                        _Ax( idx_row, unsigned( idx_col ) ) = 0.5 * CTilde( idx_lOrder - 1, std::abs( idx_kOrder ) - 1 );
240✔
264
                    }
265

266
                    if( CheckIndex( idx_lOrder + 1, kMinus( idx_kOrder ) ) ) {
256✔
267
                        idx_col                             = GlobalIndex( idx_lOrder + 1, kMinus( idx_kOrder ) );
184✔
268
                        _Ax( idx_row, unsigned( idx_col ) ) = -0.5 * DTilde( idx_lOrder + 1, std::abs( idx_kOrder ) - 1 );
184✔
269
                    }
270
                }
271

272
                if( CheckIndex( idx_lOrder - 1, kPlus( idx_kOrder ) ) ) {
292✔
273
                    idx_col                             = GlobalIndex( idx_lOrder - 1, kPlus( idx_kOrder ) );
148✔
274
                    _Ax( idx_row, unsigned( idx_col ) ) = -0.5 * ETilde( idx_lOrder - 1, std::abs( idx_kOrder ) + 1 );
148✔
275
                }
276

277
                if( CheckIndex( idx_lOrder + 1, kPlus( idx_kOrder ) ) ) {
292✔
278
                    idx_col                             = GlobalIndex( idx_lOrder + 1, kPlus( idx_kOrder ) );
212✔
279
                    _Ax( idx_row, unsigned( idx_col ) ) = 0.5 * FTilde( idx_lOrder + 1, std::abs( idx_kOrder ) + 1 );
212✔
280
                }
281
            }
282

283
            // flux matrix in direction y
284
            {
285
                if( idx_kOrder != 1 ) {
292✔
286
                    if( CheckIndex( idx_lOrder - 1, -kMinus( idx_kOrder ) ) ) {
256✔
287
                        idx_col                             = GlobalIndex( idx_lOrder - 1, -kMinus( idx_kOrder ) );
240✔
288
                        _Ay( idx_row, unsigned( idx_col ) ) = -0.5 * Sgn( idx_kOrder ) * CTilde( idx_lOrder - 1, std::abs( idx_kOrder ) - 1 );
240✔
289
                    }
290

291
                    if( CheckIndex( idx_lOrder + 1, -kMinus( idx_kOrder ) ) ) {
256✔
292
                        idx_col                             = GlobalIndex( idx_lOrder + 1, -kMinus( idx_kOrder ) );
184✔
293
                        _Ay( idx_row, unsigned( idx_col ) ) = 0.5 * Sgn( idx_kOrder ) * DTilde( idx_lOrder + 1, std::abs( idx_kOrder ) - 1 );
184✔
294
                    }
295
                }
296

297
                if( CheckIndex( idx_lOrder - 1, -kPlus( idx_kOrder ) ) ) {
292✔
298
                    idx_col                             = GlobalIndex( idx_lOrder - 1, -kPlus( idx_kOrder ) );
148✔
299
                    _Ay( idx_row, unsigned( idx_col ) ) = -0.5 * Sgn( idx_kOrder ) * ETilde( idx_lOrder - 1, std::abs( idx_kOrder ) + 1 );
148✔
300
                }
301

302
                if( CheckIndex( idx_lOrder + 1, -kPlus( idx_kOrder ) ) ) {
292✔
303
                    idx_col                             = GlobalIndex( idx_lOrder + 1, -kPlus( idx_kOrder ) );
212✔
304
                    _Ay( idx_row, unsigned( idx_col ) ) = 0.5 * Sgn( idx_kOrder ) * FTilde( idx_lOrder + 1, std::abs( idx_kOrder ) + 1 );
212✔
305
                }
306
            }
307

308
            // flux matrix in direction z
309
            {
310
                if( CheckIndex( idx_lOrder - 1, idx_kOrder ) ) {
292✔
311
                    idx_col                             = GlobalIndex( idx_lOrder - 1, idx_kOrder );
212✔
312
                    _Az( idx_row, unsigned( idx_col ) ) = AParam( idx_lOrder - 1, idx_kOrder );
212✔
313
                }
314

315
                if( CheckIndex( idx_lOrder + 1, idx_kOrder ) ) {
292✔
316
                    idx_col                             = GlobalIndex( idx_lOrder + 1, idx_kOrder );
212✔
317
                    _Az( idx_row, unsigned( idx_col ) ) = BParam( idx_lOrder + 1, idx_kOrder );
212✔
318
                }
319
            }
320
        }
321
    }
322
}
8✔
323

324
void PNSolver::ComputeFluxComponents() {
8✔
325
    Vector eigenValues( _nSystem, 0 );
16✔
326
    Vector eigenValuesX( _nSystem, 0 );
16✔
327
    Vector eigenValuesY( _nSystem, 0 );
16✔
328

329
    MatrixCol eigenVectors( _nSystem, _nSystem, 0 );    // ColumnMatrix for _AxPlus * eigenVectors Multiplication via SIMD
8✔
330
    // --- For x Direction ---
331
    {
332
        blaze::eigen( _Ax, eigenValues, eigenVectors );    // Compute Eigenvalues and Eigenvectors
8✔
333

334
        // Compute Flux Matrices A+ and A-
335
        for( unsigned idx_ij = 0; idx_ij < _nSystem; idx_ij++ ) {
300✔
336
            if( eigenValues[idx_ij] >= 0 ) {
292✔
337
                _AxPlus( idx_ij, idx_ij ) = eigenValues[idx_ij];    // positive part of Diagonal Matrix stored in _AxPlus
148✔
338
                _AxAbs( idx_ij, idx_ij )  = eigenValues[idx_ij];
148✔
339
            }
340
            else {
341
                _AxMinus( idx_ij, idx_ij ) = eigenValues[idx_ij];    // negative part of Diagonal Matrix stored in _AxMinus
144✔
342
                _AxAbs( idx_ij, idx_ij )   = -eigenValues[idx_ij];
144✔
343
            }
344
        }
345

346
        _AxPlus  = eigenVectors * _AxPlus;    // col*row minimum performance
8✔
347
        _AxMinus = eigenVectors * _AxMinus;
8✔
348
        _AxAbs   = eigenVectors * _AxAbs;
8✔
349
        blaze::transpose( eigenVectors );
350
        _AxPlus  = _AxPlus * eigenVectors;    // row*col maximum performance
8✔
351
        _AxMinus = _AxMinus * eigenVectors;
8✔
352
        _AxAbs   = _AxAbs * eigenVectors;
8✔
353

354
        // eigenValuesX = eigenValues;
355
    }
356
    // --- For y Direction -------
357
    {
358
        blaze::eigen( _Ay, eigenValues, eigenVectors );    // Compute Eigenvalues and Eigenvectors
8✔
359

360
        // Compute Flux Matrices A+ and A-
361
        for( unsigned idx_ij = 0; idx_ij < _nSystem; idx_ij++ ) {
300✔
362
            if( eigenValues[idx_ij] >= 0 ) {
292✔
363
                _AyPlus( idx_ij, idx_ij ) = eigenValues[idx_ij];    // positive part of Diagonal Matrix stored in _AxPlus
152✔
364
                _AyAbs( idx_ij, idx_ij )  = eigenValues[idx_ij];
152✔
365
            }
366
            else {
367
                _AyMinus( idx_ij, idx_ij ) = eigenValues[idx_ij];    // negative part of Diagonal Matrix stored in _AxMinus
140✔
368
                _AyAbs( idx_ij, idx_ij )   = -eigenValues[idx_ij];
140✔
369
            }
370
        }
371

372
        _AyPlus  = eigenVectors * _AyPlus;
8✔
373
        _AyMinus = eigenVectors * _AyMinus;
8✔
374
        _AyAbs   = eigenVectors * _AyAbs;
8✔
375
        blaze::transpose( eigenVectors );
376
        _AyPlus  = _AyPlus * eigenVectors;
8✔
377
        _AyMinus = _AyMinus * eigenVectors;
8✔
378
        _AyAbs   = _AyAbs * eigenVectors;
8✔
379

380
        // eigenValuesY = eigenValues;
381
    }
382
    // --- For z Direction -------
383
    {
384
        blaze::eigen( _Az, eigenValues, eigenVectors );    // Compute Eigenvalues and Eigenvectors
8✔
385

386
        // Compute Flux Matrices A+ and A-
387
        for( unsigned idx_ij = 0; idx_ij < _nSystem; idx_ij++ ) {
300✔
388
            if( eigenValues[idx_ij] >= 0 ) {
292✔
389
                _AzPlus( idx_ij, idx_ij ) = eigenValues[idx_ij];    // positive part of Diagonal Matrix stored in _AxPlus
156✔
390
                _AzAbs( idx_ij, idx_ij )  = eigenValues[idx_ij];
156✔
391
            }
392
            else {
393
                _AzMinus( idx_ij, idx_ij ) = eigenValues[idx_ij];    // negative part of Diagonal Matrix stored in _AxMinus
136✔
394
                _AzAbs( idx_ij, idx_ij )   = -eigenValues[idx_ij];
136✔
395
            }
396
        }
397

398
        _AzPlus  = eigenVectors * _AzPlus;
8✔
399
        _AzMinus = eigenVectors * _AzMinus;
8✔
400
        _AzAbs   = eigenVectors * _AzAbs;
8✔
401
        blaze::transpose( eigenVectors );
402
        _AzPlus  = _AzPlus * eigenVectors;
8✔
403
        _AzMinus = _AzMinus * eigenVectors;
8✔
404
        _AzAbs   = _AzAbs * eigenVectors;
8✔
405
    }
406

407
    // Compute Spectral Radius
408
    // std::cout << "Eigenvalues x direction " << eigenValuesX << "\n";
409
    // std::cout << "Eigenvalues y direction " << eigenValuesY << "\n";
410
    // std::cout << "Eigenvalues z direction " << eigenValues << "\n";
411
    //
412
    // std::cout << "Spectral Radius X " << blaze::max( blaze::abs( eigenValuesX ) ) << "\n";
413
    // std::cout << "Spectral Radius Y " << blaze::max( blaze::abs( eigenValuesY ) ) << "\n";
414
    // std::cout << "Spectral Radius Z " << blaze::max( blaze::abs( eigenValues ) ) << "\n";
415

416
    //_combinedSpectralRadius = blaze::max( blaze::abs( eigenValues + eigenValuesX + eigenValuesY ) );
417
    // std::cout << "Spectral Radius combined " << blaze::max( blaze::abs( eigenValues + eigenValuesX + eigenValuesY ) ) << "\n";
418
}
8✔
419

420
void PNSolver::ComputeScatterMatrix() {
8✔
421

422
    // --- Isotropic ---
423
    _scatterMatDiag[0] = -1;
8✔
424
    for( unsigned idx_diag = 1; idx_diag < _nSystem; idx_diag++ ) {
292✔
425
        _scatterMatDiag[idx_diag] = 0.0;
284✔
426
    }
427
}
8✔
428

429
double PNSolver::LegendrePoly( double x, int l ) {    // Legacy. TO BE DELETED
×
430
    // Pre computed low order polynomials for faster computation
431
    switch( l ) {
×
432
        case 0: return 1;
×
433
        case 1: return x;
×
434
        case 2:    // 0.5*(3*x*x - 1)
×
435
            return 1.5 * x * x - 0.5;
×
436
        case 3:    // 0.5* (5*x*x*x -3 *x)
×
437
            return 2.5 * x * x * x - 1.5 * x;
×
438
        case 4:    // 1/8*(35x^4-30x^2 + 3)
×
439
            return 4.375 * x * x * x * x - 3.75 * x * x + 0.375;
×
440
        case 5:    // 1/8(63x^5-70x^3 + 15*x )
×
441
            return 7.875 * x * x * x * x * x - 8.75 * x * x * x + 1.875 * x;
×
442
        case 6:    // 1/16(231x^6-315x^4+105x^2-5)
×
443
            return 14.4375 * x * x * x * x * x * x - 19.6875 * x * x * x * x + 6.5625 * x * x - 3.125;
×
444
        default: ErrorMessages::Error( "Legendre Polynomials only implemented up to order 6", CURRENT_FUNCTION ); return 0;
×
445
    }
446
}
447

448
void PNSolver::PrepareVolumeOutput() {
4✔
449
    unsigned nGroups = (unsigned)_settings->GetNVolumeOutput();
4✔
450

451
    _outputFieldNames.resize( nGroups );
4✔
452
    _outputFields.resize( nGroups );
4✔
453

454
    // Prepare all OutputGroups ==> Specified in option VOLUME_OUTPUT
455
    for( unsigned idx_group = 0; idx_group < nGroups; idx_group++ ) {
8✔
456
        // Prepare all Output Fields per group
457

458
        // Different procedure, depending on the Group...
459
        switch( _settings->GetVolumeOutput()[idx_group] ) {
4✔
460
            case MINIMAL:
4✔
461
                // Currently only one entry ==> rad flux
462
                _outputFields[idx_group].resize( 1 );
4✔
463
                _outputFieldNames[idx_group].resize( 1 );
4✔
464

465
                _outputFields[idx_group][0].resize( _nCells );
4✔
466
                _outputFieldNames[idx_group][0] = "radiation flux density";
4✔
467
                break;
4✔
468

469
            case MOMENTS:
×
470
                // As many entries as there are moments in the system
471
                _outputFields[idx_group].resize( _nSystem );
×
472
                _outputFieldNames[idx_group].resize( _nSystem );
×
473

474
                for( int idx_l = 0; idx_l <= (int)_polyDegreeBasis; idx_l++ ) {
×
475
                    for( int idx_k = -idx_l; idx_k <= idx_l; idx_k++ ) {
×
476
                        _outputFields[idx_group][GlobalIndex( idx_l, idx_k )].resize( _nCells );
×
477

478
                        _outputFieldNames[idx_group][GlobalIndex( idx_l, idx_k )] =
×
479
                            std::string( "u_" + std::to_string( idx_l ) + "^" + std::to_string( idx_k ) );
×
480
                    }
481
                }
482
                break;
×
483
            case ANALYTIC:
×
484
                // one entry per cell
485
                _outputFields[idx_group].resize( 1 );
×
486
                _outputFieldNames[idx_group].resize( 1 );
×
487
                _outputFields[idx_group][0].resize( _nCells );
×
488
                _outputFieldNames[idx_group][0] = std::string( "analytic radiation flux density" );
×
489
                break;
×
490
            default: ErrorMessages::Error( "Volume Output Group not defined for PN Solver!", CURRENT_FUNCTION ); break;
×
491
        }
492
    }
493
}
4✔
494

495
void PNSolver::WriteVolumeOutput( unsigned idx_iter ) {
16✔
496
    unsigned nGroups = (unsigned)_settings->GetNVolumeOutput();
16✔
497

498
    if( ( _settings->GetVolumeOutputFrequency() != 0 && idx_iter % (unsigned)_settings->GetVolumeOutputFrequency() == 0 ) ||
32✔
499
        ( idx_iter == _nEnergies - 1 ) /* need sol at last iteration */ ) {
16✔
500
        for( unsigned idx_group = 0; idx_group < nGroups; idx_group++ ) {
8✔
501
            switch( _settings->GetVolumeOutput()[idx_group] ) {
4✔
502
                case MINIMAL:
4✔
503
                    for( unsigned idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
2,308✔
504
                        _outputFields[idx_group][0][idx_cell] = _scalarFluxNew[idx_cell];
2,304✔
505
                    }
506
                    break;
4✔
507
                case MOMENTS:
×
508
                    for( unsigned idx_sys = 0; idx_sys < _nSystem; idx_sys++ ) {
×
509
                        for( unsigned idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
×
510
                            _outputFields[idx_group][idx_sys][idx_cell] = _sol[idx_cell][idx_sys];
×
511
                        }
512
                    }
513
                    break;
×
514
                case ANALYTIC:
×
515
                    for( unsigned idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
×
516

NEW
517
                        double time = idx_iter * _dT;
×
518

519
                        _outputFields[idx_group][0][idx_cell] = _outputFields[idx_group][0][idx_cell] = _problem->GetAnalyticalSolution(
×
520
                            _mesh->GetCellMidPoints()[idx_cell][0], _mesh->GetCellMidPoints()[idx_cell][1], time, _sigmaS[idx_iter][idx_cell] );
×
521
                    }
522
                    break;
×
523

524
                default: ErrorMessages::Error( "Volume Output Group not defined for PN Solver!", CURRENT_FUNCTION ); break;
×
525
            }
526
        }
527
    }
528
}
16✔
529

530
void PNSolver::CleanFluxMatrices() {
×
531
    for( unsigned idx_row = 0; idx_row < _nSystem; idx_row++ ) {
×
532
        for( unsigned idx_col = 0; idx_col < _nSystem; idx_col++ ) {
×
533
            if( std::abs( _AxAbs( idx_row, idx_col ) ) < 0.00000000001 ) _AxAbs( idx_row, idx_col ) = 0.0;
×
534
            if( std::abs( _AxPlus( idx_row, idx_col ) ) < 0.00000000001 ) _AxPlus( idx_row, idx_col ) = 0.0;
×
535
            if( std::abs( _AxMinus( idx_row, idx_col ) ) < 0.00000000001 ) _AxMinus( idx_row, idx_col ) = 0.0;
×
536

537
            if( std::abs( _AyAbs( idx_row, idx_col ) ) < 0.00000000001 ) _AyAbs( idx_row, idx_col ) = 0.0;
×
538
            if( std::abs( _AyPlus( idx_row, idx_col ) ) < 0.00000000001 ) _AyPlus( idx_row, idx_col ) = 0.0;
×
539
            if( std::abs( _AyMinus( idx_row, idx_col ) ) < 0.00000000001 ) _AyMinus( idx_row, idx_col ) = 0.0;
×
540

541
            if( std::abs( _AzAbs( idx_row, idx_col ) ) < 0.00000000001 ) _AzAbs( idx_row, idx_col ) = 0.0;
×
542
            if( std::abs( _AzPlus( idx_row, idx_col ) ) < 0.00000000001 ) _AzPlus( idx_row, idx_col ) = 0.0;
×
543
            if( std::abs( _AzMinus( idx_row, idx_col ) ) < 0.00000000001 ) _AzMinus( idx_row, idx_col ) = 0.0;
×
544
        }
545
    }
546
}
547

548
double PNSolver::CTilde( int l, int k ) const {
480✔
549
    if( k < 0 ) return 0.0;
480✔
550
    if( k == 0 )
424✔
551
        return std::sqrt( 2 ) * CParam( l, k );
72✔
552
    else
553
        return CParam( l, k );
352✔
554
}
555

556
double PNSolver::DTilde( int l, int k ) const {
368✔
557
    if( k < 0 ) return 0.0;
368✔
558
    if( k == 0 )
296✔
559
        return std::sqrt( 2 ) * DParam( l, k );
56✔
560
    else
561
        return DParam( l, k );
240✔
562
}
563

564
double PNSolver::ETilde( int l, int k ) const {
296✔
565
    if( k == 1 )
296✔
566
        return std::sqrt( 2 ) * EParam( l, k );
56✔
567
    else
568
        return EParam( l, k );
240✔
569
}
570

571
double PNSolver::FTilde( int l, int k ) const {
424✔
572
    if( k == 1 )
424✔
573
        return std::sqrt( 2 ) * FParam( l, k );
72✔
574
    else
575
        return FParam( l, k );
352✔
576
}
577

578
double PNSolver::AParam( int l, int k ) const {
212✔
579
    return std::sqrt( double( ( l - k + 1 ) * ( l + k + 1 ) ) / double( ( 2 * l + 3 ) * ( 2 * l + 1 ) ) );
212✔
580
}
581

582
double PNSolver::BParam( int l, int k ) const { return std::sqrt( double( ( l - k ) * ( l + k ) ) / double( ( ( 2 * l + 1 ) * ( 2 * l - 1 ) ) ) ); }
212✔
583

584
double PNSolver::CParam( int l, int k ) const {
424✔
585
    return std::sqrt( double( ( l + k + 1 ) * ( l + k + 2 ) ) / double( ( ( 2 * l + 3 ) * ( 2 * l + 1 ) ) ) );
424✔
586
}
587

588
double PNSolver::DParam( int l, int k ) const {
296✔
589
    return std::sqrt( double( ( l - k ) * ( l - k - 1 ) ) / double( ( ( 2 * l + 1 ) * ( 2 * l - 1 ) ) ) );
296✔
590
}
591

592
double PNSolver::EParam( int l, int k ) const {
296✔
593
    return std::sqrt( double( ( l - k + 1 ) * ( l - k + 2 ) ) / double( ( ( 2 * l + 3 ) * ( 2 * l + 1 ) ) ) );
296✔
594
}
595

596
double PNSolver::FParam( int l, int k ) const { return std::sqrt( double( ( l + k ) * ( l + k - 1 ) ) / double( ( 2 * l + 1 ) * ( 2 * l - 1 ) ) ); }
424✔
597

598
int PNSolver::kPlus( int k ) const { return k + Sgn( k ); }
1,888✔
599

600
int PNSolver::kMinus( int k ) const { return k - Sgn( k ); }
1,872✔
601

602
int PNSolver::GlobalIndex( int l, int k ) const {
3,614,964✔
603
    int numIndicesPrevLevel  = l * l;    // number of previous indices untill level l-1
3,614,964✔
604
    int prevIndicesThisLevel = k + l;    // number of previous indices in current level
3,614,964✔
605
    return numIndicesPrevLevel + prevIndicesThisLevel;
3,614,964✔
606
}
607

608
bool PNSolver::CheckIndex( int l, int k ) const {
2,776✔
609
    if( l >= 0 && l <= int( _polyDegreeBasis ) ) {
2,776✔
610
        if( k >= -l && k <= l ) return true;
2,352✔
611
    }
612
    return false;
784✔
613
}
614

615
int PNSolver::Sgn( int k ) const {
4,544✔
616
    if( k >= 0 )
4,544✔
617
        return 1;
2,608✔
618
    else
619
        return -1;
1,936✔
620
}
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