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

CSMMLab / KiT-RT / #143

27 Mar 2026 04:08PM UTC coverage: 57.14% (-0.03%) from 57.168%
#143

push

travis-ci

web-flow
Merge b308cf063 into 3bfa2c39b

21 of 37 new or added lines in 2 files covered. (56.76%)

19 existing lines in 2 files now uncovered.

5474 of 9580 relevant lines covered (57.14%)

31176.1 hits per line

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

83.57
/src/solvers/snsolver_hpc.cpp
1
#ifdef IMPORT_MPI
2
#include <mpi.h>
3
#endif
4
#include "common/config.hpp"
5
#include "common/io.hpp"
6
#include "common/mesh.hpp"
7
#include "kernels/scatteringkernelbase.hpp"
8
#include "problems/problembase.hpp"
9
#include "quadratures/quadraturebase.hpp"
10
#include "solvers/snsolver_hpc.hpp"
11
#include "toolboxes/textprocessingtoolbox.hpp"
12
#include <cassert>
13

14
SNSolverHPC::SNSolverHPC( Config* settings ) {
2✔
15
#ifdef IMPORT_MPI
16
    // Initialize MPI
17
    MPI_Comm_size( MPI_COMM_WORLD, &_numProcs );
18
    MPI_Comm_rank( MPI_COMM_WORLD, &_rank );
19
#endif
20
#ifndef IMPORT_MPI
21
    _numProcs = 1;    // default values
2✔
22
    _rank     = 0;
2✔
23
#endif
24
    _settings       = settings;
2✔
25
    _currTime       = 0.0;
2✔
26
    _idx_start_iter = 0;
2✔
27
    _nOutputMoments = 2;    //  Currently only u_1 (x direction) and u_1 (y direction) are supported
2✔
28
    // Create Mesh
29
    _mesh = LoadSU2MeshFromFile( settings );
2✔
30
    _settings->SetNCells( _mesh->GetNumCells() );
2✔
31
    auto quad = QuadratureBase::Create( settings );
2✔
32
    _settings->SetNQuadPoints( quad->GetNq() );
2✔
33

34
    _nCells = static_cast<unsigned long>( _mesh->GetNumCells() );
2✔
35
    _nNbr   = static_cast<unsigned long>( _mesh->GetNumNodesPerCell() );
2✔
36
    _nDim   = static_cast<unsigned long>( _mesh->GetDim() );
2✔
37
    _nNodes = static_cast<unsigned long>( _mesh->GetNumNodes() );
2✔
38

39
    _nq   = static_cast<unsigned long>( quad->GetNq() );
2✔
40
    _nSys = _nq;
2✔
41

42
    if( static_cast<unsigned long>( _numProcs ) > _nq ) {
2✔
43
        ErrorMessages::Error( "The number of processors must be less than or equal to the number of quadrature points.", CURRENT_FUNCTION );
×
44
    }
45

46
    if( _numProcs == 1 ) {
2✔
47
        _localNSys   = _nSys;
2✔
48
        _startSysIdx = 0;
2✔
49
        _endSysIdx   = _nSys;
2✔
50
    }
51
    else {
52
        _localNSys   = _nSys / ( _numProcs - 1 );
×
53
        _startSysIdx = _rank * _localNSys;
×
54
        _endSysIdx   = _rank * _localNSys + _localNSys;
×
55

56
        if( _rank == _numProcs - 1 ) {
×
57
            _localNSys = _nSys - _startSysIdx;
×
58
            _endSysIdx = _nSys;
×
59
        }
60
    }
61

62
    // std::cout << "Rank: " << _rank << " startSysIdx: " << _startSysIdx << " endSysIdx: " << _endSysIdx <<  " localNSys: " << _localNSys <<
63
    // std::endl;
64

65
    _spatialOrder  = _settings->GetSpatialOrder();
2✔
66
    _temporalOrder = _settings->GetTemporalOrder();
2✔
67

68
    _areas                  = std::vector<double>( _nCells );
2✔
69
    _normals                = std::vector<double>( _nCells * _nNbr * _nDim );
2✔
70
    _neighbors              = std::vector<unsigned>( _nCells * _nNbr );
2✔
71
    _cellMidPoints          = std::vector<double>( _nCells * _nDim );
2✔
72
    _interfaceMidPoints     = std::vector<double>( _nCells * _nNbr * _nDim );
2✔
73
    _cellBoundaryTypes      = std::vector<BOUNDARY_TYPE>( _nCells );
2✔
74
    _relativeInterfaceMidPt = std::vector<double>( _nCells * _nNbr * _nDim );
2✔
75
    _relativeCellVertices   = std::vector<double>( _nCells * _nNbr * _nDim );
2✔
76

77
    // Slope
78
    _solDx   = std::vector<double>( _nCells * _localNSys * _nDim, 0.0 );
2✔
79
    _limiter = std::vector<double>( _nCells * _localNSys, 0.0 );
2✔
80

81
    // Physics
82
    _sigmaS = std::vector<double>( _nCells );
2✔
83
    _sigmaT = std::vector<double>( _nCells );
2✔
84
    _source = std::vector<double>( _nCells * _localNSys );
2✔
85

86
    // Quadrature
87
    _quadPts     = std::vector<double>( _localNSys * _nDim );
2✔
88
    _quadWeights = std::vector<double>( _localNSys );
2✔
89

90
    // Solution
91
    _sol  = std::vector<double>( _nCells * _localNSys );
2✔
92
    _flux = std::vector<double>( _nCells * _localNSys );
2✔
93

94
    _scalarFlux              = std::vector<double>( _nCells );
2✔
95
    _scalarFluxPrevIter      = std::vector<double>( _nCells );
2✔
96
    _localMaxOrdinateOutflow = std::vector<double>( _nCells );
2✔
97

98
    auto areas           = _mesh->GetCellAreas();
4✔
99
    auto neighbors       = _mesh->GetNeighbours();
4✔
100
    auto normals         = _mesh->GetNormals();
4✔
101
    auto cellMidPts      = _mesh->GetCellMidPoints();
4✔
102
    auto interfaceMidPts = _mesh->GetInterfaceMidPoints();
4✔
103
    auto boundaryTypes   = _mesh->GetBoundaryTypes();
4✔
104
    auto nodes           = _mesh->GetNodes();
4✔
105
    auto cells           = _mesh->GetCells();
4✔
106

107
#pragma omp parallel for
2✔
108
    for( unsigned long idx_cell = 0; idx_cell < _nCells; idx_cell++ ) {
109
        _areas[idx_cell] = areas[idx_cell];
110
    }
111

112
    _dT    = ComputeTimeStep( _settings->GetCFL() );
2✔
113
    _nIter = unsigned( _settings->GetTEnd() / _dT ) + 1;
2✔
114

115
    auto quadPoints  = quad->GetPoints();
4✔
116
    auto quadWeights = quad->GetWeights();
4✔
117

118
    _problem    = ProblemBase::Create( _settings, _mesh, quad );
2✔
119
    auto sigmaT = _problem->GetTotalXS( Vector( _nIter, 0.0 ) );
4✔
120
    auto sigmaS = _problem->GetScatteringXS( Vector( _nIter, 0.0 ) );
4✔
121
    auto source = _problem->GetExternalSource( Vector( _nIter, 0.0 ) );
4✔
122

123
    // Copy to everything to solver
124
    _mass = 0;
2✔
125
#pragma omp parallel for
2✔
126
    for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
127
        for( unsigned long idx_dim = 0; idx_dim < _nDim; idx_dim++ ) {
128
            _quadPts[Idx2D( idx_sys, idx_dim, _nDim )] = quadPoints[idx_sys + _startSysIdx][idx_dim];
129
        }
130
        if( _settings->GetQuadName() == QUAD_GaussLegendreTensorized2D ) {
131
            _quadWeights[idx_sys] =
132
                2.0 * quadWeights[idx_sys + _startSysIdx];    // Rescaling of quadweights TODO: Check if this needs general refactoring
133
        }
134
        else {
135
            _quadWeights[idx_sys] = quadWeights[idx_sys + _startSysIdx];    // Rescaling of quadweights TODO: Check if this needs general refactoring}
136
        }
137
    }
138

139
#pragma omp parallel for
2✔
140
    for( unsigned long idx_cell = 0; idx_cell < _nCells; idx_cell++ ) {
141
        _cellBoundaryTypes[idx_cell] = boundaryTypes[idx_cell];
142

143
        for( unsigned long idx_dim = 0; idx_dim < _nDim; idx_dim++ ) {
144
            _cellMidPoints[Idx2D( idx_cell, idx_dim, _nDim )] = cellMidPts[idx_cell][idx_dim];
145
        }
146

147
        for( unsigned long idx_nbr = 0; idx_nbr < _nNbr; idx_nbr++ ) {
148

149
            _neighbors[Idx2D( idx_cell, idx_nbr, _nNbr )] = neighbors[idx_cell][idx_nbr];
150

151
            for( unsigned long idx_dim = 0; idx_dim < _nDim; idx_dim++ ) {
152
                _normals[Idx3D( idx_cell, idx_nbr, idx_dim, _nNbr, _nDim )]            = normals[idx_cell][idx_nbr][idx_dim];
153
                _interfaceMidPoints[Idx3D( idx_cell, idx_nbr, idx_dim, _nNbr, _nDim )] = interfaceMidPts[idx_cell][idx_nbr][idx_dim];
154
                _relativeInterfaceMidPt[Idx3D( idx_cell, idx_nbr, idx_dim, _nNbr, _nDim )] =
155
                    _interfaceMidPoints[Idx3D( idx_cell, idx_nbr, idx_dim, _nNbr, _nDim )] - _cellMidPoints[Idx2D( idx_cell, idx_dim, _nDim )];
156
                _relativeCellVertices[Idx3D( idx_cell, idx_nbr, idx_dim, _nNbr, _nDim )] =
157
                    nodes[cells[idx_cell][idx_nbr]][idx_dim] - cellMidPts[idx_cell][idx_dim];
158
            }
159
        }
160

161
        _sigmaS[idx_cell]     = sigmaS[0][idx_cell];
162
        _sigmaT[idx_cell]     = sigmaT[0][idx_cell];
163
        _scalarFlux[idx_cell] = 0;
164

165
        for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
166
            _source[Idx2D( idx_cell, idx_sys, _localNSys )] = source[0][idx_cell][0];    // CAREFUL HERE hardcoded to isotropic source
167
            _sol[Idx2D( idx_cell, idx_sys, _localNSys )]    = 0.0;                       // initial condition is zero
168

169
            _scalarFlux[idx_cell] += _sol[Idx2D( idx_cell, idx_sys, _localNSys )] * _quadWeights[idx_sys];
170
        }
171
    }
172

173
    // Lattice
174
    {
175
        _curAbsorptionLattice    = 0;
2✔
176
        _totalAbsorptionLattice  = 0;
2✔
177
        _curMaxAbsorptionLattice = 0;
2✔
178
        _curScalarOutflow        = 0;
2✔
179
        _totalScalarOutflow      = 0;
2✔
180
        _curMaxOrdinateOutflow   = 0;
2✔
181
        _curScalarOutflowPeri1   = 0;
2✔
182
        _totalScalarOutflowPeri1 = 0;
2✔
183
        _curScalarOutflowPeri2   = 0;
2✔
184
        _totalScalarOutflowPeri2 = 0;
2✔
185
        ComputeCellsPerimeterLattice();
2✔
186
    }
187
    // Hohlraum
188
    {
189
        _totalAbsorptionHohlraumCenter     = 0;
2✔
190
        _totalAbsorptionHohlraumVertical   = 0;
2✔
191
        _totalAbsorptionHohlraumHorizontal = 0;
2✔
192
        _curAbsorptionHohlraumCenter       = 0;
2✔
193
        _curAbsorptionHohlraumVertical     = 0;
2✔
194
        _curAbsorptionHohlraumHorizontal   = 0;
2✔
195
        _varAbsorptionHohlraumGreen        = 0;
2✔
196
        _avgAbsorptionHohlraumGreenBlockIntegrated = 0;
2✔
197
        _varAbsorptionHohlraumGreenBlockIntegrated = 0;
2✔
198
    }
199

200
    if( _settings->GetLoadRestartSolution() )
2✔
201
        _idx_start_iter = LoadRestartSolution( _settings->GetOutputFile(),
×
202
                                               _sol,
×
203
                                               _scalarFlux,
×
204
                                               _rank,
205
                                               _nCells,
206
                                               _totalAbsorptionHohlraumCenter,
×
207
                                               _totalAbsorptionHohlraumVertical,
×
208
                                               _totalAbsorptionHohlraumHorizontal,
×
209
                                               _totalAbsorptionLattice ) +
×
210
                          1;
211

212
#ifdef IMPORT_MPI
213
    MPI_Barrier( MPI_COMM_WORLD );
214
#endif
215
    SetGhostCells();
2✔
216
    if( _rank == 0 ) {
2✔
217
        PrepareScreenOutput();     // Screen Output
2✔
218
        PrepareHistoryOutput();    // History Output
2✔
219
    }
220
#ifdef IMPORT_MPI
221
    MPI_Barrier( MPI_COMM_WORLD );
222
#endif
223
    delete quad;
2✔
224

225
    // Initialiye QOIS
226
    _mass    = 0;
2✔
227
    _rmsFlux = 0;
2✔
228

229
    {    // Hohlraum
230

231
        unsigned n_probes = 4;
2✔
232
        if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) n_probes = 4;
2✔
233
        // if( _settings->GetProblemName() == PROBLEM_QuarterHohlraum ) n_probes = 2;
234

235
        _probingMoments = std::vector<double>( n_probes * 3, 0. );    // 10 time horizons
2✔
236

237
        if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) {
2✔
238
            _probingCellsHohlraum = {
5✔
239
                _mesh->GetCellsofBall( -0.4, 0., 0.01 ),
1✔
240
                _mesh->GetCellsofBall( 0.4, 0., 0.01 ),
1✔
241
                _mesh->GetCellsofBall( 0., -0.5, 0.01 ),
1✔
242
                _mesh->GetCellsofBall( 0., 0.5, 0.01 ),
1✔
243
            };
5✔
244
        }
245
        // else if( _settings->GetProblemName() == PROBLEM_QuarterHohlraum ) {
246
        //     _probingCellsHohlraum = {
247
        //         _mesh->GetCellsofBall( 0.4, 0., 0.01 ),
248
        //         _mesh->GetCellsofBall( 0., 0.5, 0.01 ),
249
        //     };
250
        // }
251

252
        // Green
253
        _thicknessGreen = 0.05;
2✔
254

255
        if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) {
2✔
256
            _centerGreen           = { _settings->GetPosXCenterGreenHohlraum(), _settings->GetPosYCenterGreenHohlraum() };
1✔
257
            _cornerUpperLeftGreen  = { -0.2 + _centerGreen[0], 0.4 + _centerGreen[1] };
1✔
258
            _cornerLowerLeftGreen  = { -0.2 + _centerGreen[0], -0.4 + _centerGreen[1] };
1✔
259
            _cornerUpperRightGreen = { 0.2 + _centerGreen[0], 0.4 + _centerGreen[1] };
1✔
260
            _cornerLowerRightGreen = { 0.2 + _centerGreen[0], -0.4 + _centerGreen[1] };
1✔
261
        }
262
        // else {
263
        //     _centerGreen           = { 0.0, 0.0 };
264
        //     _cornerUpperLeftGreen  = { 0., 0.4 - _thicknessGreen / 2.0 };
265
        //     _cornerLowerLeftGreen  = { 0., +_thicknessGreen / 2.0 };
266
        //     _cornerUpperRightGreen = { 0.2 - _thicknessGreen / 2.0, 0.4 - _thicknessGreen / 2.0 };
267
        //     _cornerLowerRightGreen = { 0.2 - _thicknessGreen / 2.0, 0. + _thicknessGreen / 2.0 };
268
        // }
269

270
        _nProbingCellsLineGreen = _settings->GetNumProbingCellsLineHohlraum();
2✔
271

272
        _nProbingCellsBlocksGreen           = 44;
2✔
273
        _absorptionValsBlocksGreen          = std::vector<double>( _nProbingCellsBlocksGreen, 0. );
2✔
274
        _absorptionValsBlocksGreenIntegrated = std::vector<double>( _nProbingCellsBlocksGreen, 0. );
2✔
275
        _absorptionValsLineSegment          = std::vector<double>( _nProbingCellsLineGreen, 0.0 );
2✔
276

277
        SetProbingCellsLineGreen();    // ONLY FOR HOHLRAUM
2✔
278
    }
279
}
2✔
280

281
SNSolverHPC::~SNSolverHPC() {
2✔
282
    delete _mesh;
2✔
283
    delete _problem;
2✔
284
}
2✔
285

286
void SNSolverHPC::Solve() {
2✔
287

288
    // --- Preprocessing ---
289
    if( _rank == 0 ) {
2✔
290
        PrepareVolumeOutput();
2✔
291
        DrawPreSolverOutput();
2✔
292
    }
293
    // On restart, continue simulation time from the loaded iteration index.
294
    _curSimTime = static_cast<double>( _idx_start_iter ) * _dT;
2✔
295
    auto start  = std::chrono::high_resolution_clock::now();    // Start timing
2✔
296

297
    std::chrono::duration<double> duration;
298
    // Loop over energies (pseudo-time of continuous slowing down approach)
299
    for( unsigned iter = (unsigned)_idx_start_iter; iter < _nIter; iter++ ) {
10✔
300

301
        if( iter == _nIter - 1 ) {    // last iteration
8✔
302
            _dT = _settings->GetTEnd() - iter * _dT;
2✔
303
        }
304
        _scalarFluxPrevIter = _scalarFlux;
8✔
305
        if( _temporalOrder == 2 ) {
8✔
306
            std::vector<double> solRK0( _sol );
16✔
307
            ( _spatialOrder == 2 ) ? FluxOrder2() : FluxOrder1();
8✔
308
            FVMUpdate();
8✔
309
            ( _spatialOrder == 2 ) ? FluxOrder2() : FluxOrder1();
8✔
310
            FVMUpdate();
8✔
311
#pragma omp parallel for
8✔
312
            for( unsigned long idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
313
#pragma omp simd
314
                for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
315
                    _sol[Idx2D( idx_cell, idx_sys, _localNSys )] =
316
                        0.5 * ( solRK0[Idx2D( idx_cell, idx_sys, _localNSys )] +
317
                                _sol[Idx2D( idx_cell, idx_sys, _localNSys )] );    // Solution averaging with HEUN
318
                }
319
            }
320

321
            // Keep scalar flux consistent with the final RK2-averaged solution used in postprocessing.
322
            std::vector<double> temp_scalarFluxRK( _nCells, 0.0 );
16✔
323
#pragma omp parallel for
8✔
324
            for( unsigned long idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
325
                double localScalarFlux = 0.0;
326
#pragma omp simd reduction( + : localScalarFlux )
327
                for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
328
                    localScalarFlux += _sol[Idx2D( idx_cell, idx_sys, _localNSys )] * _quadWeights[idx_sys];
329
                }
330
                temp_scalarFluxRK[idx_cell] = localScalarFlux;
331
            }
332
#ifdef IMPORT_MPI
333
            MPI_Barrier( MPI_COMM_WORLD );
334
            MPI_Allreduce( temp_scalarFluxRK.data(), _scalarFlux.data(), _nCells, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
335
            MPI_Barrier( MPI_COMM_WORLD );
336
#else
337
            _scalarFlux = temp_scalarFluxRK;
8✔
338
#endif
339
        }
340
        else {
341

342
            ( _spatialOrder == 2 ) ? FluxOrder2() : FluxOrder1();
×
343
            FVMUpdate();
×
344
        }
345
        _curSimTime += _dT;
8✔
346
        IterPostprocessing();
8✔
347
        // --- Wall time measurement
348
        duration  = std::chrono::high_resolution_clock::now() - start;
8✔
349
        _currTime = std::chrono::duration_cast<std::chrono::duration<double>>( duration ).count();
8✔
350

351
        // --- Write Output ---
352
        if( _rank == 0 ) {
8✔
353

354
            WriteScalarOutput( iter );
8✔
355

356
            // --- Update Scalar Fluxes
357

358
            // --- Print Output ---
359
            PrintScreenOutput( iter );
8✔
360
            PrintHistoryOutput( iter );
8✔
361
        }
362
#ifdef IMPORT_MPI
363
        MPI_Barrier( MPI_COMM_WORLD );
364
#endif
365

366
        PrintVolumeOutput( iter );
8✔
367
#ifdef IMPORT_MPI
368
        MPI_Barrier( MPI_COMM_WORLD );
369
#endif
370
    }
371
    // --- Postprocessing ---
372
    if( _rank == 0 ) {
2✔
373
        DrawPostSolverOutput();
2✔
374
    }
375
}
2✔
376

377
void SNSolverHPC::FluxOrder2() {
16✔
378

379
    double const eps = 1e-10;
16✔
380

381
#pragma omp parallel for
16✔
382
    for( unsigned long idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {            // Compute Slopes
383
        if( _cellBoundaryTypes[idx_cell] == BOUNDARY_TYPE::NONE ) {                // skip ghost cells
384
                                                                                   // #pragma omp simd
385
            for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {    //
386
                _limiter[Idx2D( idx_cell, idx_sys, _localNSys )]         = 1.;     // limiter should be zero at boundary//
387
                _solDx[Idx3D( idx_cell, idx_sys, 0, _localNSys, _nDim )] = 0.;
388
                _solDx[Idx3D( idx_cell, idx_sys, 1, _localNSys, _nDim )] = 0.;    //
389
                double solInterfaceAvg                                   = 0.0;
390
                for( unsigned long idx_nbr = 0; idx_nbr < _nNbr; ++idx_nbr ) {            // Compute slopes and mininum and maximum
391
                    unsigned nbr_glob = _neighbors[Idx2D( idx_cell, idx_nbr, _nNbr )];    //
392
                    // Slopes
393
                    solInterfaceAvg = 0.5 * ( _sol[Idx2D( idx_cell, idx_sys, _localNSys )] + _sol[Idx2D( nbr_glob, idx_sys, _localNSys )] );
394
                    _solDx[Idx3D( idx_cell, idx_sys, 0, _localNSys, _nDim )] +=
395
                        solInterfaceAvg * _normals[Idx3D( idx_cell, idx_nbr, 0, _nNbr, _nDim )];
396
                    _solDx[Idx3D( idx_cell, idx_sys, 1, _localNSys, _nDim )] +=
397
                        solInterfaceAvg * _normals[Idx3D( idx_cell, idx_nbr, 1, _nNbr, _nDim )];
398
                }    //
399
                _solDx[Idx3D( idx_cell, idx_sys, 0, _localNSys, _nDim )] /= _areas[idx_cell];
400
                _solDx[Idx3D( idx_cell, idx_sys, 1, _localNSys, _nDim )] /= _areas[idx_cell];
401
            }
402
        }
403
    }
404
#pragma omp parallel for
16✔
405
    for( unsigned long idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {    // Compute Limiter
406
        if( _cellBoundaryTypes[idx_cell] == BOUNDARY_TYPE::NONE ) {        // skip ghost cells
407

408
#pragma omp simd
409
            for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
410

411
                double gaussPoint = 0;
412
                double r          = 0;
413
                double minSol     = _sol[Idx2D( idx_cell, idx_sys, _localNSys )];
414
                double maxSol     = _sol[Idx2D( idx_cell, idx_sys, _localNSys )];
415

416
                for( unsigned long idx_nbr = 0; idx_nbr < _nNbr; ++idx_nbr ) {    // Compute slopes and mininum and maximum
417
                    unsigned nbr_glob = _neighbors[Idx2D( idx_cell, idx_nbr, _nNbr )];
418
                    // Compute ptswise max and minimum solultion values of current and neighbor cells
419
                    maxSol = std::max( _sol[Idx2D( nbr_glob, idx_sys, _localNSys )], maxSol );
420
                    minSol = std::min( _sol[Idx2D( nbr_glob, idx_sys, _localNSys )], minSol );
421
                }
422

423
                for( unsigned long idx_nbr = 0; idx_nbr < _nNbr; idx_nbr++ ) {    // Compute limiter, see https://arxiv.org/pdf/1710.07187.pdf
424

425
                    // Compute test value at cell vertex, called gaussPt
426
                    gaussPoint =
427
                        _solDx[Idx3D( idx_cell, idx_sys, 0, _localNSys, _nDim )] *
428
                            _relativeCellVertices[Idx3D( idx_cell, idx_nbr, 0, _nNbr, _nDim )] +
429
                        _solDx[Idx3D( idx_cell, idx_sys, 1, _localNSys, _nDim )] * _relativeCellVertices[Idx3D( idx_cell, idx_nbr, 1, _nNbr, _nDim )];
430

431
                    // BARTH-JESPERSEN LIMITER
432
                    // r = ( gaussPoint > 0 ) ? std::min( ( maxSol - _sol[Idx2D( idx_cell, idx_sys, _localNSys )] ) / ( gaussPoint + eps ), 1.0 )
433
                    //                       : std::min( ( minSol - _sol[Idx2D( idx_cell, idx_sys, _localNSys )] ) / ( gaussPoint - eps ), 1.0 );
434
                    //
435
                    // r = ( std::abs( gaussPoint ) < eps ) ? 1 : r;
436
                    //_limiter[Idx2D( idx_cell, idx_sys, _localNSys )] = std::min( r, _limiter[Idx2D( idx_cell, idx_sys, _localNSys )] );
437

438
                    // VENKATAKRISHNAN LIMITER
439
                    double delta1Max = maxSol - _sol[Idx2D( idx_cell, idx_sys, _localNSys )];
440
                    double delta1Min = minSol - _sol[Idx2D( idx_cell, idx_sys, _localNSys )];
441

442
                    r = ( gaussPoint > 0 ) ? ( ( delta1Max * delta1Max + _areas[idx_cell] ) * gaussPoint + 2 * gaussPoint * gaussPoint * delta1Max ) /
443
                                                 ( delta1Max * delta1Max + 2 * gaussPoint * gaussPoint + delta1Max * gaussPoint + _areas[idx_cell] ) /
444
                                                 ( gaussPoint + eps )
445
                                           : ( ( delta1Min * delta1Min + _areas[idx_cell] ) * gaussPoint + 2 * gaussPoint * gaussPoint * delta1Min ) /
446
                                                 ( delta1Min * delta1Min + 2 * gaussPoint * gaussPoint + delta1Min * gaussPoint + _areas[idx_cell] ) /
447
                                                 ( gaussPoint - eps );
448

449
                    r = ( std::abs( gaussPoint ) < eps ) ? 1 : r;
450

451
                    _limiter[Idx2D( idx_cell, idx_sys, _localNSys )] = std::min( r, _limiter[Idx2D( idx_cell, idx_sys, _localNSys )] );
452
                }
453
            }
454
        }
455
        else {
456
#pragma omp simd
457
            for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
458
                _limiter[Idx2D( idx_cell, idx_sys, _localNSys )]         = 0.;    // limiter should be zero at boundary
459
                _solDx[Idx3D( idx_cell, idx_sys, 0, _localNSys, _nDim )] = 0.;
460
                _solDx[Idx3D( idx_cell, idx_sys, 1, _localNSys, _nDim )] = 0.;
461
            }
462
        }
463
    }
464
#pragma omp parallel for
16✔
465
    for( unsigned long idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {    // Compute Flux
466
#pragma omp simd
467
        for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
468
            _flux[Idx2D( idx_cell, idx_sys, _localNSys )] = 0.;
469
        }
470

471
        // Fluxes
472
        for( unsigned long idx_nbr = 0; idx_nbr < _nNbr; ++idx_nbr ) {
473
            if( _cellBoundaryTypes[idx_cell] == BOUNDARY_TYPE::NEUMANN && _neighbors[Idx2D( idx_cell, idx_nbr, _nNbr )] == _nCells ) {
474
                // #pragma omp simd
475
                for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
476
                    double localInner = _quadPts[Idx2D( idx_sys, 0, _nDim )] * _normals[Idx3D( idx_cell, idx_nbr, 0, _nNbr, _nDim )] +
477
                                        _quadPts[Idx2D( idx_sys, 1, _nDim )] * _normals[Idx3D( idx_cell, idx_nbr, 1, _nNbr, _nDim )];
478
                    if( localInner > 0 ) {
479
                        _flux[Idx2D( idx_cell, idx_sys, _localNSys )] += localInner * _sol[Idx2D( idx_cell, idx_sys, _localNSys )];
480
                    }
481
                    else {
482
                        double ghostCellValue = _ghostCells[idx_cell][idx_sys];    // fixed boundary
483
                        _flux[Idx2D( idx_cell, idx_sys, _localNSys )] += localInner * ghostCellValue;
484
                    }
485
                }
486
            }
487
            else {
488

489
                unsigned long nbr_glob = _neighbors[Idx2D( idx_cell, idx_nbr, _nNbr )];    // global idx of neighbor cell
490
                                                                                           // Second order
491
#pragma omp simd
492
                for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
493
                    // store flux contribution on psiNew_sigmaS to save memory
494
                    double localInner = _quadPts[Idx2D( idx_sys, 0, _nDim )] * _normals[Idx3D( idx_cell, idx_nbr, 0, _nNbr, _nDim )] +
495
                                        _quadPts[Idx2D( idx_sys, 1, _nDim )] * _normals[Idx3D( idx_cell, idx_nbr, 1, _nNbr, _nDim )];
496

497
                    _flux[Idx2D( idx_cell, idx_sys, _localNSys )] +=
498
                        ( localInner > 0 ) ? localInner * ( _sol[Idx2D( idx_cell, idx_sys, _localNSys )] +
499
                                                            _limiter[Idx2D( idx_cell, idx_sys, _localNSys )] *
500
                                                                ( _solDx[Idx3D( idx_cell, idx_sys, 0, _localNSys, _nDim )] *
501
                                                                      _relativeInterfaceMidPt[Idx3D( idx_cell, idx_nbr, 0, _nNbr, _nDim )] +
502
                                                                  _solDx[Idx3D( idx_cell, idx_sys, 1, _localNSys, _nDim )] *
503
                                                                      _relativeInterfaceMidPt[Idx3D( idx_cell, idx_nbr, 1, _nNbr, _nDim )] ) )
504
                                           : localInner * ( _sol[Idx2D( nbr_glob, idx_sys, _localNSys )] +
505
                                                            _limiter[Idx2D( nbr_glob, idx_sys, _localNSys )] *
506
                                                                ( _solDx[Idx3D( nbr_glob, idx_sys, 0, _localNSys, _nDim )] *
507
                                                                      ( _interfaceMidPoints[Idx3D( idx_cell, idx_nbr, 0, _nNbr, _nDim )] -
508
                                                                        _cellMidPoints[Idx2D( nbr_glob, 0, _nDim )] ) +
509
                                                                  _solDx[Idx3D( nbr_glob, idx_sys, 1, _localNSys, _nDim )] *
510
                                                                      ( _interfaceMidPoints[Idx3D( idx_cell, idx_nbr, 1, _nNbr, _nDim )] -
511
                                                                        _cellMidPoints[Idx2D( nbr_glob, 1, _nDim )] ) ) );
512
                }
513
            }
514
        }
515
    }
516
}
16✔
517

518
void SNSolverHPC::FluxOrder1() {
×
519

520
#pragma omp parallel for
×
521
    for( unsigned long idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
522

523
#pragma omp simd
524
        for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
525
            _flux[Idx2D( idx_cell, idx_sys, _localNSys )] = 0.0;    // Reset temporary variable
526
        }
527

528
        // Fluxes
529
        for( unsigned long idx_nbr = 0; idx_nbr < _nNbr; ++idx_nbr ) {
530
            if( _cellBoundaryTypes[idx_cell] == BOUNDARY_TYPE::NEUMANN && _neighbors[Idx2D( idx_cell, idx_nbr, _nNbr )] == _nCells ) {
531
#pragma omp simd
532
                for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
533
                    double localInner = _quadPts[Idx2D( idx_sys, 0, _nDim )] * _normals[Idx3D( idx_cell, idx_nbr, 0, _nNbr, _nDim )] +
534
                                        _quadPts[Idx2D( idx_sys, 1, _nDim )] * _normals[Idx3D( idx_cell, idx_nbr, 1, _nNbr, _nDim )];
535
                    if( localInner > 0 ) {
536
                        _flux[Idx2D( idx_cell, idx_sys, _localNSys )] += localInner * _sol[Idx2D( idx_cell, idx_sys, _localNSys )];
537
                    }
538
                    else {
539
                        double ghostCellValue = _ghostCells[idx_cell][idx_sys];    // fixed boundary
540
                        _flux[Idx2D( idx_cell, idx_sys, _localNSys )] += localInner * ghostCellValue;
541
                    }
542
                }
543
            }
544
            else {
545
                unsigned long nbr_glob = _neighbors[Idx2D( idx_cell, idx_nbr, _nNbr )];    // global idx of neighbor cell
546
#pragma omp simd
547
                for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
548

549
                    double localInner = _quadPts[Idx2D( idx_sys, 0, _nDim )] * _normals[Idx3D( idx_cell, idx_nbr, 0, _nNbr, _nDim )] +
550
                                        _quadPts[Idx2D( idx_sys, 1, _nDim )] * _normals[Idx3D( idx_cell, idx_nbr, 1, _nNbr, _nDim )];
551

552
                    _flux[Idx2D( idx_cell, idx_sys, _localNSys )] += ( localInner > 0 ) ? localInner * _sol[Idx2D( idx_cell, idx_sys, _localNSys )]
553
                                                                                        : localInner * _sol[Idx2D( nbr_glob, idx_sys, _localNSys )];
554
                }
555
            }
556
        }
557
    }
558
}
559

560
void SNSolverHPC::FVMUpdate() {
16✔
561
    std::vector<double> temp_scalarFlux( _nCells );    // for MPI allreduce
32✔
562

563
#pragma omp parallel for
16✔
564
    for( unsigned long idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
565

566
#pragma omp simd
567
        for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
568
            // Update
569
            _sol[Idx2D( idx_cell, idx_sys, _localNSys )] =
570
                ( 1 - _dT * _sigmaT[idx_cell] ) * _sol[Idx2D( idx_cell, idx_sys, _localNSys )] -
571
                _dT / _areas[idx_cell] * _flux[Idx2D( idx_cell, idx_sys, _localNSys )] +
572
                _dT * ( _sigmaS[idx_cell] * _scalarFlux[idx_cell] / ( 2 * M_PI ) + _source[Idx2D( idx_cell, idx_sys, _localNSys )] );
573
        }
574
        double localScalarFlux = 0;
575

576
#pragma omp simd reduction( + : localScalarFlux )
577
        for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
578
            _sol[Idx2D( idx_cell, idx_sys, _localNSys )] = std::max( _sol[Idx2D( idx_cell, idx_sys, _localNSys )], 0.0 );
579
            localScalarFlux += _sol[Idx2D( idx_cell, idx_sys, _localNSys )] * _quadWeights[idx_sys];
580
        }
581
        temp_scalarFlux[idx_cell] = localScalarFlux;    // set flux
582
    }
583
// MPI Allreduce: _scalarFlux
584
#ifdef IMPORT_MPI
585
    MPI_Barrier( MPI_COMM_WORLD );
586
    MPI_Allreduce( temp_scalarFlux.data(), _scalarFlux.data(), _nCells, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
587
    MPI_Barrier( MPI_COMM_WORLD );
588
#endif
589
#ifndef IMPORT_MPI
590
    _scalarFlux = temp_scalarFlux;
16✔
591
#endif
592
}
16✔
593

594
void SNSolverHPC::IterPostprocessing() {
8✔
595
    // ALREDUCE NEEDED
596
    _mass    = 0.0;
8✔
597
    _rmsFlux = 0.0;
8✔
598
#pragma omp parallel for reduction( + : _mass, _rmsFlux )
8✔
599
    for( unsigned long idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
600
        _mass += _scalarFlux[idx_cell] * _areas[idx_cell];
601
        double diff = _scalarFlux[idx_cell] - _scalarFluxPrevIter[idx_cell];
602
        _rmsFlux += diff * diff;
603
    }
604

605
    _curAbsorptionLattice            = 0.0;
8✔
606
    _curScalarOutflow                = 0.0;
8✔
607
    _curScalarOutflowPeri1           = 0.0;
8✔
608
    _curScalarOutflowPeri2           = 0.0;
8✔
609
    _curAbsorptionHohlraumCenter     = 0.0;    // Green and blue areas of symmetric hohlraum
8✔
610
    _curAbsorptionHohlraumVertical   = 0.0;    // Red areas of symmetric hohlraum
8✔
611
    _curAbsorptionHohlraumHorizontal = 0.0;    // Black areas of symmetric hohlraum
8✔
612
    _varAbsorptionHohlraumGreen      = 0.0;
8✔
613
    double a_g                       = 0.0;
8✔
614

615
#pragma omp parallel for reduction( + : _curAbsorptionLattice,                                                                                       \
8✔
616
                                        _curScalarOutflow,                                                                                           \
617
                                        _curScalarOutflowPeri1,                                                                                      \
618
                                        _curScalarOutflowPeri2,                                                                                      \
619
                                        _curAbsorptionHohlraumCenter,                                                                                \
620
                                        _curAbsorptionHohlraumVertical,                                                                              \
621
                                        _curAbsorptionHohlraumHorizontal,                                                                            \
622
                                        a_g ) reduction( max : _curMaxOrdinateOutflow, _curMaxAbsorptionLattice )
8✔
623
    for( unsigned long idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
624

625
        if( _settings->GetProblemName() == PROBLEM_Lattice || _settings->GetProblemName() == PROBLEM_HalfLattice ) {
626
            if( IsAbsorptionLattice( _cellMidPoints[Idx2D( idx_cell, 0, _nDim )], _cellMidPoints[Idx2D( idx_cell, 1, _nDim )] ) ) {
627
                double sigmaAPsi = _scalarFlux[idx_cell] * ( _sigmaT[idx_cell] - _sigmaS[idx_cell] ) * _areas[idx_cell];
628
                _curAbsorptionLattice += sigmaAPsi;
629
                _curMaxAbsorptionLattice = ( _curMaxAbsorptionLattice < sigmaAPsi ) ? sigmaAPsi : _curMaxAbsorptionLattice;
630
            }
631
        }
632

633
        if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) {    //} || _settings->GetProblemName() == PROBLEM_QuarterHohlraum ) {
634

635
            double x = _cellMidPoints[Idx2D( idx_cell, 0, _nDim )];
636
            double y = _cellMidPoints[Idx2D( idx_cell, 1, _nDim )];
637
            _curAbsorptionLattice += _scalarFlux[idx_cell] * ( _sigmaT[idx_cell] - _sigmaS[idx_cell] ) * _areas[idx_cell];
638
            if( x > -0.2 + _settings->GetPosXCenterGreenHohlraum() && x < 0.2 + _settings->GetPosXCenterGreenHohlraum() &&
639
                y > -0.4 + _settings->GetPosYCenterGreenHohlraum() && y < 0.4 + _settings->GetPosYCenterGreenHohlraum() ) {
640
                _curAbsorptionHohlraumCenter += _scalarFlux[idx_cell] * ( _sigmaT[idx_cell] - _sigmaS[idx_cell] ) * _areas[idx_cell];
641
            }
642
            if( ( x < _settings->GetPosRedLeftBorderHohlraum() && y > _settings->GetPosRedLeftBottomHohlraum() &&
643
                  y < _settings->GetPosRedLeftTopHohlraum() ) ||
644
                ( x > _settings->GetPosRedRightBorderHohlraum() && y > _settings->GetPosRedLeftBottomHohlraum() &&
645
                  y < _settings->GetPosRedRightTopHohlraum() ) ) {
646
                _curAbsorptionHohlraumVertical += _scalarFlux[idx_cell] * ( _sigmaT[idx_cell] - _sigmaS[idx_cell] ) * _areas[idx_cell];
647
            }
648
            if( y > 0.6 || y < -0.6 ) {
649
                _curAbsorptionHohlraumHorizontal += _scalarFlux[idx_cell] * ( _sigmaT[idx_cell] - _sigmaS[idx_cell] ) * _areas[idx_cell];
650
            }
651

652
            // Variation in absorption of center (part 1)
653
            // green area 1 (lower boundary)
654
            bool green1 = x > -0.2 + _settings->GetPosXCenterGreenHohlraum() && x < 0.2 + _settings->GetPosXCenterGreenHohlraum() &&
655
                          y > -0.4 + _settings->GetPosYCenterGreenHohlraum() && y < -0.35 + _settings->GetPosYCenterGreenHohlraum();
656
            // green area 2 (upper boundary)
657
            bool green2 = x > -0.2 + _settings->GetPosXCenterGreenHohlraum() && x < 0.2 + _settings->GetPosXCenterGreenHohlraum() &&
658
                          y > 0.35 + _settings->GetPosYCenterGreenHohlraum() && y < 0.4 + _settings->GetPosYCenterGreenHohlraum();
659
            // green area 3 (left boundary)
660
            bool green3 = x > -0.2 + _settings->GetPosXCenterGreenHohlraum() && x < -0.15 + _settings->GetPosXCenterGreenHohlraum() &&
661
                          y > -0.35 + _settings->GetPosYCenterGreenHohlraum() && y < 0.35 + _settings->GetPosYCenterGreenHohlraum();
662
            // green area 4 (right boundary)
663
            bool green4 = x > 0.15 + _settings->GetPosXCenterGreenHohlraum() && x < 0.2 + _settings->GetPosXCenterGreenHohlraum() &&
664
                          y > -0.35 + _settings->GetPosYCenterGreenHohlraum() && y < 0.35 + _settings->GetPosYCenterGreenHohlraum();
665
            if( green1 || green2 || green3 || green4 ) {
666
                a_g += ( _sigmaT[idx_cell] - _sigmaS[idx_cell] ) * _scalarFlux[idx_cell] * _areas[idx_cell] /
667
                       ( 44 * 0.05 * 0.05 );    // divisor is area of the green
668
            }
669
        }
670

671
        if( _settings->GetProblemName() == PROBLEM_Lattice ) {
672
            // Outflow out of inner and middle perimeter
673
            if( _isPerimeterLatticeCell1[idx_cell] ) {    // inner
674
                for( unsigned long idx_nbr_helper = 0; idx_nbr_helper < _cellsLatticePerimeter1[idx_cell].size(); ++idx_nbr_helper ) {
675
#pragma omp simd reduction( + : _curScalarOutflowPeri1 )
676
                    for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
677
                        double localInner = _quadPts[Idx2D( idx_sys, 0, _nDim )] *
678
                                                _normals[Idx3D( idx_cell, _cellsLatticePerimeter1[idx_cell][idx_nbr_helper], 0, _nNbr, _nDim )] +
679
                                            _quadPts[Idx2D( idx_sys, 1, _nDim )] *
680
                                                _normals[Idx3D( idx_cell, _cellsLatticePerimeter1[idx_cell][idx_nbr_helper], 1, _nNbr, _nDim )];
681
                        // Find outward facing transport directions
682

683
                        if( localInner > 0.0 ) {
684
                            _curScalarOutflowPeri1 +=
685
                                localInner * _sol[Idx2D( idx_cell, idx_sys, _localNSys )] * _quadWeights[idx_sys];    // Integrate flux
686
                        }
687
                    }
688
                }
689
            }
690
            if( _isPerimeterLatticeCell2[idx_cell] ) {    // middle
691
                for( unsigned long idx_nbr_helper = 0; idx_nbr_helper < _cellsLatticePerimeter2[idx_cell].size(); ++idx_nbr_helper ) {
692
#pragma omp simd reduction( + : _curScalarOutflowPeri2 )
693
                    for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
694
                        double localInner = _quadPts[Idx2D( idx_sys, 0, _nDim )] *
695
                                                _normals[Idx3D( idx_cell, _cellsLatticePerimeter2[idx_cell][idx_nbr_helper], 0, _nNbr, _nDim )] +
696
                                            _quadPts[Idx2D( idx_sys, 1, _nDim )] *
697
                                                _normals[Idx3D( idx_cell, _cellsLatticePerimeter2[idx_cell][idx_nbr_helper], 1, _nNbr, _nDim )];
698
                        // Find outward facing transport directions
699

700
                        if( localInner > 0.0 ) {
701
                            _curScalarOutflowPeri2 +=
702
                                localInner * _sol[Idx2D( idx_cell, idx_sys, _localNSys )] * _quadWeights[idx_sys];    // Integrate flux
703
                        }
704
                    }
705
                }
706
            }
707
        }
708
        // Outflow out of domain
709
        if( _cellBoundaryTypes[idx_cell] == BOUNDARY_TYPE::NEUMANN ) {
710
            // Iterate over face cell faces
711
            double currOrdinatewiseOutflow = 0.0;
712

713
            for( unsigned long idx_nbr = 0; idx_nbr < _nNbr; ++idx_nbr ) {
714
                // Find face that points outward
715
                if( _neighbors[Idx2D( idx_cell, idx_nbr, _nNbr )] == _nCells ) {
716
#pragma omp simd reduction( + : _curScalarOutflow ) reduction( max : _curMaxOrdinateOutflow )
717
                    for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
718

719
                        double localInner = _quadPts[Idx2D( idx_sys, 0, _nDim )] * _normals[Idx3D( idx_cell, idx_nbr, 0, _nNbr, _nDim )] +
720
                                            _quadPts[Idx2D( idx_sys, 1, _nDim )] * _normals[Idx3D( idx_cell, idx_nbr, 1, _nNbr, _nDim )];
721
                        // Find outward facing transport directions
722

723
                        if( localInner > 0.0 ) {
724
                            _curScalarOutflow +=
725
                                localInner * _sol[Idx2D( idx_cell, idx_sys, _localNSys )] * _quadWeights[idx_sys];    // Integrate flux
726

727
                            currOrdinatewiseOutflow =
728
                                _sol[Idx2D( idx_cell, idx_sys, _localNSys )] * localInner /
729
                                sqrt( (
730
                                    _normals[Idx3D( idx_cell, idx_nbr, 0, _nNbr, _nDim )] * _normals[Idx3D( idx_cell, idx_nbr, 0, _nNbr, _nDim )] +
731
                                    _normals[Idx3D( idx_cell, idx_nbr, 1, _nNbr, _nDim )] * _normals[Idx3D( idx_cell, idx_nbr, 1, _nNbr, _nDim )] ) );
732

733
                            _curMaxOrdinateOutflow =
734
                                ( currOrdinatewiseOutflow > _curMaxOrdinateOutflow ) ? currOrdinatewiseOutflow : _curMaxOrdinateOutflow;
735
                        }
736
                    }
737
                }
738
            }
739
        }
740
    }
741
// MPI Allreduce
742
#ifdef IMPORT_MPI
743
    double tmp_curScalarOutflow      = 0.0;
744
    double tmp_curScalarOutflowPeri1 = 0.0;
745
    double tmp_curScalarOutflowPeri2 = 0.0;
746
    double tmp_curMaxOrdinateOutflow = 0.0;
747
    MPI_Barrier( MPI_COMM_WORLD );
748
    MPI_Allreduce( &_curScalarOutflow, &tmp_curScalarOutflow, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
749
    _curScalarOutflow = tmp_curScalarOutflow;
750
    MPI_Barrier( MPI_COMM_WORLD );
751
    MPI_Allreduce( &_curScalarOutflowPeri1, &tmp_curScalarOutflowPeri1, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
752
    _curScalarOutflowPeri1 = tmp_curScalarOutflowPeri1;
753
    MPI_Barrier( MPI_COMM_WORLD );
754
    MPI_Allreduce( &_curScalarOutflowPeri2, &tmp_curScalarOutflowPeri2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
755
    _curScalarOutflowPeri2 = tmp_curScalarOutflowPeri2;
756
    MPI_Barrier( MPI_COMM_WORLD );
757
    MPI_Allreduce( &_curMaxOrdinateOutflow, &tmp_curMaxOrdinateOutflow, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD );
758
    _curMaxOrdinateOutflow = tmp_curMaxOrdinateOutflow;
759
    MPI_Barrier( MPI_COMM_WORLD );
760
#endif
761
    // Variation absorption (part II)
762
    if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) {
8✔
763
        unsigned n_probes = 4;
5✔
764
        std::vector<double> temp_probingMoments( 3 * n_probes );    // for MPI allreduce
10✔
765

766
#pragma omp parallel for reduction( + : _varAbsorptionHohlraumGreen )
5✔
767
        for( unsigned long idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
768
            double x = _cellMidPoints[Idx2D( idx_cell, 0, _nDim )];
769
            double y = _cellMidPoints[Idx2D( idx_cell, 1, _nDim )];
770

771
            // green area 1 (lower boundary)
772
            bool green1 = x > -0.2 + _settings->GetPosXCenterGreenHohlraum() && x < 0.2 + _settings->GetPosXCenterGreenHohlraum() &&
773
                          y > -0.4 + _settings->GetPosYCenterGreenHohlraum() && y < -0.35 + _settings->GetPosYCenterGreenHohlraum();
774
            // green area 2 (upper boundary)
775
            bool green2 = x > -0.2 + _settings->GetPosXCenterGreenHohlraum() && x < 0.2 + _settings->GetPosXCenterGreenHohlraum() &&
776
                          y > 0.35 + _settings->GetPosYCenterGreenHohlraum() && y < 0.4 + _settings->GetPosYCenterGreenHohlraum();
777
            // green area 3 (left boundary)
778
            bool green3 = x > -0.2 + _settings->GetPosXCenterGreenHohlraum() && x < -0.15 + _settings->GetPosXCenterGreenHohlraum() &&
779
                          y > -0.35 + _settings->GetPosYCenterGreenHohlraum() && y < 0.35 + _settings->GetPosYCenterGreenHohlraum();
780
            // green area 4 (right boundary)
781
            bool green4 = x > 0.15 + _settings->GetPosXCenterGreenHohlraum() && x < 0.2 + _settings->GetPosXCenterGreenHohlraum() &&
782
                          y > -0.35 + _settings->GetPosYCenterGreenHohlraum() && y < 0.35 + _settings->GetPosYCenterGreenHohlraum();
783
            if( green1 || green2 || green3 || green4 ) {
784
                _varAbsorptionHohlraumGreen += ( a_g - _scalarFlux[idx_cell] * ( _sigmaT[idx_cell] - _sigmaS[idx_cell] ) ) *
785
                                               ( a_g - _scalarFlux[idx_cell] * ( _sigmaT[idx_cell] - _sigmaS[idx_cell] ) ) * _areas[idx_cell];
786
            }
787
        }
788
        // Probes value moments
789
        // #pragma omp parallel for
790
        for( unsigned long idx_probe = 0; idx_probe < n_probes; idx_probe++ ) {    // Loop over probing cells
25✔
791
            temp_probingMoments[Idx2D( idx_probe, 0, 3 )] = 0.0;
20✔
792
            temp_probingMoments[Idx2D( idx_probe, 1, 3 )] = 0.0;
20✔
793
            temp_probingMoments[Idx2D( idx_probe, 2, 3 )] = 0.0;
20✔
794
            // for( unsigned long idx_ball = 0; idx_ball < _probingCellsHohlraum[idx_probe].size(); idx_ball++ ) {
795
            //   std::cout << idx_ball << _areas[_probingCellsHohlraum[idx_probe][idx_ball]] / ( 0.01 * 0.01 * M_PI ) << std::endl;
796
            //}
797
            for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
740✔
798
                for( unsigned long idx_ball = 0; idx_ball < _probingCellsHohlraum[idx_probe].size(); idx_ball++ ) {
1,440✔
799
                    temp_probingMoments[Idx2D( idx_probe, 0, 3 )] += _sol[Idx2D( _probingCellsHohlraum[idx_probe][idx_ball], idx_sys, _localNSys )] *
1,440✔
800
                                                                     _quadWeights[idx_sys] * _areas[_probingCellsHohlraum[idx_probe][idx_ball]] /
720✔
801
                                                                     ( 0.01 * 0.01 * M_PI );
802
                    temp_probingMoments[Idx2D( idx_probe, 1, 3 )] +=
720✔
803
                        _quadPts[Idx2D( idx_sys, 0, _nDim )] * _sol[Idx2D( _probingCellsHohlraum[idx_probe][idx_ball], idx_sys, _localNSys )] *
720✔
804
                        _quadWeights[idx_sys] * _areas[_probingCellsHohlraum[idx_probe][idx_ball]] / ( 0.01 * 0.01 * M_PI );
720✔
805
                    temp_probingMoments[Idx2D( idx_probe, 2, 3 )] +=
720✔
806
                        _quadPts[Idx2D( idx_sys, 1, _nDim )] * _sol[Idx2D( _probingCellsHohlraum[idx_probe][idx_ball], idx_sys, _localNSys )] *
720✔
807
                        _quadWeights[idx_sys] * _areas[_probingCellsHohlraum[idx_probe][idx_ball]] / ( 0.01 * 0.01 * M_PI );
720✔
808
                }
809
            }
810
        }
811

812
#ifdef IMPORT_MPI
813
        MPI_Barrier( MPI_COMM_WORLD );
814
        MPI_Allreduce( temp_probingMoments.data(), _probingMoments.data(), 3 * n_probes, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
815
        MPI_Barrier( MPI_COMM_WORLD );
816
#endif
817
#ifndef IMPORT_MPI
818
        for( unsigned long idx_probe = 0; idx_probe < n_probes; idx_probe++ ) {    // Loop over probing cells
25✔
819
            _probingMoments[Idx2D( idx_probe, 0, 3 )] = temp_probingMoments[Idx2D( idx_probe, 0, 3 )];
20✔
820
            _probingMoments[Idx2D( idx_probe, 1, 3 )] = temp_probingMoments[Idx2D( idx_probe, 1, 3 )];
20✔
821
            _probingMoments[Idx2D( idx_probe, 2, 3 )] = temp_probingMoments[Idx2D( idx_probe, 2, 3 )];
20✔
822
        }
823
#endif
824
    }
825
    // probe values green
826
    if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) {
8✔
827
        ComputeQOIsGreenProbingLine();
5✔
828
    }
829
    // Update time integral values on rank 0
830
    if( _rank == 0 ) {
8✔
831
        constexpr double greenBlockArea = 0.05 * 0.05;
8✔
832

833
        _totalScalarOutflow += _curScalarOutflow * _dT;
8✔
834
        _totalScalarOutflowPeri1 += _curScalarOutflowPeri1 * _dT;
8✔
835
        _totalScalarOutflowPeri2 += _curScalarOutflowPeri2 * _dT;
8✔
836
        _totalAbsorptionLattice += _curAbsorptionLattice * _dT;
8✔
837

838
        _totalAbsorptionHohlraumCenter += _curAbsorptionHohlraumCenter * _dT;
8✔
839
        _totalAbsorptionHohlraumVertical += _curAbsorptionHohlraumVertical * _dT;
8✔
840
        _totalAbsorptionHohlraumHorizontal += _curAbsorptionHohlraumHorizontal * _dT;
8✔
841
        for( unsigned i = 0; i < _nProbingCellsBlocksGreen; ++i ) {
360✔
842
            _absorptionValsBlocksGreenIntegrated[i] += _dT * _absorptionValsBlocksGreen[i] / greenBlockArea;
352✔
843
        }
844
        _avgAbsorptionHohlraumGreenBlockIntegrated = 0.0;
8✔
845
        _varAbsorptionHohlraumGreenBlockIntegrated = 0.0;
8✔
846
        for( unsigned i = 0; i < _nProbingCellsBlocksGreen; ++i ) {
360✔
847
            _avgAbsorptionHohlraumGreenBlockIntegrated += _absorptionValsBlocksGreenIntegrated[i];
352✔
848
        }
849
        _avgAbsorptionHohlraumGreenBlockIntegrated /= static_cast<double>( _nProbingCellsBlocksGreen );
8✔
850
        for( unsigned i = 0; i < _nProbingCellsBlocksGreen; ++i ) {
360✔
851
            const double diff = _absorptionValsBlocksGreenIntegrated[i] - _avgAbsorptionHohlraumGreenBlockIntegrated;
352✔
852
            _varAbsorptionHohlraumGreenBlockIntegrated += diff * diff;
352✔
853
        }
854
        _varAbsorptionHohlraumGreenBlockIntegrated /= static_cast<double>( _nProbingCellsBlocksGreen );
8✔
855

856
        _rmsFlux = sqrt( _rmsFlux );
8✔
857
    }
858
}
8✔
859

860
bool SNSolverHPC::IsAbsorptionLattice( double x, double y ) const {
600✔
861
    // Check whether pos is inside absorbing squares
862
    double xy_corrector = -3.5;
600✔
863
    std::vector<double> lbounds{ 1 + xy_corrector, 2 + xy_corrector, 3 + xy_corrector, 4 + xy_corrector, 5 + xy_corrector };
1,200✔
864
    std::vector<double> ubounds{ 2 + xy_corrector, 3 + xy_corrector, 4 + xy_corrector, 5 + xy_corrector, 6 + xy_corrector };
1,200✔
865
    for( unsigned k = 0; k < lbounds.size(); ++k ) {
3,204✔
866
        for( unsigned l = 0; l < lbounds.size(); ++l ) {
15,984✔
867
            if( ( l + k ) % 2 == 1 || ( k == 2 && l == 2 ) || ( k == 2 && l == 4 ) ) continue;
13,380✔
868
            if( x >= lbounds[k] && x <= ubounds[k] && y >= lbounds[l] && y <= ubounds[l] ) {
5,940✔
869
                return true;
132✔
870
            }
871
        }
872
    }
873
    return false;
468✔
874
}
875

876
// --- Helper ---
877
double SNSolverHPC::ComputeTimeStep( double cfl ) const {
2✔
878
    // for pseudo 1D, set timestep to dx
879
    double dx, dy;
880
    switch( _settings->GetProblemName() ) {
2✔
881
        case PROBLEM_Checkerboard1D:
×
882
            dx = 7.0 / (double)_nCells;
×
883
            dy = 0.3;
×
884
            return cfl * ( dx * dy ) / ( dx + dy );
×
885
            break;
886
        case PROBLEM_Linesource1D:     // Fallthrough
×
887
        case PROBLEM_Meltingcube1D:    // Fallthrough
888
        case PROBLEM_Aircavity1D:
889
            dx = 3.0 / (double)_nCells;
×
890
            dy = 0.3;
×
891
            return cfl * ( dx * dy ) / ( dx + dy );
×
892
            break;
893
        default: break;    // 2d as normal
2✔
894
    }
895
    // 2D case
896
    double charSize = __DBL_MAX__;    // minimum char size of all mesh cells in the mesh
2✔
897

898
#pragma omp parallel for reduction( min : charSize )
2✔
899
    for( unsigned long j = 0; j < _nCells; j++ ) {
900
        double currCharSize = sqrt( _areas[j] );
901
        if( currCharSize < charSize ) {
902
            charSize = currCharSize;
903
        }
904
    }
905
    if( _rank == 0 ) {
2✔
906
        auto log         = spdlog::get( "event" );
6✔
907
        std::string line = "| Smallest characteristic length of a grid cell in this mesh: " + std::to_string( charSize );
4✔
908
        log->info( line );
2✔
909
        line = "| Corresponding maximal time-step: " + std::to_string( cfl * charSize );
2✔
910
        log->info( line );
2✔
911
    }
912
    return cfl * charSize;
2✔
913
}
914

915
// --- IO ----
916
void SNSolverHPC::PrepareScreenOutput() {
2✔
917
    unsigned nFields = (unsigned)_settings->GetNScreenOutput();
2✔
918

919
    _screenOutputFieldNames.resize( nFields );
2✔
920
    _screenOutputFields.resize( nFields );
2✔
921

922
    // Prepare all output Fields ==> Specified in option SCREEN_OUTPUT
923
    for( unsigned idx_field = 0; idx_field < nFields; idx_field++ ) {
14✔
924
        // Prepare all Output Fields per group
925

926
        // Different procedure, depending on the Group...
927
        switch( _settings->GetScreenOutput()[idx_field] ) {
12✔
928
            case MASS: _screenOutputFieldNames[idx_field] = "Mass"; break;
2✔
929
            case ITER: _screenOutputFieldNames[idx_field] = "Iter"; break;
2✔
930
            case SIM_TIME: _screenOutputFieldNames[idx_field] = "Sim time"; break;
×
931
            case WALL_TIME: _screenOutputFieldNames[idx_field] = "Wall time [s]"; break;
2✔
932
            case RMS_FLUX: _screenOutputFieldNames[idx_field] = "RMS flux"; break;
2✔
933
            case VTK_OUTPUT: _screenOutputFieldNames[idx_field] = "VTK out"; break;
2✔
934
            case CSV_OUTPUT: _screenOutputFieldNames[idx_field] = "CSV out"; break;
2✔
935
            case CUR_OUTFLOW: _screenOutputFieldNames[idx_field] = "Cur. outflow"; break;
×
936
            case TOTAL_OUTFLOW: _screenOutputFieldNames[idx_field] = "Tot. outflow"; break;
×
937
            case CUR_OUTFLOW_P1: _screenOutputFieldNames[idx_field] = "Cur. outflow P1"; break;
×
938
            case TOTAL_OUTFLOW_P1: _screenOutputFieldNames[idx_field] = "Tot. outflow P1"; break;
×
939
            case CUR_OUTFLOW_P2: _screenOutputFieldNames[idx_field] = "Cur. outflow P2"; break;
×
940
            case TOTAL_OUTFLOW_P2: _screenOutputFieldNames[idx_field] = "Tot. outflow P2"; break;
×
941
            case MAX_OUTFLOW: _screenOutputFieldNames[idx_field] = "Max outflow"; break;
×
942
            case CUR_PARTICLE_ABSORPTION: _screenOutputFieldNames[idx_field] = "Cur. absorption"; break;
×
943
            case TOTAL_PARTICLE_ABSORPTION: _screenOutputFieldNames[idx_field] = "Tot. absorption"; break;
×
944
            case MAX_PARTICLE_ABSORPTION: _screenOutputFieldNames[idx_field] = "Max absorption"; break;
×
945
            case TOTAL_PARTICLE_ABSORPTION_CENTER: _screenOutputFieldNames[idx_field] = "Tot. abs. center"; break;
×
946
            case TOTAL_PARTICLE_ABSORPTION_VERTICAL: _screenOutputFieldNames[idx_field] = "Tot. abs. vertical wall"; break;
×
947
            case TOTAL_PARTICLE_ABSORPTION_HORIZONTAL: _screenOutputFieldNames[idx_field] = "Tot. abs. horizontal wall"; break;
×
948
            case PROBE_MOMENT_TIME_TRACE:
×
949
                _screenOutputFieldNames[idx_field] = "Probe 1 u_0";
×
950
                idx_field++;
×
951
                _screenOutputFieldNames[idx_field] = "Probe 2 u_0";
×
952
                if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) {
×
953
                    idx_field++;
×
954
                    _screenOutputFieldNames[idx_field] = "Probe 3 u_0";
×
955
                    idx_field++;
×
956
                    _screenOutputFieldNames[idx_field] = "Probe 4 u_0";
×
957
                }
958
                break;
×
959
            case VAR_ABSORPTION_GREEN: _screenOutputFieldNames[idx_field] = "Var. absorption green"; break;
×
NEW
960
            case AVG_ABSORPTION_GREEN_BLOCK_INTEGRATED: _screenOutputFieldNames[idx_field] = "A_G"; break;
×
NEW
961
            case VAR_ABSORPTION_GREEN_BLOCK_INTEGRATED: _screenOutputFieldNames[idx_field] = "V_G"; break;
×
962

963
            default: ErrorMessages::Error( "Screen output field not defined!", CURRENT_FUNCTION ); break;
×
964
        }
965
    }
966
}
2✔
967

968
void SNSolverHPC::WriteScalarOutput( unsigned idx_iter ) {
8✔
969
    unsigned n_probes = 4;
8✔
970

971
    unsigned nFields                  = (unsigned)_settings->GetNScreenOutput();
8✔
972
    const VectorVector probingMoments = _problem->GetCurrentProbeMoment();
16✔
973
    // -- Screen Output
974
    for( unsigned idx_field = 0; idx_field < nFields; idx_field++ ) {
56✔
975
        // Prepare all Output Fields per group
976
        // Different procedure, depending on the Group...
977
        switch( _settings->GetScreenOutput()[idx_field] ) {
48✔
978
            case MASS: _screenOutputFields[idx_field] = _mass; break;
8✔
979
            case ITER: _screenOutputFields[idx_field] = idx_iter; break;
8✔
980
            case SIM_TIME: _screenOutputFields[idx_field] = _curSimTime; break;
×
981
            case WALL_TIME: _screenOutputFields[idx_field] = _currTime; break;
8✔
982
            case RMS_FLUX: _screenOutputFields[idx_field] = _rmsFlux; break;
8✔
983
            case VTK_OUTPUT:
8✔
984
                _screenOutputFields[idx_field] = 0;
8✔
985
                if( ( _settings->GetVolumeOutputFrequency() != 0 && idx_iter % (unsigned)_settings->GetVolumeOutputFrequency() == 0 ) ||
16✔
986
                    ( idx_iter == _nIter - 1 ) /* need sol at last iteration */ ) {
8✔
987
                    _screenOutputFields[idx_field] = 1;
2✔
988
                }
989
                break;
8✔
990
            case CSV_OUTPUT:
8✔
991
                _screenOutputFields[idx_field] = 0;
8✔
992
                if( ( _settings->GetHistoryOutputFrequency() != 0 && idx_iter % (unsigned)_settings->GetHistoryOutputFrequency() == 0 ) ||
8✔
993
                    ( idx_iter == _nIter - 1 ) /* need sol at last iteration */ ) {
×
994
                    _screenOutputFields[idx_field] = 1;
8✔
995
                }
996
                break;
8✔
997
            case CUR_OUTFLOW: _screenOutputFields[idx_field] = _curScalarOutflow; break;
×
998
            case TOTAL_OUTFLOW: _screenOutputFields[idx_field] = _totalScalarOutflow; break;
×
999
            case CUR_OUTFLOW_P1: _screenOutputFields[idx_field] = _curScalarOutflowPeri1; break;
×
1000
            case TOTAL_OUTFLOW_P1: _screenOutputFields[idx_field] = _totalScalarOutflowPeri1; break;
×
1001
            case CUR_OUTFLOW_P2: _screenOutputFields[idx_field] = _curScalarOutflowPeri2; break;
×
1002
            case TOTAL_OUTFLOW_P2: _screenOutputFields[idx_field] = _totalScalarOutflowPeri2; break;
×
1003
            case MAX_OUTFLOW: _screenOutputFields[idx_field] = _curMaxOrdinateOutflow; break;
×
1004
            case CUR_PARTICLE_ABSORPTION: _screenOutputFields[idx_field] = _curAbsorptionLattice; break;
×
1005
            case TOTAL_PARTICLE_ABSORPTION: _screenOutputFields[idx_field] = _totalAbsorptionLattice; break;
×
1006
            case MAX_PARTICLE_ABSORPTION: _screenOutputFields[idx_field] = _curMaxAbsorptionLattice; break;
×
1007
            case TOTAL_PARTICLE_ABSORPTION_CENTER: _screenOutputFields[idx_field] = _totalAbsorptionHohlraumCenter; break;
×
1008
            case TOTAL_PARTICLE_ABSORPTION_VERTICAL: _screenOutputFields[idx_field] = _totalAbsorptionHohlraumVertical; break;
×
1009
            case TOTAL_PARTICLE_ABSORPTION_HORIZONTAL: _screenOutputFields[idx_field] = _totalAbsorptionHohlraumHorizontal; break;
×
1010
            case PROBE_MOMENT_TIME_TRACE:
×
1011
                if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) n_probes = 4;
×
1012
                // if( _settings->GetProblemName() == PROBLEM_QuarterHohlraum ) n_probes = 2;
1013
                for( unsigned i = 0; i < n_probes; i++ ) {
×
1014
                    _screenOutputFields[idx_field] = _probingMoments[Idx2D( i, 0, 3 )];
×
1015
                    idx_field++;
×
1016
                }
1017
                idx_field--;
×
1018
                break;
×
1019
            case VAR_ABSORPTION_GREEN: _screenOutputFields[idx_field] = _varAbsorptionHohlraumGreen; break;
×
NEW
1020
            case AVG_ABSORPTION_GREEN_BLOCK_INTEGRATED:
×
NEW
1021
                _screenOutputFields[idx_field] = _avgAbsorptionHohlraumGreenBlockIntegrated;
×
NEW
1022
                break;
×
NEW
1023
            case VAR_ABSORPTION_GREEN_BLOCK_INTEGRATED:
×
NEW
1024
                _screenOutputFields[idx_field] = _varAbsorptionHohlraumGreenBlockIntegrated;
×
NEW
1025
                break;
×
UNCOV
1026
            default: ErrorMessages::Error( "Screen output group not defined!", CURRENT_FUNCTION ); break;
×
1027
        }
1028
    }
1029

1030
    // --- History output ---
1031
    nFields = (unsigned)_settings->GetNHistoryOutput();
8✔
1032

1033
    std::vector<SCALAR_OUTPUT> screenOutputFields = _settings->GetScreenOutput();
16✔
1034
    for( unsigned idx_field = 0; idx_field < nFields; idx_field++ ) {
149✔
1035

1036
        // Prepare all Output Fields per group
1037
        // Different procedure, depending on the Group...
1038
        switch( _settings->GetHistoryOutput()[idx_field] ) {
141✔
1039
            case MASS: _historyOutputFields[idx_field] = _mass; break;
8✔
1040
            case ITER: _historyOutputFields[idx_field] = idx_iter; break;
8✔
1041
            case SIM_TIME: _historyOutputFields[idx_field] = _curSimTime; break;
8✔
1042
            case WALL_TIME: _historyOutputFields[idx_field] = _currTime; break;
8✔
1043
            case RMS_FLUX: _historyOutputFields[idx_field] = _rmsFlux; break;
8✔
1044
            case VTK_OUTPUT:
8✔
1045
                _historyOutputFields[idx_field] = 0;
8✔
1046
                if( ( _settings->GetVolumeOutputFrequency() != 0 && idx_iter % (unsigned)_settings->GetVolumeOutputFrequency() == 0 ) ||
16✔
1047
                    ( idx_iter == _nIter - 1 ) /* need sol at last iteration */ ) {
8✔
1048
                    _historyOutputFields[idx_field] = 1;
2✔
1049
                }
1050
                break;
8✔
1051

1052
            case CSV_OUTPUT:
8✔
1053
                _historyOutputFields[idx_field] = 0;
8✔
1054
                if( ( _settings->GetHistoryOutputFrequency() != 0 && idx_iter % (unsigned)_settings->GetHistoryOutputFrequency() == 0 ) ||
8✔
1055
                    ( idx_iter == _nIter - 1 ) /* need sol at last iteration */ ) {
×
1056
                    _historyOutputFields[idx_field] = 1;
8✔
1057
                }
1058
                break;
8✔
1059
            case CUR_OUTFLOW: _historyOutputFields[idx_field] = _curScalarOutflow; break;
8✔
1060
            case TOTAL_OUTFLOW: _historyOutputFields[idx_field] = _totalScalarOutflow; break;
8✔
1061
            case CUR_OUTFLOW_P1: _historyOutputFields[idx_field] = _curScalarOutflowPeri1; break;
3✔
1062
            case TOTAL_OUTFLOW_P1: _historyOutputFields[idx_field] = _totalScalarOutflowPeri1; break;
3✔
1063
            case CUR_OUTFLOW_P2: _historyOutputFields[idx_field] = _curScalarOutflowPeri2; break;
3✔
1064
            case TOTAL_OUTFLOW_P2: _historyOutputFields[idx_field] = _totalScalarOutflowPeri2; break;
3✔
1065
            case MAX_OUTFLOW: _historyOutputFields[idx_field] = _curMaxOrdinateOutflow; break;
8✔
1066
            case CUR_PARTICLE_ABSORPTION: _historyOutputFields[idx_field] = _curAbsorptionLattice; break;
3✔
1067
            case TOTAL_PARTICLE_ABSORPTION: _historyOutputFields[idx_field] = _totalAbsorptionLattice; break;
8✔
1068
            case MAX_PARTICLE_ABSORPTION: _historyOutputFields[idx_field] = _curMaxAbsorptionLattice; break;
3✔
1069
            case TOTAL_PARTICLE_ABSORPTION_CENTER: _historyOutputFields[idx_field] = _totalAbsorptionHohlraumCenter; break;
5✔
1070
            case TOTAL_PARTICLE_ABSORPTION_VERTICAL: _historyOutputFields[idx_field] = _totalAbsorptionHohlraumVertical; break;
5✔
1071
            case TOTAL_PARTICLE_ABSORPTION_HORIZONTAL: _historyOutputFields[idx_field] = _totalAbsorptionHohlraumHorizontal; break;
5✔
1072
            case PROBE_MOMENT_TIME_TRACE:
5✔
1073
                if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) n_probes = 4;
5✔
1074
                // if( _settings->GetProblemName() == PROBLEM_QuarterHohlraum ) n_probes = 2;
1075
                for( unsigned i = 0; i < n_probes; i++ ) {
25✔
1076
                    for( unsigned j = 0; j < 3; j++ ) {
80✔
1077
                        _historyOutputFields[idx_field] = _probingMoments[Idx2D( i, j, 3 )];
60✔
1078
                        idx_field++;
60✔
1079
                    }
1080
                }
1081
                idx_field--;
5✔
1082
                break;
5✔
1083
            case VAR_ABSORPTION_GREEN: _historyOutputFields[idx_field] = _varAbsorptionHohlraumGreen; break;
5✔
NEW
1084
            case AVG_ABSORPTION_GREEN_BLOCK_INTEGRATED:
×
NEW
1085
                _historyOutputFields[idx_field] = _avgAbsorptionHohlraumGreenBlockIntegrated;
×
NEW
1086
                break;
×
NEW
1087
            case VAR_ABSORPTION_GREEN_BLOCK_INTEGRATED:
×
NEW
1088
                _historyOutputFields[idx_field] = _varAbsorptionHohlraumGreenBlockIntegrated;
×
NEW
1089
                break;
×
1090
            case ABSORPTION_GREEN_LINE:
5✔
1091
                for( unsigned i = 0; i < _settings->GetNumProbingCellsLineHohlraum(); i++ ) {
105✔
1092
                    _historyOutputFields[idx_field] = _absorptionValsLineSegment[i];
100✔
1093
                    idx_field++;
100✔
1094
                }
1095
                idx_field--;
5✔
1096
                break;
5✔
1097
            case ABSORPTION_GREEN_BLOCK:
5✔
1098
                for( unsigned i = 0; i < 44; i++ ) {
225✔
1099
                    _historyOutputFields[idx_field] = _absorptionValsBlocksGreen[i];
220✔
1100
                    // std::cout << _absorptionValsBlocksGreen[i] << "/" << _historyOutputFields[idx_field] << std::endl;
1101
                    idx_field++;
220✔
1102
                }
1103
                idx_field--;
5✔
1104
                break;
5✔
1105
            default: ErrorMessages::Error( "History output group not defined!", CURRENT_FUNCTION ); break;
×
1106
        }
1107
    }
1108
}
8✔
1109

1110
void SNSolverHPC::PrintScreenOutput( unsigned idx_iter ) {
8✔
1111
    auto log = spdlog::get( "event" );
24✔
1112

1113
    unsigned strLen  = 15;    // max width of one column
8✔
1114
    char paddingChar = ' ';
8✔
1115

1116
    // assemble the line to print
1117
    std::string lineToPrint = "| ";
16✔
1118
    std::string tmp;
16✔
1119
    for( unsigned idx_field = 0; idx_field < _settings->GetNScreenOutput(); idx_field++ ) {
56✔
1120
        tmp = std::to_string( _screenOutputFields[idx_field] );
48✔
1121

1122
        // Format outputs correctly
1123
        std::vector<SCALAR_OUTPUT> integerFields    = { ITER };
96✔
1124
        std::vector<SCALAR_OUTPUT> scientificFields = { RMS_FLUX,
1125
                                                        MASS,
1126
                                                        WALL_TIME,
1127
                                                        CUR_OUTFLOW,
1128
                                                        TOTAL_OUTFLOW,
1129
                                                        CUR_OUTFLOW_P1,
1130
                                                        TOTAL_OUTFLOW_P1,
1131
                                                        CUR_OUTFLOW_P2,
1132
                                                        TOTAL_OUTFLOW_P2,
1133
                                                        MAX_OUTFLOW,
1134
                                                        CUR_PARTICLE_ABSORPTION,
1135
                                                        TOTAL_PARTICLE_ABSORPTION,
1136
                                                        MAX_PARTICLE_ABSORPTION,
1137
                                                        TOTAL_PARTICLE_ABSORPTION_CENTER,
1138
                                                        TOTAL_PARTICLE_ABSORPTION_VERTICAL,
1139
                                                        TOTAL_PARTICLE_ABSORPTION_HORIZONTAL,
1140
                                                        PROBE_MOMENT_TIME_TRACE,
1141
                                                        VAR_ABSORPTION_GREEN,
1142
                                                        AVG_ABSORPTION_GREEN_BLOCK_INTEGRATED,
1143
                                                        VAR_ABSORPTION_GREEN_BLOCK_INTEGRATED,
1144
                                                        ABSORPTION_GREEN_BLOCK,
1145
                                                        ABSORPTION_GREEN_LINE };
96✔
1146
        std::vector<SCALAR_OUTPUT> booleanFields    = { VTK_OUTPUT, CSV_OUTPUT };
48✔
1147

1148
        if( !( integerFields.end() == std::find( integerFields.begin(), integerFields.end(), _settings->GetScreenOutput()[idx_field] ) ) ) {
48✔
1149
            tmp = std::to_string( (int)_screenOutputFields[idx_field] );
8✔
1150
        }
1151
        else if( !( booleanFields.end() == std::find( booleanFields.begin(), booleanFields.end(), _settings->GetScreenOutput()[idx_field] ) ) ) {
40✔
1152
            tmp = "no";
16✔
1153
            if( (bool)_screenOutputFields[idx_field] ) tmp = "yes";
16✔
1154
        }
1155
        else if( !( scientificFields.end() ==
24✔
1156
                    std::find( scientificFields.begin(), scientificFields.end(), _settings->GetScreenOutput()[idx_field] ) ) ) {
48✔
1157

1158
            std::stringstream ss;
24✔
1159
            ss << TextProcessingToolbox::DoubleToScientificNotation( _screenOutputFields[idx_field] );
24✔
1160
            tmp = ss.str();
24✔
1161
            tmp.erase( std::remove( tmp.begin(), tmp.end(), '+' ), tmp.end() );    // removing the '+' sign
24✔
1162
        }
1163

1164
        if( strLen > tmp.size() )    // Padding
48✔
1165
            tmp.insert( 0, strLen - tmp.size(), paddingChar );
48✔
1166
        else if( strLen < tmp.size() )    // Cutting
×
1167
            tmp.resize( strLen );
×
1168

1169
        lineToPrint += tmp + " |";
48✔
1170
    }
1171
    if( _settings->GetScreenOutputFrequency() != 0 && idx_iter % (unsigned)_settings->GetScreenOutputFrequency() == 0 ) {
8✔
1172
        log->info( lineToPrint );
8✔
1173
    }
1174
    else if( idx_iter == _nIter - 1 ) {    // Always print last iteration
×
1175
        log->info( lineToPrint );
×
1176
    }
1177
}
8✔
1178

1179
void SNSolverHPC::PrepareHistoryOutput() {
2✔
1180
    unsigned n_probes = 4;
2✔
1181

1182
    unsigned nFields = (unsigned)_settings->GetNHistoryOutput();
2✔
1183

1184
    _historyOutputFieldNames.resize( nFields );
2✔
1185
    _historyOutputFields.resize( nFields );
2✔
1186

1187
    // Prepare all output Fields ==> Specified in option SCREEN_OUTPUT
1188
    for( unsigned idx_field = 0; idx_field < nFields; idx_field++ ) {
37✔
1189
        // Prepare all Output Fields per group
1190

1191
        // Different procedure, depending on the Group...
1192
        switch( _settings->GetHistoryOutput()[idx_field] ) {
35✔
1193
            case MASS: _historyOutputFieldNames[idx_field] = "Mass"; break;
2✔
1194
            case ITER: _historyOutputFieldNames[idx_field] = "Iter"; break;
2✔
1195
            case SIM_TIME: _historyOutputFieldNames[idx_field] = "Sim_time"; break;
2✔
1196
            case WALL_TIME: _historyOutputFieldNames[idx_field] = "Wall_time_[s]"; break;
2✔
1197
            case RMS_FLUX: _historyOutputFieldNames[idx_field] = "RMS_flux"; break;
2✔
1198
            case VTK_OUTPUT: _historyOutputFieldNames[idx_field] = "VTK_out"; break;
2✔
1199
            case CSV_OUTPUT: _historyOutputFieldNames[idx_field] = "CSV_out"; break;
2✔
1200
            case CUR_OUTFLOW: _historyOutputFieldNames[idx_field] = "Cur_outflow"; break;
2✔
1201
            case TOTAL_OUTFLOW: _historyOutputFieldNames[idx_field] = "Total_outflow"; break;
2✔
1202
            case CUR_OUTFLOW_P1: _historyOutputFieldNames[idx_field] = "Cur_outflow_P1"; break;
1✔
1203
            case TOTAL_OUTFLOW_P1: _historyOutputFieldNames[idx_field] = "Total_outflow_P1"; break;
1✔
1204
            case CUR_OUTFLOW_P2: _historyOutputFieldNames[idx_field] = "Cur_outflow_P2"; break;
1✔
1205
            case TOTAL_OUTFLOW_P2: _historyOutputFieldNames[idx_field] = "Total_outflow_P2"; break;
1✔
1206
            case MAX_OUTFLOW: _historyOutputFieldNames[idx_field] = "Max_outflow"; break;
2✔
1207
            case CUR_PARTICLE_ABSORPTION: _historyOutputFieldNames[idx_field] = "Cur_absorption"; break;
1✔
1208
            case TOTAL_PARTICLE_ABSORPTION: _historyOutputFieldNames[idx_field] = "Total_absorption"; break;
2✔
1209
            case MAX_PARTICLE_ABSORPTION: _historyOutputFieldNames[idx_field] = "Max_absorption"; break;
1✔
1210
            case TOTAL_PARTICLE_ABSORPTION_CENTER: _historyOutputFieldNames[idx_field] = "Cumulated_absorption_center"; break;
1✔
1211
            case TOTAL_PARTICLE_ABSORPTION_VERTICAL: _historyOutputFieldNames[idx_field] = "Cumulated_absorption_vertical_wall"; break;
1✔
1212
            case TOTAL_PARTICLE_ABSORPTION_HORIZONTAL: _historyOutputFieldNames[idx_field] = "Cumulated_absorption_horizontal_wall"; break;
1✔
1213
            case PROBE_MOMENT_TIME_TRACE:
1✔
1214
                if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) n_probes = 4;
1✔
1215
                // if( _settings->GetProblemName() == PROBLEM_QuarterHohlraum ) n_probes = 2;
1216
                for( unsigned i = 0; i < n_probes; i++ ) {
5✔
1217
                    for( unsigned j = 0; j < 3; j++ ) {
16✔
1218
                        _historyOutputFieldNames[idx_field] = "Probe " + std::to_string( i ) + " u_" + std::to_string( j );
12✔
1219
                        idx_field++;
12✔
1220
                    }
1221
                }
1222
                idx_field--;
1✔
1223
                break;
1✔
1224
            case VAR_ABSORPTION_GREEN: _historyOutputFieldNames[idx_field] = "Var. absorption green"; break;
1✔
NEW
1225
            case AVG_ABSORPTION_GREEN_BLOCK_INTEGRATED: _historyOutputFieldNames[idx_field] = "A_G"; break;
×
NEW
1226
            case VAR_ABSORPTION_GREEN_BLOCK_INTEGRATED: _historyOutputFieldNames[idx_field] = "V_G"; break;
×
1227
            case ABSORPTION_GREEN_BLOCK:
1✔
1228
                for( unsigned i = 0; i < 44; i++ ) {
45✔
1229
                    _historyOutputFieldNames[idx_field] = "Probe Green Block " + std::to_string( i );
44✔
1230
                    idx_field++;
44✔
1231
                }
1232
                idx_field--;
1✔
1233
                break;
1✔
1234

1235
            case ABSORPTION_GREEN_LINE:
1✔
1236
                for( unsigned i = 0; i < _settings->GetNumProbingCellsLineHohlraum(); i++ ) {
21✔
1237
                    _historyOutputFieldNames[idx_field] = "Probe Green Line " + std::to_string( i );
20✔
1238
                    idx_field++;
20✔
1239
                }
1240
                idx_field--;
1✔
1241
                break;
1✔
1242
            default: ErrorMessages::Error( "History output field not defined!", CURRENT_FUNCTION ); break;
×
1243
        }
1244
    }
1245
}
2✔
1246

1247
void SNSolverHPC::PrintHistoryOutput( unsigned idx_iter ) {
8✔
1248

1249
    auto log = spdlog::get( "tabular" );
24✔
1250

1251
    // assemble the line to print
1252
    std::string lineToPrint = "";
16✔
1253
    std::string tmp;
16✔
1254
    for( int idx_field = 0; idx_field < _settings->GetNHistoryOutput() - 1; idx_field++ ) {
506✔
1255
        if( idx_field == 0 ) {
498✔
1256
            tmp = std::to_string( _historyOutputFields[idx_field] );    // Iteration count
8✔
1257
        }
1258
        else {
1259
            tmp = TextProcessingToolbox::DoubleToScientificNotation( _historyOutputFields[idx_field] );
490✔
1260
        }
1261
        lineToPrint += tmp + ",";
498✔
1262
    }
1263
    tmp = TextProcessingToolbox::DoubleToScientificNotation( _historyOutputFields[_settings->GetNHistoryOutput() - 1] );
8✔
1264
    lineToPrint += tmp;    // Last element without comma
8✔
1265
    // std::cout << lineToPrint << std::endl;
1266
    if( _settings->GetHistoryOutputFrequency() != 0 && idx_iter % (unsigned)_settings->GetHistoryOutputFrequency() == 0 ) {
8✔
1267
        log->info( lineToPrint );
8✔
1268
    }
1269
    else if( idx_iter == _nIter - 1 ) {    // Always print last iteration
×
1270
        log->info( lineToPrint );
×
1271
    }
1272
}
8✔
1273

1274
void SNSolverHPC::DrawPreSolverOutput() {
2✔
1275

1276
    // Logger
1277
    auto log    = spdlog::get( "event" );
6✔
1278
    auto logCSV = spdlog::get( "tabular" );
6✔
1279

1280
    std::string hLine = "--";
4✔
1281

1282
    unsigned strLen  = 15;    // max width of one column
2✔
1283
    char paddingChar = ' ';
2✔
1284

1285
    // Assemble Header for Screen Output
1286
    std::string lineToPrint = "| ";
4✔
1287
    std::string tmpLine     = "-----------------";
4✔
1288
    for( unsigned idxFields = 0; idxFields < _settings->GetNScreenOutput(); idxFields++ ) {
14✔
1289
        std::string tmp = _screenOutputFieldNames[idxFields];
24✔
1290

1291
        if( strLen > tmp.size() )    // Padding
12✔
1292
            tmp.insert( 0, strLen - tmp.size(), paddingChar );
12✔
1293
        else if( strLen < tmp.size() )    // Cutting
×
1294
            tmp.resize( strLen );
×
1295

1296
        lineToPrint += tmp + " |";
12✔
1297
        hLine += tmpLine;
12✔
1298
    }
1299
    log->info( "---------------------------- Solver Starts -----------------------------" );
2✔
1300
    log->info( "| The simulation will run for {} iterations.", _nIter );
2✔
1301
    log->info( "| The spatial grid contains {} cells.", _nCells );
2✔
1302
    if( _settings->GetSolverName() != PN_SOLVER && _settings->GetSolverName() != CSD_PN_SOLVER ) {
2✔
1303
        log->info( "| The velocity grid contains {} points.", _nq );
2✔
1304
    }
1305
    log->info( hLine );
2✔
1306
    log->info( lineToPrint );
2✔
1307
    log->info( hLine );
2✔
1308

1309
    std::string lineToPrintCSV = "";
4✔
1310
    for( int idxFields = 0; idxFields < _settings->GetNHistoryOutput() - 1; idxFields++ ) {
108✔
1311
        std::string tmp = _historyOutputFieldNames[idxFields];
106✔
1312
        lineToPrintCSV += tmp + ",";
106✔
1313
    }
1314
    lineToPrintCSV += _historyOutputFieldNames[_settings->GetNHistoryOutput() - 1];
2✔
1315
    logCSV->info( lineToPrintCSV );
2✔
1316
}
2✔
1317

1318
void SNSolverHPC::DrawPostSolverOutput() {
2✔
1319

1320
    // Logger
1321
    auto log = spdlog::get( "event" );
6✔
1322

1323
    std::string hLine = "--";
4✔
1324

1325
    unsigned strLen  = 10;    // max width of one column
2✔
1326
    char paddingChar = ' ';
2✔
1327

1328
    // Assemble Header for Screen Output
1329
    std::string lineToPrint = "| ";
4✔
1330
    std::string tmpLine     = "------------";
4✔
1331
    for( unsigned idxFields = 0; idxFields < _settings->GetNScreenOutput(); idxFields++ ) {
14✔
1332
        std::string tmp = _screenOutputFieldNames[idxFields];
24✔
1333

1334
        if( strLen > tmp.size() )    // Padding
12✔
1335
            tmp.insert( 0, strLen - tmp.size(), paddingChar );
10✔
1336
        else if( strLen < tmp.size() )    // Cutting
2✔
1337
            tmp.resize( strLen );
2✔
1338

1339
        lineToPrint += tmp + " |";
12✔
1340
        hLine += tmpLine;
12✔
1341
    }
1342
    log->info( hLine );
2✔
1343
#ifndef BUILD_TESTING
1344
    log->info( "| The volume output files have been stored at " + _settings->GetOutputFile() );
1345
    log->info( "| The log files have been stored at " + _settings->GetLogDir() + _settings->GetLogFile() );
1346
#endif
1347
    log->info( "--------------------------- Solver Finished ----------------------------" );
2✔
1348
}
2✔
1349

1350
unsigned long SNSolverHPC::Idx2D( unsigned long idx1, unsigned long idx2, unsigned long len2 ) { return idx1 * len2 + idx2; }
6,394,040✔
1351

1352
unsigned long SNSolverHPC::Idx3D( unsigned long idx1, unsigned long idx2, unsigned long idx3, unsigned long len2, unsigned long len3 ) {
4,711,152✔
1353
    return ( idx1 * len2 + idx2 ) * len3 + idx3;
4,711,152✔
1354
}
1355

1356
void SNSolverHPC::WriteVolumeOutput( unsigned idx_iter ) {
2✔
1357
    unsigned nGroups = (unsigned)_settings->GetNVolumeOutput();
2✔
1358
    if( ( _settings->GetVolumeOutputFrequency() != 0 && idx_iter % (unsigned)_settings->GetVolumeOutputFrequency() == 0 ) ||
4✔
1359
        ( idx_iter == _nIter - 1 ) /* need sol at last iteration */ ) {
2✔
1360
        for( unsigned idx_group = 0; idx_group < nGroups; idx_group++ ) {
4✔
1361
            switch( _settings->GetVolumeOutput()[idx_group] ) {
2✔
1362
                case MINIMAL:
2✔
1363
                    if( _rank == 0 ) {
2✔
1364
                        _outputFields[idx_group][0] = _scalarFlux;
2✔
1365
                    }
1366
                    break;
2✔
1367

1368
                case MOMENTS:
×
1369
#pragma omp parallel for
×
1370
                    for( unsigned idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
1371
                        _outputFields[idx_group][0][idx_cell] = 0.0;
1372
                        _outputFields[idx_group][1][idx_cell] = 0.0;
1373
                        for( unsigned idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
1374
                            _outputFields[idx_group][0][idx_cell] +=
1375
                                _quadPts[Idx2D( idx_sys, 0, _nDim )] * _sol[Idx2D( idx_cell, idx_sys, _localNSys )] * _quadWeights[idx_sys];
1376
                            _outputFields[idx_group][1][idx_cell] +=
1377
                                _quadPts[Idx2D( idx_sys, 1, _nDim )] * _sol[Idx2D( idx_cell, idx_sys, _localNSys )] * _quadWeights[idx_sys];
1378
                        }
1379
                    }
1380
#ifdef IMPORT_MPI
1381
                    MPI_Barrier( MPI_COMM_WORLD );
1382
                    MPI_Allreduce(
1383
                        _outputFields[idx_group][0].data(), _outputFields[idx_group][0].data(), _nCells, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
1384
                    MPI_Allreduce(
1385
                        _outputFields[idx_group][1].data(), _outputFields[idx_group][1].data(), _nCells, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
1386
                    MPI_Barrier( MPI_COMM_WORLD );
1387
#endif
1388
                    break;
×
1389
                default: ErrorMessages::Error( "Volume Output Group not defined for HPC SN Solver!", CURRENT_FUNCTION ); break;
×
1390
            }
1391
        }
1392
    }
1393
}
2✔
1394

1395
void SNSolverHPC::PrintVolumeOutput( int idx_iter ) {
8✔
1396
    if( _settings->GetSaveRestartSolutionFrequency() != 0 && idx_iter % (int)_settings->GetSaveRestartSolutionFrequency() == 0 ) {
8✔
1397
        // std::cout << "Saving restart solution at iteration " << idx_iter << std::endl;
1398
        WriteRestartSolution( _settings->GetOutputFile(),
×
1399
                              _sol,
×
1400
                              _scalarFlux,
×
1401
                              _rank,
1402
                              idx_iter,
1403
                              _totalAbsorptionHohlraumCenter,
1404
                              _totalAbsorptionHohlraumVertical,
1405
                              _totalAbsorptionHohlraumHorizontal,
1406
                              _totalAbsorptionLattice );
1407
    }
1408

1409
    if( _settings->GetVolumeOutputFrequency() != 0 && idx_iter % (int)_settings->GetVolumeOutputFrequency() == 0 ) {
8✔
1410
        WriteVolumeOutput( idx_iter );
×
1411
        if( _rank == 0 ) {
×
1412
            ExportVTK( _settings->GetOutputFile() + "_" + std::to_string( idx_iter ), _outputFields, _outputFieldNames, _mesh );    // slow
×
1413
        }
1414
    }
1415
    if( idx_iter == (int)_nIter - 1 ) {    // Last iteration write without suffix.
8✔
1416
        WriteVolumeOutput( idx_iter );
2✔
1417
        if( _rank == 0 ) {
2✔
1418
            ExportVTK( _settings->GetOutputFile(), _outputFields, _outputFieldNames, _mesh );
2✔
1419
        }
1420
    }
1421
}
8✔
1422

1423
void SNSolverHPC::PrepareVolumeOutput() {
2✔
1424
    unsigned nGroups = (unsigned)_settings->GetNVolumeOutput();
2✔
1425

1426
    _outputFieldNames.resize( nGroups );
2✔
1427
    _outputFields.resize( nGroups );
2✔
1428

1429
    // Prepare all OutputGroups ==> Specified in option VOLUME_OUTPUT
1430
    for( unsigned idx_group = 0; idx_group < nGroups; idx_group++ ) {
4✔
1431
        // Prepare all Output Fields per group
1432

1433
        // Different procedure, depending on the Group...
1434
        switch( _settings->GetVolumeOutput()[idx_group] ) {
2✔
1435
            case MINIMAL:
2✔
1436
                // Currently only one entry ==> rad flux
1437
                _outputFields[idx_group].resize( 1 );
2✔
1438
                _outputFieldNames[idx_group].resize( 1 );
2✔
1439

1440
                _outputFields[idx_group][0].resize( _nCells );
2✔
1441
                _outputFieldNames[idx_group][0] = "scalar flux";
2✔
1442
                break;
2✔
1443
            case MOMENTS:
×
1444
                // As many entries as there are moments in the system
1445
                _outputFields[idx_group].resize( _nOutputMoments );
×
1446
                _outputFieldNames[idx_group].resize( _nOutputMoments );
×
1447

1448
                for( unsigned idx_moment = 0; idx_moment < _nOutputMoments; idx_moment++ ) {
×
1449
                    _outputFieldNames[idx_group][idx_moment] = std::string( "u_" + std::to_string( idx_moment ) );
×
1450
                    _outputFields[idx_group][idx_moment].resize( _nCells );
×
1451
                }
1452
                break;
×
1453

1454
            default: ErrorMessages::Error( "Volume Output Group not defined for HPC SN Solver!", CURRENT_FUNCTION ); break;
×
1455
        }
1456
    }
1457
}
2✔
1458

1459
void SNSolverHPC::SetGhostCells() {
2✔
1460
    if( _settings->GetProblemName() == PROBLEM_Lattice ) {
2✔
1461
        // #pragma omp parallel for
1462
        for( unsigned idx_cell = 0; idx_cell < _nCells; idx_cell++ ) {
201✔
1463
            if( _cellBoundaryTypes[idx_cell] == BOUNDARY_TYPE::NEUMANN || _cellBoundaryTypes[idx_cell] == BOUNDARY_TYPE::DIRICHLET ) {
200✔
1464
                _ghostCells[idx_cell] = std::vector<double>( _localNSys, 0.0 );
38✔
1465
            }
1466
        }
1467
    }
1468
    else if( _settings->GetProblemName() == PROBLEM_HalfLattice ) {    // HALF LATTICE NOT WORKING
1✔
1469
        ErrorMessages::Error( "Test case does not work with MPI", CURRENT_FUNCTION );
×
1470
    }
1471
    else if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) {
1✔
1472

1473
        auto nodes = _mesh->GetNodes();
2✔
1474
        double tol = 1e-12;    // For distance to boundary
1✔
1475

1476
        // #pragma omp parallel for
1477
        for( unsigned idx_cell = 0; idx_cell < _nCells; idx_cell++ ) {
201✔
1478

1479
            if( _cellBoundaryTypes[idx_cell] == BOUNDARY_TYPE::NEUMANN || _cellBoundaryTypes[idx_cell] == BOUNDARY_TYPE::DIRICHLET ) {
200✔
1480
                _ghostCells[idx_cell] = std::vector<double>( _localNSys, 0.0 );
38✔
1481

1482
                auto localCellNodes = _mesh->GetCells()[idx_cell];
76✔
1483

1484
                for( unsigned idx_node = 0; idx_node < _mesh->GetNumNodesPerCell(); idx_node++ ) {    // Check if corner node is in this cell
56✔
1485
                    if( nodes[localCellNodes[idx_node]][0] < -0.65 + tol ) {                          // close to 0 => left boundary
56✔
1486
                        for( unsigned idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
407✔
1487
                            if( _quadPts[Idx2D( idx_sys, 0, _nDim )] > 0.0 ) _ghostCells[idx_cell][idx_sys] = 1.0;
396✔
1488
                        }
1489
                        break;
11✔
1490
                    }
1491
                    else if( nodes[localCellNodes[idx_node]][0] > 0.65 - tol ) {    // right boundary
45✔
1492
                        for( unsigned idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
370✔
1493
                            if( _quadPts[Idx2D( idx_sys, 0, _nDim )] < 0.0 ) _ghostCells[idx_cell][idx_sys] = 1.0;
360✔
1494
                        }
1495
                        break;
10✔
1496
                    }
1497
                    else if( nodes[localCellNodes[idx_node]][1] < -0.65 + tol ) {    // lower boundary
35✔
1498
                        break;
9✔
1499
                    }
1500
                    else if( nodes[localCellNodes[idx_node]][1] > 0.65 - tol ) {    // upper boundary
26✔
1501
                        break;
8✔
1502
                    }
1503
                    else if( idx_node == _mesh->GetNumNodesPerCell() - 1 ) {
18✔
1504
                        ErrorMessages::Error( " Problem with ghost cell setup and  boundary of this mesh ", CURRENT_FUNCTION );
×
1505
                    }
1506
                }
1507
            }
1508
        }
1509
    }
1510
    else if( _settings->GetProblemName() == PROBLEM_QuarterHohlraum ) {
×
1511
        ErrorMessages::Error( "Test case does not work with MPI", CURRENT_FUNCTION );
×
1512
    }
1513
}
2✔
1514

1515
void SNSolverHPC::SetProbingCellsLineGreen() {
2✔
1516

1517
    if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) {
2✔
1518
        assert( _nProbingCellsLineGreen % 2 == 0 );
1✔
1519

1520
        std::vector<double> p1 = { _cornerUpperLeftGreen[0] + _thicknessGreen / 2.0, _cornerUpperLeftGreen[1] - _thicknessGreen / 2.0 };
2✔
1521
        std::vector<double> p2 = { _cornerUpperRightGreen[0] - _thicknessGreen / 2.0, _cornerUpperRightGreen[1] - _thicknessGreen / 2.0 };
2✔
1522
        std::vector<double> p3 = { _cornerLowerRightGreen[0] - _thicknessGreen / 2.0, _cornerLowerRightGreen[1] + _thicknessGreen / 2.0 };
2✔
1523
        std::vector<double> p4 = { _cornerLowerLeftGreen[0] + _thicknessGreen / 2.0, _cornerLowerLeftGreen[1] + _thicknessGreen / 2.0 };
2✔
1524

1525
        double verticalLineWidth   = std::abs( p1[1] - p4[1] );
1✔
1526
        double horizontalLineWidth = std::abs( p1[0] - p2[0] );
1✔
1527

1528
        double pt_ratio_h = horizontalLineWidth / ( horizontalLineWidth + verticalLineWidth );
1✔
1529

1530
        unsigned nHorizontalProbingCells = (unsigned)std::ceil( _nProbingCellsLineGreen / 2 * pt_ratio_h );
1✔
1531
        unsigned nVerticalProbingCells   = _nProbingCellsLineGreen / 2 - nHorizontalProbingCells;
1✔
1532
        assert( nHorizontalProbingCells > 1 );
1✔
1533
        assert( nVerticalProbingCells > 1 );
1✔
1534

1535
        _probingCellsLineGreen = std::vector<unsigned>( 2 * ( nVerticalProbingCells + nHorizontalProbingCells ) );
1✔
1536

1537
        // Sample points on each side of the rectangle
1538
        std::vector<unsigned> side1 = linspace2D( p1, p2, nHorizontalProbingCells );    // upper horizontal
2✔
1539
        std::vector<unsigned> side2 = linspace2D( p2, p3, nVerticalProbingCells );      // right vertical
2✔
1540
        std::vector<unsigned> side3 = linspace2D( p3, p4, nHorizontalProbingCells );    // lower horizontal
2✔
1541
        std::vector<unsigned> side4 = linspace2D( p4, p1, nVerticalProbingCells );      // left vertical
2✔
1542

1543
        for( unsigned i = 0; i < nHorizontalProbingCells; ++i ) {
5✔
1544
            _probingCellsLineGreen[i] = side1[i];
4✔
1545
        }
1546
        for( unsigned i = 0; i < nVerticalProbingCells; ++i ) {
7✔
1547
            _probingCellsLineGreen[i + nHorizontalProbingCells] = side2[i];
6✔
1548
        }
1549
        for( unsigned i = 0; i < nHorizontalProbingCells; ++i ) {
5✔
1550
            _probingCellsLineGreen[i + nVerticalProbingCells + nHorizontalProbingCells] = side3[i];
4✔
1551
        }
1552
        for( unsigned i = 0; i < nVerticalProbingCells; ++i ) {
7✔
1553
            _probingCellsLineGreen[i + nVerticalProbingCells + 2 * nHorizontalProbingCells] = side4[i];
6✔
1554
        }
1555

1556
        // Block-wise approach
1557
        // Initialize the vector to store the corner points of each block
1558
        std::vector<std::vector<std::vector<double>>> block_corners;
2✔
1559

1560
        double block_size = 0.05;
1✔
1561
        const double cx   = _centerGreen[0];
1✔
1562
        const double cy   = _centerGreen[1];
1✔
1563

1564
        // Loop to fill the blocks
1565
        for( int i = 0; i < 8; ++i ) {    // 8 blocks in the x-direction (horizontal) (upper) (left to right)
9✔
1566

1567
            // Top row
1568
            double x1 = -0.2 + cx + i * block_size;
8✔
1569
            double y1 = 0.4 + cy;
8✔
1570
            double x2 = x1 + block_size;
8✔
1571
            double y2 = y1 - block_size;
8✔
1572

1573
            std::vector<std::vector<double>> corners = {
1574
                { x1, y1 },    // top-left
1575
                { x2, y1 },    // top-right
1576
                { x2, y2 },    // bottom-right
1577
                { x1, y2 }     // bottom-left
1578
            };
64✔
1579
            block_corners.push_back( corners );
8✔
1580
        }
1581

1582
        for( int j = 0; j < 14; ++j ) {    // 14 blocks in the y-direction (vertical)
15✔
1583
            // right column double x1 = 0.15;
1584
            double x1 = 0.15 + cx;
14✔
1585
            double y1 = 0.35 + cy - j * block_size;
14✔
1586
            double x2 = x1 + block_size;
14✔
1587
            double y2 = y1 - block_size;
14✔
1588

1589
            // Store the four corner points for this block
1590
            std::vector<std::vector<double>> corners = {
1591
                { x1, y1 },    // top-left
1592
                { x2, y1 },    // top-right
1593
                { x2, y2 },    // bottom-right
1594
                { x1, y2 }     // bottom-left
1595
            };
112✔
1596

1597
            block_corners.push_back( corners );
14✔
1598
        }
1599

1600
        for( int i = 0; i < 8; ++i ) {    // 8 blocks in the x-direction (horizontal) (lower) (right to left)
9✔
1601
            // bottom row
1602
            double x1 = 0.15 + cx - i * block_size;
8✔
1603
            double y1 = -0.35 + cy;
8✔
1604
            double x2 = x1 + block_size;
8✔
1605
            double y2 = y1 - block_size;
8✔
1606

1607
            std::vector<std::vector<double>> corners = {
1608
                { x1, y1 },    // top-left
1609
                { x2, y1 },    // top-right
1610
                { x2, y2 },    // bottom-right
1611
                { x1, y2 }     // bottom-left
1612
            };
64✔
1613
            block_corners.push_back( corners );
8✔
1614
        }
1615

1616
        for( int j = 0; j < 14; ++j ) {    // 14 blocks in the y-direction (vertical) (down to up)
15✔
1617

1618
            // left column
1619
            double x1 = -0.2 + cx;
14✔
1620
            double y1 = -0.3 + cy + j * block_size;
14✔
1621
            double x2 = x1 + block_size;
14✔
1622
            double y2 = y1 - block_size;
14✔
1623

1624
            // Store the four corner points for this block
1625
            std::vector<std::vector<double>> corners = {
1626
                { x1, y1 },    // top-left
1627
                { x2, y1 },    // top-right
1628
                { x2, y2 },    // bottom-right
1629
                { x1, y2 }     // bottom-left
1630
            };
112✔
1631

1632
            block_corners.push_back( corners );
14✔
1633
        }
1634

1635
        // Compute the probing cells for each block
1636
        for( unsigned i = 0; i < _nProbingCellsBlocksGreen; i++ ) {
45✔
1637
            _probingCellsBlocksGreen.push_back( _mesh->GetCellsofRectangle( block_corners[i] ) );
44✔
1638
        }
1639
    }
1640
}
2✔
1641

1642
void SNSolverHPC::ComputeQOIsGreenProbingLine() {
5✔
1643
#pragma omp parallel for
5✔
1644
    for( unsigned i = 0; i < _nProbingCellsLineGreen; i++ ) {    // Loop over probing cells
1645
        _absorptionValsLineSegment[i] =
1646
            ( _sigmaT[_probingCellsLineGreen[i]] - _sigmaS[_probingCellsLineGreen[i]] ) * _scalarFlux[_probingCellsLineGreen[i]];
1647
    }
1648

1649
    // Block-wise approach
1650
    // #pragma omp parallel for
1651
    for( unsigned i = 0; i < _nProbingCellsBlocksGreen; i++ ) {
225✔
1652
        _absorptionValsBlocksGreen[i] = 0.0;
220✔
1653
        for( unsigned j = 0; j < _probingCellsBlocksGreen[i].size(); j++ ) {
440✔
1654
            _absorptionValsBlocksGreen[i] += ( _sigmaT[_probingCellsBlocksGreen[i][j]] - _sigmaS[_probingCellsBlocksGreen[i][j]] ) *
440✔
1655
                                             _scalarFlux[_probingCellsBlocksGreen[i][j]] * _areas[_probingCellsBlocksGreen[i][j]];
220✔
1656
        }
1657
    }
1658
    // std::cout << _absorptionValsBlocksGreen[1] << std::endl;
1659
    // std::cout << _absorptionValsLineSegment[1] << std::endl;
1660
}
5✔
1661

1662
std::vector<unsigned> SNSolverHPC::linspace2D( const std::vector<double>& start, const std::vector<double>& end, unsigned num_points ) {
4✔
1663
    /**
1664
     * Generate a 2D linspace based on the start and end points with a specified number of points.
1665
     *
1666
     * @param start vector of starting x and y coordinates
1667
     * @param end vector of ending x and y coordinates
1668
     * @param num_points number of points to generate
1669
     *
1670
     * @return vector of unsigned integers representing the result
1671
     */
1672

1673
    std::vector<unsigned> result;
4✔
1674
    assert( num_points > 1 );
4✔
1675
    result.resize( num_points );
4✔
1676
    double stepX = ( end[0] - start[0] ) / ( num_points - 1 );
4✔
1677
    double stepY = ( end[1] - start[1] ) / ( num_points - 1 );
4✔
1678
#pragma omp parallel for
4✔
1679
    for( unsigned i = 0; i < num_points; ++i ) {
1680
        double x = start[0] + i * stepX;
1681
        double y = start[1] + i * stepY;
1682

1683
        result[i] = _mesh->GetCellOfKoordinate( x, y );
1684
    }
1685

1686
    return result;
4✔
1687
}
1688

1689
void SNSolverHPC::ComputeCellsPerimeterLattice() {
2✔
1690
    double l_1    = 1.5;    // perimeter 1
2✔
1691
    double l_2    = 2.5;    // perimeter 2
2✔
1692
    auto nodes    = _mesh->GetNodes();
4✔
1693
    auto cells    = _mesh->GetCells();
4✔
1694
    auto cellMids = _mesh->GetCellMidPoints();
4✔
1695
    auto normals  = _mesh->GetNormals();
4✔
1696
    auto neigbors = _mesh->GetNeighbours();
4✔
1697

1698
    _isPerimeterLatticeCell1.resize( _mesh->GetNumCells(), false );
2✔
1699
    _isPerimeterLatticeCell2.resize( _mesh->GetNumCells(), false );
2✔
1700

1701
    for( unsigned idx_cell = 0; idx_cell < _mesh->GetNumCells(); ++idx_cell ) {
402✔
1702
        if( abs( cellMids[idx_cell][0] ) < l_1 && abs( cellMids[idx_cell][1] ) < l_1 ) {
400✔
1703
            // Cell is within perimeter
1704
            for( unsigned idx_nbr = 0; idx_nbr < _mesh->GetNumNodesPerCell(); ++idx_nbr ) {
928✔
1705
                if( neigbors[idx_cell][idx_nbr] == _mesh->GetNumCells() ) {
696✔
1706
                    continue;    // Skip boundary - ghost cells
40✔
1707
                }
1708

1709
                if( ( abs( cellMids[neigbors[idx_cell][idx_nbr]][0] ) > l_1 && abs( cellMids[idx_cell][0] ) < l_1 ) ||
1,312✔
1710
                    ( abs( cellMids[neigbors[idx_cell][idx_nbr]][1] ) > l_1 && abs( cellMids[idx_cell][1] ) < l_1 ) ) {
656✔
1711
                    // neighbor is outside perimeter
1712
                    _cellsLatticePerimeter1[idx_cell].push_back( idx_nbr );
16✔
1713
                    _isPerimeterLatticeCell1[idx_cell] = true;
16✔
1714
                }
1715
            }
1716
        }
1717
        else if( abs( cellMids[idx_cell][0] ) < l_2 && abs( cellMids[idx_cell][1] ) < l_2 ) {
168✔
1718
            // Cell is within perimeter
1719
            for( unsigned idx_nbr = 0; idx_nbr < _mesh->GetNumNodesPerCell(); ++idx_nbr ) {
264✔
1720
                if( neigbors[idx_cell][idx_nbr] == _mesh->GetNumCells() ) {
198✔
1721
                    continue;    // Skip boundary - ghost cells
×
1722
                }
1723
                if( ( abs( cellMids[neigbors[idx_cell][idx_nbr]][0] ) > l_2 && abs( cellMids[idx_cell][0] ) < l_2 ) ||
394✔
1724
                    ( abs( cellMids[neigbors[idx_cell][idx_nbr]][1] ) > l_2 && abs( cellMids[idx_cell][1] ) < l_2 ) ) {
196✔
1725
                    // neighbor is outside perimeter
1726
                    _cellsLatticePerimeter2[idx_cell].push_back( idx_nbr );
54✔
1727
                    _isPerimeterLatticeCell2[idx_cell] = true;
54✔
1728
                }
1729
            }
1730
        }
1731
    }
1732
}
2✔
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