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

CSMMLab / KiT-RT / #115

10 Feb 2026 07:55PM UTC coverage: 46.577% (-0.05%) from 46.626%
#115

push

travis-ci

web-flow
Merge 67b7f1690 into e3695236a

0 of 28 new or added lines in 1 file covered. (0.0%)

1 existing line in 1 file now uncovered.

4422 of 9494 relevant lines covered (46.58%)

57066.71 hits per line

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

0.0
/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 ) {
×
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
×
22
    _rank     = 0;
×
23
#endif
24
    _settings       = settings;
×
25
    _currTime       = 0.0;
×
26
    _idx_start_iter = 0;
×
27
    _nOutputMoments = 2;    //  Currently only u_1 (x direction) and u_1 (y direction) are supported
×
28
    // Create Mesh
29
    _mesh = LoadSU2MeshFromFile( settings );
×
30
    _settings->SetNCells( _mesh->GetNumCells() );
×
31
    auto quad = QuadratureBase::Create( settings );
×
32
    _settings->SetNQuadPoints( quad->GetNq() );
×
33

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

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

42
    if( _numProcs > _nq ) {
×
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 ) {
×
47
        _localNSys   = _nSys;
×
48
        _startSysIdx = 0;
×
49
        _endSysIdx   = _nSys;
×
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();
×
66
    _temporalOrder = _settings->GetTemporalOrder();
×
67

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

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

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

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

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

94
    _scalarFlux              = std::vector<double>( _nCells );
×
95
    _localMaxOrdinateOutflow = std::vector<double>( _nCells );
×
96

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

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

111
    _dT    = ComputeTimeStep( _settings->GetCFL() );
×
112
    _nIter = unsigned( _settings->GetTEnd() / _dT ) + 1;
×
113

114
    auto quadPoints  = quad->GetPoints();
×
115
    auto quadWeights = quad->GetWeights();
×
116

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

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

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

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

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

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

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

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

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

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

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

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

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

223
    // Initialiye QOIS
224
    _mass    = 0;
×
225
    _rmsFlux = 0;
×
226

227
    {    // Hohlraum
228

229
        unsigned n_probes = 4;
×
230
        if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) n_probes = 4;
×
231
        // if( _settings->GetProblemName() == PROBLEM_QuarterHohlraum ) n_probes = 2;
232

233
        _probingMoments = std::vector<double>( n_probes * 3, 0. );    // 10 time horizons
×
234

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

250
        // Green
251
        _thicknessGreen = 0.05;
×
252

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

268
        _nProbingCellsLineGreen = _settings->GetNumProbingCellsLineHohlraum();
×
269

270
        _nProbingCellsBlocksGreen  = 44;
×
271
        _absorptionValsBlocksGreen = std::vector<double>( _nProbingCellsBlocksGreen, 0. );
×
272
        _absorptionValsLineSegment = std::vector<double>( _nProbingCellsLineGreen, 0.0 );
×
273

274
        SetProbingCellsLineGreen();    // ONLY FOR HOHLRAUM
×
275
    }
276
}
277

278
SNSolverHPC::~SNSolverHPC() {
×
279
    delete _mesh;
×
280
    delete _problem;
×
281
}
282

283
void SNSolverHPC::Solve() {
×
284

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

294
    std::chrono::duration<double> duration;
295
    // Loop over energies (pseudo-time of continuous slowing down approach)
296
    for( unsigned iter = (unsigned)_idx_start_iter; iter < _nIter; iter++ ) {
×
297

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

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

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

347
        // --- Write Output ---
348
        if( _rank == 0 ) {
×
349

350
            WriteScalarOutput( iter );
×
351

352
            // --- Update Scalar Fluxes
353

354
            // --- Print Output ---
355
            PrintScreenOutput( iter );
×
356
            PrintHistoryOutput( iter );
×
357
        }
358
#ifdef IMPORT_MPI
359
        MPI_Barrier( MPI_COMM_WORLD );
360
#endif
361

362
        PrintVolumeOutput( iter );
×
363
#ifdef IMPORT_MPI
364
        MPI_Barrier( MPI_COMM_WORLD );
365
#endif
366
    }
367
    // --- Postprocessing ---
368
    if( _rank == 0 ) {
×
369
        DrawPostSolverOutput();
×
370
    }
371
}
372

373
void SNSolverHPC::FluxOrder2() {
×
374

375
    double const eps = 1e-10;
×
376

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

404
#pragma omp simd
405
            for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
406

407
                double gaussPoint = 0;
408
                double r          = 0;
409
                double minSol     = _sol[Idx2D( idx_cell, idx_sys, _localNSys )];
410
                double maxSol     = _sol[Idx2D( idx_cell, idx_sys, _localNSys )];
411

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

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

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

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

434
                    // VENKATAKRISHNAN LIMITER
435
                    double delta1Max = maxSol - _sol[Idx2D( idx_cell, idx_sys, _localNSys )];
436
                    double delta1Min = minSol - _sol[Idx2D( idx_cell, idx_sys, _localNSys )];
437

438
                    r = ( gaussPoint > 0 ) ? ( ( delta1Max * delta1Max + _areas[idx_cell] ) * gaussPoint + 2 * gaussPoint * gaussPoint * delta1Max ) /
439
                                                 ( delta1Max * delta1Max + 2 * gaussPoint * gaussPoint + delta1Max * gaussPoint + _areas[idx_cell] ) /
440
                                                 ( gaussPoint + eps )
441
                                           : ( ( delta1Min * delta1Min + _areas[idx_cell] ) * gaussPoint + 2 * gaussPoint * gaussPoint * delta1Min ) /
442
                                                 ( delta1Min * delta1Min + 2 * gaussPoint * gaussPoint + delta1Min * gaussPoint + _areas[idx_cell] ) /
443
                                                 ( gaussPoint - eps );
444

445
                    r = ( std::abs( gaussPoint ) < eps ) ? 1 : r;
446

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

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

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

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

514
void SNSolverHPC::FluxOrder1() {
×
515

516
#pragma omp parallel for
×
517
    for( unsigned long idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
518

519
#pragma omp simd
520
        for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
521
            _flux[Idx2D( idx_cell, idx_sys, _localNSys )] = 0.0;    // Reset temporary variable
522
        }
523

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

545
                    double localInner = _quadPts[Idx2D( idx_sys, 0, _nDim )] * _normals[Idx3D( idx_cell, idx_nbr, 0, _nNbr, _nDim )] +
546
                                        _quadPts[Idx2D( idx_sys, 1, _nDim )] * _normals[Idx3D( idx_cell, idx_nbr, 1, _nNbr, _nDim )];
547

548
                    _flux[Idx2D( idx_cell, idx_sys, _localNSys )] += ( localInner > 0 ) ? localInner * _sol[Idx2D( idx_cell, idx_sys, _localNSys )]
549
                                                                                        : localInner * _sol[Idx2D( nbr_glob, idx_sys, _localNSys )];
550
                }
551
            }
552
        }
553
    }
554
}
555

556
void SNSolverHPC::FVMUpdate() {
×
557
    _mass    = 0.0;
×
558
    _rmsFlux = 0.0;
×
559
    std::vector<double> temp_scalarFlux( _nCells );    // for MPI allreduce
×
NEW
560
    std::vector<double> prev_scalarFlux( _scalarFlux );
×
561

NEW
562
#pragma omp parallel for reduction( + : _mass )
×
563
    for( unsigned long idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
564

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

575
#pragma omp simd reduction( + : localScalarFlux )
576
        for( unsigned long idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
577
            _sol[Idx2D( idx_cell, idx_sys, _localNSys )] = std::max( _sol[Idx2D( idx_cell, idx_sys, _localNSys )], 0.0 );
578
            localScalarFlux += _sol[Idx2D( idx_cell, idx_sys, _localNSys )] * _quadWeights[idx_sys];
579
        }
580
        _mass += localScalarFlux * _areas[idx_cell];
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
    if( _rank == 0 ) {
589
        for( unsigned long idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
590
            double diff = _scalarFlux[idx_cell] - prev_scalarFlux[idx_cell];
591
            _rmsFlux += diff * diff;
592
        }
593
    }
594
#endif
595
#ifndef IMPORT_MPI
596
    _scalarFlux = temp_scalarFlux;
×
NEW
597
#pragma omp parallel for reduction( + : _rmsFlux )
×
598
    for( unsigned long idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
599
        double diff = _scalarFlux[idx_cell] - prev_scalarFlux[idx_cell];
600
        _rmsFlux += diff * diff;
601
    }
602
#endif
603
}
604

605
void SNSolverHPC::IterPostprocessing() {
×
606
    // ALREDUCE NEEDED
607

608
    _curAbsorptionLattice            = 0.0;
×
609
    _curScalarOutflow                = 0.0;
×
610
    _curScalarOutflowPeri1           = 0.0;
×
611
    _curScalarOutflowPeri2           = 0.0;
×
612
    _curAbsorptionHohlraumCenter     = 0.0;    // Green and blue areas of symmetric hohlraum
×
613
    _curAbsorptionHohlraumVertical   = 0.0;    // Red areas of symmetric hohlraum
×
614
    _curAbsorptionHohlraumHorizontal = 0.0;    // Black areas of symmetric hohlraum
×
615
    _varAbsorptionHohlraumGreen      = 0.0;
×
616
    double a_g                       = 0.0;
×
617

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

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

636
        if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) {    //} || _settings->GetProblemName() == PROBLEM_QuarterHohlraum ) {
637

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

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

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

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

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

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

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

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

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

736
                            _curMaxOrdinateOutflow =
737
                                ( currOrdinatewiseOutflow > _curMaxOrdinateOutflow ) ? currOrdinatewiseOutflow : _curMaxOrdinateOutflow;
738
                        }
739
                    }
740
                }
741
            }
742
        }
743
    }
744
// MPI Allreduce
745
#ifdef IMPORT_MPI
746
    double tmp_curScalarOutflow      = 0.0;
747
    double tmp_curScalarOutflowPeri1 = 0.0;
748
    double tmp_curScalarOutflowPeri2 = 0.0;
749
    double tmp_curMaxOrdinateOutflow = 0.0;
750
    double tmp_mass                  = 0.0;
751
    double tmp_rmsFlux               = 0.0;
752
    MPI_Barrier( MPI_COMM_WORLD );
753
    MPI_Allreduce( &_curScalarOutflow, &tmp_curScalarOutflow, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
754
    _curScalarOutflow = tmp_curScalarOutflow;
755
    MPI_Barrier( MPI_COMM_WORLD );
756
    MPI_Allreduce( &_curScalarOutflowPeri1, &tmp_curScalarOutflowPeri1, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
757
    _curScalarOutflowPeri1 = tmp_curScalarOutflowPeri1;
758
    MPI_Barrier( MPI_COMM_WORLD );
759
    MPI_Allreduce( &_curScalarOutflowPeri2, &tmp_curScalarOutflowPeri2, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
760
    _curScalarOutflowPeri2 = tmp_curScalarOutflowPeri2;
761
    MPI_Barrier( MPI_COMM_WORLD );
762
    MPI_Allreduce( &_curMaxOrdinateOutflow, &tmp_curMaxOrdinateOutflow, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD );
763
    _curMaxOrdinateOutflow = tmp_curMaxOrdinateOutflow;
764
    MPI_Barrier( MPI_COMM_WORLD );
765
    MPI_Allreduce( &_mass, &tmp_mass, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
766
    _mass = tmp_mass;
767
    MPI_Barrier( MPI_COMM_WORLD );
768
    MPI_Allreduce( &_rmsFlux, &tmp_rmsFlux, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
769
    _rmsFlux = tmp_rmsFlux;
770
    MPI_Barrier( MPI_COMM_WORLD );
771
#endif
772
    // Variation absorption (part II)
773
    if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) {
×
774
        unsigned n_probes = 4;
×
775
        std::vector<double> temp_probingMoments( 3 * n_probes );    // for MPI allreduce
×
776

777
#pragma omp parallel for reduction( + : _varAbsorptionHohlraumGreen )
×
778
        for( unsigned long idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
779
            double x = _cellMidPoints[Idx2D( idx_cell, 0, _nDim )];
780
            double y = _cellMidPoints[Idx2D( idx_cell, 1, _nDim )];
781

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

823
#ifdef IMPORT_MPI
824
        MPI_Barrier( MPI_COMM_WORLD );
825
        MPI_Allreduce( temp_probingMoments.data(), _probingMoments.data(), 3 * n_probes, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
826
        MPI_Barrier( MPI_COMM_WORLD );
827
#endif
828
#ifndef IMPORT_MPI
829
        for( unsigned long idx_probe = 0; idx_probe < n_probes; idx_probe++ ) {    // Loop over probing cells
×
830
            _probingMoments[Idx2D( idx_probe, 0, 3 )] = temp_probingMoments[Idx2D( idx_probe, 0, 3 )];
×
831
            _probingMoments[Idx2D( idx_probe, 1, 3 )] = temp_probingMoments[Idx2D( idx_probe, 1, 3 )];
×
832
            _probingMoments[Idx2D( idx_probe, 2, 3 )] = temp_probingMoments[Idx2D( idx_probe, 2, 3 )];
×
833
        }
834
#endif
835
    }
836
    // probe values green
837
    if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) {
×
838
        ComputeQOIsGreenProbingLine();
×
839
    }
840
    // Update time integral values on rank 0
841
    if( _rank == 0 ) {
×
842
        _totalScalarOutflow += _curScalarOutflow * _dT;
×
843
        _totalScalarOutflowPeri1 += _curScalarOutflowPeri1 * _dT;
×
844
        _totalScalarOutflowPeri2 += _curScalarOutflowPeri2 * _dT;
×
845
        _totalAbsorptionLattice += _curAbsorptionLattice * _dT;
×
846

847
        _totalAbsorptionHohlraumCenter += _curAbsorptionHohlraumCenter * _dT;
×
848
        _totalAbsorptionHohlraumVertical += _curAbsorptionHohlraumVertical * _dT;
×
849
        _totalAbsorptionHohlraumHorizontal += _curAbsorptionHohlraumHorizontal * _dT;
×
850

851
        _rmsFlux = sqrt( _rmsFlux );
×
852
    }
853
}
854

855
bool SNSolverHPC::IsAbsorptionLattice( double x, double y ) const {
×
856
    // Check whether pos is inside absorbing squares
857
    double xy_corrector = -3.5;
×
858
    std::vector<double> lbounds{ 1 + xy_corrector, 2 + xy_corrector, 3 + xy_corrector, 4 + xy_corrector, 5 + xy_corrector };
×
859
    std::vector<double> ubounds{ 2 + xy_corrector, 3 + xy_corrector, 4 + xy_corrector, 5 + xy_corrector, 6 + xy_corrector };
×
860
    for( unsigned k = 0; k < lbounds.size(); ++k ) {
×
861
        for( unsigned l = 0; l < lbounds.size(); ++l ) {
×
862
            if( ( l + k ) % 2 == 1 || ( k == 2 && l == 2 ) || ( k == 2 && l == 4 ) ) continue;
×
863
            if( x >= lbounds[k] && x <= ubounds[k] && y >= lbounds[l] && y <= ubounds[l] ) {
×
864
                return true;
×
865
            }
866
        }
867
    }
868
    return false;
×
869
}
870

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

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

910
// --- IO ----
911
void SNSolverHPC::PrepareScreenOutput() {
×
912
    unsigned nFields = (unsigned)_settings->GetNScreenOutput();
×
913

914
    _screenOutputFieldNames.resize( nFields );
×
915
    _screenOutputFields.resize( nFields );
×
916

917
    // Prepare all output Fields ==> Specified in option SCREEN_OUTPUT
918
    for( unsigned idx_field = 0; idx_field < nFields; idx_field++ ) {
×
919
        // Prepare all Output Fields per group
920

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

956
            default: ErrorMessages::Error( "Screen output field not defined!", CURRENT_FUNCTION ); break;
×
957
        }
958
    }
959
}
960

961
void SNSolverHPC::WriteScalarOutput( unsigned idx_iter ) {
×
962
    unsigned n_probes = 4;
×
963

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

1017
    // --- History output ---
1018
    nFields = (unsigned)_settings->GetNHistoryOutput();
×
1019

1020
    std::vector<SCALAR_OUTPUT> screenOutputFields = _settings->GetScreenOutput();
×
1021
    for( unsigned idx_field = 0; idx_field < nFields; idx_field++ ) {
×
1022

1023
        // Prepare all Output Fields per group
1024
        // Different procedure, depending on the Group...
1025
        switch( _settings->GetHistoryOutput()[idx_field] ) {
×
1026
            case MASS: _historyOutputFields[idx_field] = _mass; break;
×
1027
            case ITER: _historyOutputFields[idx_field] = idx_iter; break;
×
1028
            case SIM_TIME: _historyOutputFields[idx_field] = _curSimTime; break;
×
1029
            case WALL_TIME: _historyOutputFields[idx_field] = _currTime; break;
×
1030
            case RMS_FLUX: _historyOutputFields[idx_field] = _rmsFlux; break;
×
1031
            case VTK_OUTPUT:
×
1032
                _historyOutputFields[idx_field] = 0;
×
1033
                if( ( _settings->GetVolumeOutputFrequency() != 0 && idx_iter % (unsigned)_settings->GetVolumeOutputFrequency() == 0 ) ||
×
1034
                    ( idx_iter == _nIter - 1 ) /* need sol at last iteration */ ) {
×
1035
                    _historyOutputFields[idx_field] = 1;
×
1036
                }
1037
                break;
×
1038

1039
            case CSV_OUTPUT:
×
1040
                _historyOutputFields[idx_field] = 0;
×
1041
                if( ( _settings->GetHistoryOutputFrequency() != 0 && idx_iter % (unsigned)_settings->GetHistoryOutputFrequency() == 0 ) ||
×
1042
                    ( idx_iter == _nIter - 1 ) /* need sol at last iteration */ ) {
×
1043
                    _historyOutputFields[idx_field] = 1;
×
1044
                }
1045
                break;
×
1046
            case CUR_OUTFLOW: _historyOutputFields[idx_field] = _curScalarOutflow; break;
×
1047
            case TOTAL_OUTFLOW: _historyOutputFields[idx_field] = _totalScalarOutflow; break;
×
1048
            case CUR_OUTFLOW_P1: _historyOutputFields[idx_field] = _curScalarOutflowPeri1; break;
×
1049
            case TOTAL_OUTFLOW_P1: _historyOutputFields[idx_field] = _totalScalarOutflowPeri1; break;
×
1050
            case CUR_OUTFLOW_P2: _historyOutputFields[idx_field] = _curScalarOutflowPeri2; break;
×
1051
            case TOTAL_OUTFLOW_P2: _historyOutputFields[idx_field] = _totalScalarOutflowPeri2; break;
×
1052
            case MAX_OUTFLOW: _historyOutputFields[idx_field] = _curMaxOrdinateOutflow; break;
×
1053
            case CUR_PARTICLE_ABSORPTION: _historyOutputFields[idx_field] = _curAbsorptionLattice; break;
×
1054
            case TOTAL_PARTICLE_ABSORPTION: _historyOutputFields[idx_field] = _totalAbsorptionLattice; break;
×
1055
            case MAX_PARTICLE_ABSORPTION: _historyOutputFields[idx_field] = _curMaxAbsorptionLattice; break;
×
1056
            case TOTAL_PARTICLE_ABSORPTION_CENTER: _historyOutputFields[idx_field] = _totalAbsorptionHohlraumCenter; break;
×
1057
            case TOTAL_PARTICLE_ABSORPTION_VERTICAL: _historyOutputFields[idx_field] = _totalAbsorptionHohlraumVertical; break;
×
1058
            case TOTAL_PARTICLE_ABSORPTION_HORIZONTAL: _historyOutputFields[idx_field] = _totalAbsorptionHohlraumHorizontal; break;
×
1059
            case PROBE_MOMENT_TIME_TRACE:
×
1060
                if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) n_probes = 4;
×
1061
                // if( _settings->GetProblemName() == PROBLEM_QuarterHohlraum ) n_probes = 2;
1062
                for( unsigned i = 0; i < n_probes; i++ ) {
×
1063
                    for( unsigned j = 0; j < 3; j++ ) {
×
1064
                        _historyOutputFields[idx_field] = _probingMoments[Idx2D( i, j, 3 )];
×
1065
                        idx_field++;
×
1066
                    }
1067
                }
1068
                idx_field--;
×
1069
                break;
×
1070
            case VAR_ABSORPTION_GREEN: _historyOutputFields[idx_field] = _varAbsorptionHohlraumGreen; break;
×
1071
            case ABSORPTION_GREEN_LINE:
×
1072
                for( unsigned i = 0; i < _settings->GetNumProbingCellsLineHohlraum(); i++ ) {
×
1073
                    _historyOutputFields[idx_field] = _absorptionValsLineSegment[i];
×
1074
                    idx_field++;
×
1075
                }
1076
                idx_field--;
×
1077
                break;
×
1078
            case ABSORPTION_GREEN_BLOCK:
×
1079
                for( unsigned i = 0; i < 44; i++ ) {
×
1080
                    _historyOutputFields[idx_field] = _absorptionValsBlocksGreen[i];
×
1081
                    // std::cout << _absorptionValsBlocksGreen[i] << "/" << _historyOutputFields[idx_field] << std::endl;
1082
                    idx_field++;
×
1083
                }
1084
                idx_field--;
×
1085
                break;
×
1086
            default: ErrorMessages::Error( "History output group not defined!", CURRENT_FUNCTION ); break;
×
1087
        }
1088
    }
1089
}
1090

1091
void SNSolverHPC::PrintScreenOutput( unsigned idx_iter ) {
×
1092
    auto log = spdlog::get( "event" );
×
1093

1094
    unsigned strLen  = 15;    // max width of one column
×
1095
    char paddingChar = ' ';
×
1096

1097
    // assemble the line to print
1098
    std::string lineToPrint = "| ";
×
1099
    std::string tmp;
×
1100
    for( unsigned idx_field = 0; idx_field < _settings->GetNScreenOutput(); idx_field++ ) {
×
1101
        tmp = std::to_string( _screenOutputFields[idx_field] );
×
1102

1103
        // Format outputs correctly
1104
        std::vector<SCALAR_OUTPUT> integerFields    = { ITER };
×
1105
        std::vector<SCALAR_OUTPUT> scientificFields = { RMS_FLUX,
1106
                                                        MASS,
1107
                                                        WALL_TIME,
1108
                                                        CUR_OUTFLOW,
1109
                                                        TOTAL_OUTFLOW,
1110
                                                        CUR_OUTFLOW_P1,
1111
                                                        TOTAL_OUTFLOW_P1,
1112
                                                        CUR_OUTFLOW_P2,
1113
                                                        TOTAL_OUTFLOW_P2,
1114
                                                        MAX_OUTFLOW,
1115
                                                        CUR_PARTICLE_ABSORPTION,
1116
                                                        TOTAL_PARTICLE_ABSORPTION,
1117
                                                        MAX_PARTICLE_ABSORPTION,
1118
                                                        TOTAL_PARTICLE_ABSORPTION_CENTER,
1119
                                                        TOTAL_PARTICLE_ABSORPTION_VERTICAL,
1120
                                                        TOTAL_PARTICLE_ABSORPTION_HORIZONTAL,
1121
                                                        PROBE_MOMENT_TIME_TRACE,
1122
                                                        VAR_ABSORPTION_GREEN,
1123
                                                        ABSORPTION_GREEN_BLOCK,
1124
                                                        ABSORPTION_GREEN_LINE };
×
1125
        std::vector<SCALAR_OUTPUT> booleanFields    = { VTK_OUTPUT, CSV_OUTPUT };
×
1126

1127
        if( !( integerFields.end() == std::find( integerFields.begin(), integerFields.end(), _settings->GetScreenOutput()[idx_field] ) ) ) {
×
1128
            tmp = std::to_string( (int)_screenOutputFields[idx_field] );
×
1129
        }
1130
        else if( !( booleanFields.end() == std::find( booleanFields.begin(), booleanFields.end(), _settings->GetScreenOutput()[idx_field] ) ) ) {
×
1131
            tmp = "no";
×
1132
            if( (bool)_screenOutputFields[idx_field] ) tmp = "yes";
×
1133
        }
1134
        else if( !( scientificFields.end() ==
×
1135
                    std::find( scientificFields.begin(), scientificFields.end(), _settings->GetScreenOutput()[idx_field] ) ) ) {
×
1136

1137
            std::stringstream ss;
×
1138
            ss << TextProcessingToolbox::DoubleToScientificNotation( _screenOutputFields[idx_field] );
×
1139
            tmp = ss.str();
×
1140
            tmp.erase( std::remove( tmp.begin(), tmp.end(), '+' ), tmp.end() );    // removing the '+' sign
×
1141
        }
1142

1143
        if( strLen > tmp.size() )    // Padding
×
1144
            tmp.insert( 0, strLen - tmp.size(), paddingChar );
×
1145
        else if( strLen < tmp.size() )    // Cutting
×
1146
            tmp.resize( strLen );
×
1147

1148
        lineToPrint += tmp + " |";
×
1149
    }
1150
    if( _settings->GetScreenOutputFrequency() != 0 && idx_iter % (unsigned)_settings->GetScreenOutputFrequency() == 0 ) {
×
1151
        log->info( lineToPrint );
×
1152
    }
1153
    else if( idx_iter == _nIter - 1 ) {    // Always print last iteration
×
1154
        log->info( lineToPrint );
×
1155
    }
1156
}
1157

1158
void SNSolverHPC::PrepareHistoryOutput() {
×
1159
    unsigned n_probes = 4;
×
1160

1161
    unsigned nFields = (unsigned)_settings->GetNHistoryOutput();
×
1162

1163
    _historyOutputFieldNames.resize( nFields );
×
1164
    _historyOutputFields.resize( nFields );
×
1165

1166
    // Prepare all output Fields ==> Specified in option SCREEN_OUTPUT
1167
    for( unsigned idx_field = 0; idx_field < nFields; idx_field++ ) {
×
1168
        // Prepare all Output Fields per group
1169

1170
        // Different procedure, depending on the Group...
1171
        switch( _settings->GetHistoryOutput()[idx_field] ) {
×
1172
            case MASS: _historyOutputFieldNames[idx_field] = "Mass"; break;
×
1173
            case ITER: _historyOutputFieldNames[idx_field] = "Iter"; break;
×
1174
            case SIM_TIME: _historyOutputFieldNames[idx_field] = "Sim_time"; break;
×
1175
            case WALL_TIME: _historyOutputFieldNames[idx_field] = "Wall_time_[s]"; break;
×
1176
            case RMS_FLUX: _historyOutputFieldNames[idx_field] = "RMS_flux"; break;
×
1177
            case VTK_OUTPUT: _historyOutputFieldNames[idx_field] = "VTK_out"; break;
×
1178
            case CSV_OUTPUT: _historyOutputFieldNames[idx_field] = "CSV_out"; break;
×
1179
            case CUR_OUTFLOW: _historyOutputFieldNames[idx_field] = "Cur_outflow"; break;
×
1180
            case TOTAL_OUTFLOW: _historyOutputFieldNames[idx_field] = "Total_outflow"; break;
×
1181
            case CUR_OUTFLOW_P1: _historyOutputFieldNames[idx_field] = "Cur_outflow_P1"; break;
×
1182
            case TOTAL_OUTFLOW_P1: _historyOutputFieldNames[idx_field] = "Total_outflow_P1"; break;
×
1183
            case CUR_OUTFLOW_P2: _historyOutputFieldNames[idx_field] = "Cur_outflow_P2"; break;
×
1184
            case TOTAL_OUTFLOW_P2: _historyOutputFieldNames[idx_field] = "Total_outflow_P2"; break;
×
1185
            case MAX_OUTFLOW: _historyOutputFieldNames[idx_field] = "Max_outflow"; break;
×
1186
            case CUR_PARTICLE_ABSORPTION: _historyOutputFieldNames[idx_field] = "Cur_absorption"; break;
×
1187
            case TOTAL_PARTICLE_ABSORPTION: _historyOutputFieldNames[idx_field] = "Total_absorption"; break;
×
1188
            case MAX_PARTICLE_ABSORPTION: _historyOutputFieldNames[idx_field] = "Max_absorption"; break;
×
1189
            case TOTAL_PARTICLE_ABSORPTION_CENTER: _historyOutputFieldNames[idx_field] = "Cumulated_absorption_center"; break;
×
1190
            case TOTAL_PARTICLE_ABSORPTION_VERTICAL: _historyOutputFieldNames[idx_field] = "Cumulated_absorption_vertical_wall"; break;
×
1191
            case TOTAL_PARTICLE_ABSORPTION_HORIZONTAL: _historyOutputFieldNames[idx_field] = "Cumulated_absorption_horizontal_wall"; break;
×
1192
            case PROBE_MOMENT_TIME_TRACE:
×
1193
                if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) n_probes = 4;
×
1194
                // if( _settings->GetProblemName() == PROBLEM_QuarterHohlraum ) n_probes = 2;
1195
                for( unsigned i = 0; i < n_probes; i++ ) {
×
1196
                    for( unsigned j = 0; j < 3; j++ ) {
×
1197
                        _historyOutputFieldNames[idx_field] = "Probe " + std::to_string( i ) + " u_" + std::to_string( j );
×
1198
                        idx_field++;
×
1199
                    }
1200
                }
1201
                idx_field--;
×
1202
                break;
×
1203
            case VAR_ABSORPTION_GREEN: _historyOutputFieldNames[idx_field] = "Var. absorption green"; break;
×
1204
            case ABSORPTION_GREEN_BLOCK:
×
1205
                for( unsigned i = 0; i < 44; i++ ) {
×
1206
                    _historyOutputFieldNames[idx_field] = "Probe Green Block " + std::to_string( i );
×
1207
                    idx_field++;
×
1208
                }
1209
                idx_field--;
×
1210
                break;
×
1211

1212
            case ABSORPTION_GREEN_LINE:
×
1213
                for( unsigned i = 0; i < _settings->GetNumProbingCellsLineHohlraum(); i++ ) {
×
1214
                    _historyOutputFieldNames[idx_field] = "Probe Green Line " + std::to_string( i );
×
1215
                    idx_field++;
×
1216
                }
1217
                idx_field--;
×
1218
                break;
×
1219
            default: ErrorMessages::Error( "History output field not defined!", CURRENT_FUNCTION ); break;
×
1220
        }
1221
    }
1222
}
1223

1224
void SNSolverHPC::PrintHistoryOutput( unsigned idx_iter ) {
×
1225

1226
    auto log = spdlog::get( "tabular" );
×
1227

1228
    // assemble the line to print
1229
    std::string lineToPrint = "";
×
1230
    std::string tmp;
×
1231
    for( int idx_field = 0; idx_field < _settings->GetNHistoryOutput() - 1; idx_field++ ) {
×
1232
        if( idx_field == 0 ) {
×
1233
            tmp = std::to_string( _historyOutputFields[idx_field] );    // Iteration count
×
1234
        }
1235
        else {
1236
            tmp = TextProcessingToolbox::DoubleToScientificNotation( _historyOutputFields[idx_field] );
×
1237
        }
1238
        lineToPrint += tmp + ",";
×
1239
    }
1240
    tmp = TextProcessingToolbox::DoubleToScientificNotation( _historyOutputFields[_settings->GetNHistoryOutput() - 1] );
×
1241
    lineToPrint += tmp;    // Last element without comma
×
1242
    // std::cout << lineToPrint << std::endl;
1243
    if( _settings->GetHistoryOutputFrequency() != 0 && idx_iter % (unsigned)_settings->GetHistoryOutputFrequency() == 0 ) {
×
1244
        log->info( lineToPrint );
×
1245
    }
1246
    else if( idx_iter == _nIter - 1 ) {    // Always print last iteration
×
1247
        log->info( lineToPrint );
×
1248
    }
1249
}
1250

1251
void SNSolverHPC::DrawPreSolverOutput() {
×
1252

1253
    // Logger
1254
    auto log    = spdlog::get( "event" );
×
1255
    auto logCSV = spdlog::get( "tabular" );
×
1256

1257
    std::string hLine = "--";
×
1258

1259
    unsigned strLen  = 15;    // max width of one column
×
1260
    char paddingChar = ' ';
×
1261

1262
    // Assemble Header for Screen Output
1263
    std::string lineToPrint = "| ";
×
1264
    std::string tmpLine     = "-----------------";
×
1265
    for( unsigned idxFields = 0; idxFields < _settings->GetNScreenOutput(); idxFields++ ) {
×
1266
        std::string tmp = _screenOutputFieldNames[idxFields];
×
1267

1268
        if( strLen > tmp.size() )    // Padding
×
1269
            tmp.insert( 0, strLen - tmp.size(), paddingChar );
×
1270
        else if( strLen < tmp.size() )    // Cutting
×
1271
            tmp.resize( strLen );
×
1272

1273
        lineToPrint += tmp + " |";
×
1274
        hLine += tmpLine;
×
1275
    }
1276
    log->info( "---------------------------- Solver Starts -----------------------------" );
×
1277
    log->info( "| The simulation will run for {} iterations.", _nIter );
×
1278
    log->info( "| The spatial grid contains {} cells.", _nCells );
×
1279
    if( _settings->GetSolverName() != PN_SOLVER && _settings->GetSolverName() != CSD_PN_SOLVER ) {
×
1280
        log->info( "| The velocity grid contains {} points.", _nq );
×
1281
    }
1282
    log->info( hLine );
×
1283
    log->info( lineToPrint );
×
1284
    log->info( hLine );
×
1285

1286
    std::string lineToPrintCSV = "";
×
1287
    for( int idxFields = 0; idxFields < _settings->GetNHistoryOutput() - 1; idxFields++ ) {
×
1288
        std::string tmp = _historyOutputFieldNames[idxFields];
×
1289
        lineToPrintCSV += tmp + ",";
×
1290
    }
1291
    lineToPrintCSV += _historyOutputFieldNames[_settings->GetNHistoryOutput() - 1];
×
1292
    logCSV->info( lineToPrintCSV );
×
1293
}
1294

1295
void SNSolverHPC::DrawPostSolverOutput() {
×
1296

1297
    // Logger
1298
    auto log = spdlog::get( "event" );
×
1299

1300
    std::string hLine = "--";
×
1301

1302
    unsigned strLen  = 10;    // max width of one column
×
1303
    char paddingChar = ' ';
×
1304

1305
    // Assemble Header for Screen Output
1306
    std::string lineToPrint = "| ";
×
1307
    std::string tmpLine     = "------------";
×
1308
    for( unsigned idxFields = 0; idxFields < _settings->GetNScreenOutput(); idxFields++ ) {
×
1309
        std::string tmp = _screenOutputFieldNames[idxFields];
×
1310

1311
        if( strLen > tmp.size() )    // Padding
×
1312
            tmp.insert( 0, strLen - tmp.size(), paddingChar );
×
1313
        else if( strLen < tmp.size() )    // Cutting
×
1314
            tmp.resize( strLen );
×
1315

1316
        lineToPrint += tmp + " |";
×
1317
        hLine += tmpLine;
×
1318
    }
1319
    log->info( hLine );
×
1320
#ifndef BUILD_TESTING
1321
    log->info( "| The volume output files have been stored at " + _settings->GetOutputFile() );
1322
    log->info( "| The log files have been stored at " + _settings->GetLogDir() + _settings->GetLogFile() );
1323
#endif
1324
    log->info( "--------------------------- Solver Finished ----------------------------" );
×
1325
}
1326

1327
unsigned long SNSolverHPC::Idx2D( unsigned long idx1, unsigned long idx2, unsigned long len2 ) { return idx1 * len2 + idx2; }
×
1328

1329
unsigned long SNSolverHPC::Idx3D( unsigned long idx1, unsigned long idx2, unsigned long idx3, unsigned long len2, unsigned long len3 ) {
×
1330
    return ( idx1 * len2 + idx2 ) * len3 + idx3;
×
1331
}
1332

1333
void SNSolverHPC::WriteVolumeOutput( unsigned idx_iter ) {
×
1334
    unsigned nGroups = (unsigned)_settings->GetNVolumeOutput();
×
1335
    if( ( _settings->GetVolumeOutputFrequency() != 0 && idx_iter % (unsigned)_settings->GetVolumeOutputFrequency() == 0 ) ||
×
1336
        ( idx_iter == _nIter - 1 ) /* need sol at last iteration */ ) {
×
1337
        for( unsigned idx_group = 0; idx_group < nGroups; idx_group++ ) {
×
1338
            switch( _settings->GetVolumeOutput()[idx_group] ) {
×
1339
                case MINIMAL:
×
1340
                    if( _rank == 0 ) {
×
1341
                        _outputFields[idx_group][0] = _scalarFlux;
×
1342
                    }
1343
                    break;
×
1344

1345
                case MOMENTS:
×
1346
#pragma omp parallel for
×
1347
                    for( unsigned idx_cell = 0; idx_cell < _nCells; ++idx_cell ) {
1348
                        _outputFields[idx_group][0][idx_cell] = 0.0;
1349
                        _outputFields[idx_group][1][idx_cell] = 0.0;
1350
                        for( unsigned idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
1351
                            _outputFields[idx_group][0][idx_cell] +=
1352
                                _quadPts[Idx2D( idx_sys, 0, _nDim )] * _sol[Idx2D( idx_cell, idx_sys, _localNSys )] * _quadWeights[idx_sys];
1353
                            _outputFields[idx_group][1][idx_cell] +=
1354
                                _quadPts[Idx2D( idx_sys, 1, _nDim )] * _sol[Idx2D( idx_cell, idx_sys, _localNSys )] * _quadWeights[idx_sys];
1355
                        }
1356
                    }
1357
#ifdef IMPORT_MPI
1358
                    MPI_Barrier( MPI_COMM_WORLD );
1359
                    MPI_Allreduce(
1360
                        _outputFields[idx_group][0].data(), _outputFields[idx_group][0].data(), _nCells, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
1361
                    MPI_Allreduce(
1362
                        _outputFields[idx_group][1].data(), _outputFields[idx_group][1].data(), _nCells, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
1363
                    MPI_Barrier( MPI_COMM_WORLD );
1364
#endif
1365
                    break;
×
1366
                default: ErrorMessages::Error( "Volume Output Group not defined for HPC SN Solver!", CURRENT_FUNCTION ); break;
×
1367
            }
1368
        }
1369
    }
1370
}
1371

1372
void SNSolverHPC::PrintVolumeOutput( int idx_iter ) {
×
1373
    if( _settings->GetSaveRestartSolutionFrequency() != 0 && idx_iter % (int)_settings->GetSaveRestartSolutionFrequency() == 0 ) {
×
1374
        // std::cout << "Saving restart solution at iteration " << idx_iter << std::endl;
1375
        WriteRestartSolution( _settings->GetOutputFile(),
×
1376
                              _sol,
×
1377
                              _scalarFlux,
×
1378
                              _rank,
1379
                              idx_iter,
1380
                              _totalAbsorptionHohlraumCenter,
1381
                              _totalAbsorptionHohlraumVertical,
1382
                              _totalAbsorptionHohlraumHorizontal,
1383
                              _totalAbsorptionLattice );
1384
    }
1385

1386
    if( _settings->GetVolumeOutputFrequency() != 0 && idx_iter % (int)_settings->GetVolumeOutputFrequency() == 0 ) {
×
1387
        WriteVolumeOutput( idx_iter );
×
1388
        if( _rank == 0 ) {
×
1389
            ExportVTK( _settings->GetOutputFile() + "_" + std::to_string( idx_iter ), _outputFields, _outputFieldNames, _mesh );    // slow
×
1390
        }
1391
    }
1392
    if( idx_iter == (int)_nIter - 1 ) {    // Last iteration write without suffix.
×
1393
        WriteVolumeOutput( idx_iter );
×
1394
        if( _rank == 0 ) {
×
1395
            ExportVTK( _settings->GetOutputFile(), _outputFields, _outputFieldNames, _mesh );
×
1396
        }
1397
    }
1398
}
1399

1400
void SNSolverHPC::PrepareVolumeOutput() {
×
1401
    unsigned nGroups = (unsigned)_settings->GetNVolumeOutput();
×
1402

1403
    _outputFieldNames.resize( nGroups );
×
1404
    _outputFields.resize( nGroups );
×
1405

1406
    // Prepare all OutputGroups ==> Specified in option VOLUME_OUTPUT
1407
    for( unsigned idx_group = 0; idx_group < nGroups; idx_group++ ) {
×
1408
        // Prepare all Output Fields per group
1409

1410
        // Different procedure, depending on the Group...
1411
        switch( _settings->GetVolumeOutput()[idx_group] ) {
×
1412
            case MINIMAL:
×
1413
                // Currently only one entry ==> rad flux
1414
                _outputFields[idx_group].resize( 1 );
×
1415
                _outputFieldNames[idx_group].resize( 1 );
×
1416

1417
                _outputFields[idx_group][0].resize( _nCells );
×
1418
                _outputFieldNames[idx_group][0] = "scalar flux";
×
1419
                break;
×
1420
            case MOMENTS:
×
1421
                // As many entries as there are moments in the system
1422
                _outputFields[idx_group].resize( _nOutputMoments );
×
1423
                _outputFieldNames[idx_group].resize( _nOutputMoments );
×
1424

1425
                for( unsigned idx_moment = 0; idx_moment < _nOutputMoments; idx_moment++ ) {
×
1426
                    _outputFieldNames[idx_group][idx_moment] = std::string( "u_" + std::to_string( idx_moment ) );
×
1427
                    _outputFields[idx_group][idx_moment].resize( _nCells );
×
1428
                }
1429
                break;
×
1430

1431
            default: ErrorMessages::Error( "Volume Output Group not defined for HPC SN Solver!", CURRENT_FUNCTION ); break;
×
1432
        }
1433
    }
1434
}
1435

1436
void SNSolverHPC::SetGhostCells() {
×
1437
    if( _settings->GetProblemName() == PROBLEM_Lattice ) {
×
1438
        // #pragma omp parallel for
1439
        for( unsigned idx_cell = 0; idx_cell < _nCells; idx_cell++ ) {
×
1440
            if( _cellBoundaryTypes[idx_cell] == BOUNDARY_TYPE::NEUMANN || _cellBoundaryTypes[idx_cell] == BOUNDARY_TYPE::DIRICHLET ) {
×
1441
                _ghostCells[idx_cell] = std::vector<double>( _localNSys, 0.0 );
×
1442
            }
1443
        }
1444
    }
1445
    else if( _settings->GetProblemName() == PROBLEM_HalfLattice ) {    // HALF LATTICE NOT WORKING
×
1446
        ErrorMessages::Error( "Test case does not work with MPI", CURRENT_FUNCTION );
×
1447
    }
1448
    else if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) {
×
1449

1450
        auto nodes = _mesh->GetNodes();
×
1451
        double tol = 1e-12;    // For distance to boundary
×
1452

1453
        // #pragma omp parallel for
1454
        for( unsigned idx_cell = 0; idx_cell < _nCells; idx_cell++ ) {
×
1455

1456
            if( _cellBoundaryTypes[idx_cell] == BOUNDARY_TYPE::NEUMANN || _cellBoundaryTypes[idx_cell] == BOUNDARY_TYPE::DIRICHLET ) {
×
1457
                _ghostCells[idx_cell] = std::vector<double>( _localNSys, 0.0 );
×
1458

1459
                auto localCellNodes = _mesh->GetCells()[idx_cell];
×
1460

1461
                for( unsigned idx_node = 0; idx_node < _mesh->GetNumNodesPerCell(); idx_node++ ) {    // Check if corner node is in this cell
×
1462
                    if( nodes[localCellNodes[idx_node]][0] < -0.65 + tol ) {                          // close to 0 => left boundary
×
1463
                        for( unsigned idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
×
1464
                            if( _quadPts[Idx2D( idx_sys, 0, _nDim )] > 0.0 ) _ghostCells[idx_cell][idx_sys] = 1.0;
×
1465
                        }
1466
                        break;
×
1467
                    }
1468
                    else if( nodes[localCellNodes[idx_node]][0] > 0.65 - tol ) {    // right boundary
×
1469
                        for( unsigned idx_sys = 0; idx_sys < _localNSys; idx_sys++ ) {
×
1470
                            if( _quadPts[Idx2D( idx_sys, 0, _nDim )] < 0.0 ) _ghostCells[idx_cell][idx_sys] = 1.0;
×
1471
                        }
1472
                        break;
×
1473
                    }
1474
                    else if( nodes[localCellNodes[idx_node]][1] < -0.65 + tol ) {    // lower boundary
×
1475
                        break;
×
1476
                    }
1477
                    else if( nodes[localCellNodes[idx_node]][1] > 0.65 - tol ) {    // upper boundary
×
1478
                        break;
×
1479
                    }
1480
                    else if( idx_node == _mesh->GetNumNodesPerCell() - 1 ) {
×
1481
                        ErrorMessages::Error( " Problem with ghost cell setup and  boundary of this mesh ", CURRENT_FUNCTION );
×
1482
                    }
1483
                }
1484
            }
1485
        }
1486
    }
1487
    else if( _settings->GetProblemName() == PROBLEM_QuarterHohlraum ) {
×
1488
        ErrorMessages::Error( "Test case does not work with MPI", CURRENT_FUNCTION );
×
1489
    }
1490
}
1491

1492
void SNSolverHPC::SetProbingCellsLineGreen() {
×
1493

UNCOV
1494
    if( _settings->GetProblemName() == PROBLEM_SymmetricHohlraum ) {
×
NEW
1495
        assert( _nProbingCellsLineGreen % 2 == 0 );
×
1496

1497
        std::vector<double> p1 = { _cornerUpperLeftGreen[0] + _thicknessGreen / 2.0, _cornerUpperLeftGreen[1] - _thicknessGreen / 2.0 };
×
1498
        std::vector<double> p2 = { _cornerUpperRightGreen[0] - _thicknessGreen / 2.0, _cornerUpperRightGreen[1] - _thicknessGreen / 2.0 };
×
1499
        std::vector<double> p3 = { _cornerLowerRightGreen[0] - _thicknessGreen / 2.0, _cornerLowerRightGreen[1] + _thicknessGreen / 2.0 };
×
1500
        std::vector<double> p4 = { _cornerLowerLeftGreen[0] + _thicknessGreen / 2.0, _cornerLowerLeftGreen[1] + _thicknessGreen / 2.0 };
×
1501

1502
        double verticalLineWidth   = std::abs( p1[1] - p4[1] );
×
1503
        double horizontalLineWidth = std::abs( p1[0] - p2[0] );
×
1504

1505
        double pt_ratio_h = horizontalLineWidth / ( horizontalLineWidth + verticalLineWidth );
×
1506
        double pt_ratio_v = verticalLineWidth / ( horizontalLineWidth + verticalLineWidth );
×
1507

1508
        unsigned nHorizontalProbingCells = (unsigned)std::ceil( _nProbingCellsLineGreen / 2 * pt_ratio_h );
×
1509
        unsigned nVerticalProbingCells   = _nProbingCellsLineGreen / 2 - nHorizontalProbingCells;
×
NEW
1510
        assert( nHorizontalProbingCells > 1 );
×
NEW
1511
        assert( nVerticalProbingCells > 1 );
×
1512

1513
        _probingCellsLineGreen = std::vector<unsigned>( 2 * ( nVerticalProbingCells + nHorizontalProbingCells ) );
×
1514

1515
        // Sample points on each side of the rectangle
1516
        std::vector<unsigned> side1 = linspace2D( p1, p2, nHorizontalProbingCells );    // upper horizontal
×
1517
        std::vector<unsigned> side2 = linspace2D( p2, p3, nVerticalProbingCells );      // right vertical
×
1518
        std::vector<unsigned> side3 = linspace2D( p3, p4, nHorizontalProbingCells );    // lower horizontal
×
1519
        std::vector<unsigned> side4 = linspace2D( p4, p1, nVerticalProbingCells );      // left vertical
×
1520

1521
        for( unsigned i = 0; i < nHorizontalProbingCells; ++i ) {
×
1522
            _probingCellsLineGreen[i] = side1[i];
×
1523
        }
1524
        for( unsigned i = 0; i < nVerticalProbingCells; ++i ) {
×
1525
            _probingCellsLineGreen[i + nHorizontalProbingCells] = side2[i];
×
1526
        }
1527
        for( unsigned i = 0; i < nHorizontalProbingCells; ++i ) {
×
1528
            _probingCellsLineGreen[i + nVerticalProbingCells + nHorizontalProbingCells] = side3[i];
×
1529
        }
1530
        for( unsigned i = 0; i < nVerticalProbingCells; ++i ) {
×
1531
            _probingCellsLineGreen[i + nVerticalProbingCells + 2 * nHorizontalProbingCells] = side4[i];
×
1532
        }
1533

1534
        // Block-wise approach
1535
        // Initialize the vector to store the corner points of each block
1536
        std::vector<std::vector<std::vector<double>>> block_corners;
×
1537

1538
        double block_size = 0.05;
×
NEW
1539
        const double cx   = _centerGreen[0];
×
NEW
1540
        const double cy   = _centerGreen[1];
×
1541

1542
        // Loop to fill the blocks
1543
        for( int i = 0; i < 8; ++i ) {    // 8 blocks in the x-direction (horizontal) (upper) (left to right)
×
1544

1545
            // Top row
NEW
1546
            double x1 = -0.2 + cx + i * block_size;
×
NEW
1547
            double y1 = 0.4 + cy;
×
1548
            double x2 = x1 + block_size;
×
1549
            double y2 = y1 - block_size;
×
1550

1551
            std::vector<std::vector<double>> corners = {
1552
                { x1, y1 },    // top-left
1553
                { x2, y1 },    // top-right
1554
                { x2, y2 },    // bottom-right
1555
                { x1, y2 }     // bottom-left
1556
            };
1557
            block_corners.push_back( corners );
×
1558
        }
1559

1560
        for( int j = 0; j < 14; ++j ) {    // 14 blocks in the y-direction (vertical)
×
1561
            // right column double x1 = 0.15;
NEW
1562
            double x1 = 0.15 + cx;
×
NEW
1563
            double y1 = 0.35 + cy - j * block_size;
×
1564
            double x2 = x1 + block_size;
×
1565
            double y2 = y1 - block_size;
×
1566

1567
            // Store the four corner points for this block
1568
            std::vector<std::vector<double>> corners = {
1569
                { x1, y1 },    // top-left
1570
                { x2, y1 },    // top-right
1571
                { x2, y2 },    // bottom-right
1572
                { x1, y2 }     // bottom-left
1573
            };
1574

1575
            block_corners.push_back( corners );
×
1576
        }
1577

1578
        for( int i = 0; i < 8; ++i ) {    // 8 blocks in the x-direction (horizontal) (lower) (right to left)
×
1579
            // bottom row
NEW
1580
            double x1 = 0.15 + cx - i * block_size;
×
NEW
1581
            double y1 = -0.35 + cy;
×
1582
            double x2 = x1 + block_size;
×
1583
            double y2 = y1 - block_size;
×
1584

1585
            std::vector<std::vector<double>> corners = {
1586
                { x1, y1 },    // top-left
1587
                { x2, y1 },    // top-right
1588
                { x2, y2 },    // bottom-right
1589
                { x1, y2 }     // bottom-left
1590
            };
1591
            block_corners.push_back( corners );
×
1592
        }
1593

1594
        for( int j = 0; j < 14; ++j ) {    // 14 blocks in the y-direction (vertical) (down to up)
×
1595

1596
            // left column
NEW
1597
            double x1 = -0.2 + cx;
×
NEW
1598
            double y1 = -0.3 + cy + j * block_size;
×
1599
            double x2 = x1 + block_size;
×
1600
            double y2 = y1 - block_size;
×
1601

1602
            // Store the four corner points for this block
1603
            std::vector<std::vector<double>> corners = {
1604
                { x1, y1 },    // top-left
1605
                { x2, y1 },    // top-right
1606
                { x2, y2 },    // bottom-right
1607
                { x1, y2 }     // bottom-left
1608
            };
1609

1610
            block_corners.push_back( corners );
×
1611
        }
1612

1613
        // Compute the probing cells for each block
1614
        for( int i = 0; i < _nProbingCellsBlocksGreen; i++ ) {
×
1615
            _probingCellsBlocksGreen.push_back( _mesh->GetCellsofRectangle( block_corners[i] ) );
×
1616
        }
1617
    }
1618
}
1619

1620
void SNSolverHPC::ComputeQOIsGreenProbingLine() {
×
1621
    double verticalLineWidth   = std::abs( _cornerUpperLeftGreen[1] - _cornerLowerLeftGreen[1] - _thicknessGreen );
×
1622
    double horizontalLineWidth = std::abs( _cornerUpperLeftGreen[0] - _cornerUpperRightGreen[0] - _thicknessGreen );
×
1623

1624
    double dl    = 2 * ( horizontalLineWidth + verticalLineWidth ) / ( (double)_nProbingCellsLineGreen );
×
1625
    double area  = dl * _thicknessGreen;
×
1626
    double l_max = _nProbingCellsLineGreen * dl;
×
1627

1628
#pragma omp parallel for
×
1629
    for( unsigned i = 0; i < _nProbingCellsLineGreen; i++ ) {    // Loop over probing cells
1630
        _absorptionValsLineSegment[i] =
1631
            ( _sigmaT[_probingCellsLineGreen[i]] - _sigmaS[_probingCellsLineGreen[i]] ) * _scalarFlux[_probingCellsLineGreen[i]];
1632
    }
1633

1634
    // Block-wise approach
1635
    // #pragma omp parallel for
1636
    for( unsigned i = 0; i < _nProbingCellsBlocksGreen; i++ ) {
×
1637
        _absorptionValsBlocksGreen[i] = 0.0;
×
1638
        for( unsigned j = 0; j < _probingCellsBlocksGreen[i].size(); j++ ) {
×
1639
            _absorptionValsBlocksGreen[i] += ( _sigmaT[_probingCellsBlocksGreen[i][j]] - _sigmaS[_probingCellsBlocksGreen[i][j]] ) *
×
1640
                                             _scalarFlux[_probingCellsBlocksGreen[i][j]] * _areas[_probingCellsBlocksGreen[i][j]];
×
1641
        }
1642
    }
1643
    // std::cout << _absorptionValsBlocksGreen[1] << std::endl;
1644
    // std::cout << _absorptionValsLineSegment[1] << std::endl;
1645
}
1646

1647
std::vector<unsigned> SNSolverHPC::linspace2D( const std::vector<double>& start, const std::vector<double>& end, unsigned num_points ) {
×
1648
    /**
1649
     * Generate a 2D linspace based on the start and end points with a specified number of points.
1650
     *
1651
     * @param start vector of starting x and y coordinates
1652
     * @param end vector of ending x and y coordinates
1653
     * @param num_points number of points to generate
1654
     *
1655
     * @return vector of unsigned integers representing the result
1656
     */
1657

1658
    std::vector<unsigned> result;
×
NEW
1659
    assert( num_points > 1 );
×
1660
    result.resize( num_points );
×
1661
    double stepX = ( end[0] - start[0] ) / ( num_points - 1 );
×
1662
    double stepY = ( end[1] - start[1] ) / ( num_points - 1 );
×
1663
#pragma omp parallel for
×
1664
    for( unsigned i = 0; i < num_points; ++i ) {
1665
        double x = start[0] + i * stepX;
1666
        double y = start[1] + i * stepY;
1667

1668
        result[i] = _mesh->GetCellOfKoordinate( x, y );
1669
    }
1670

1671
    return result;
×
1672
}
1673

1674
void SNSolverHPC::ComputeCellsPerimeterLattice() {
×
1675
    double l_1    = 1.5;    // perimeter 1
×
1676
    double l_2    = 2.5;    // perimeter 2
×
1677
    auto nodes    = _mesh->GetNodes();
×
1678
    auto cells    = _mesh->GetCells();
×
1679
    auto cellMids = _mesh->GetCellMidPoints();
×
1680
    auto normals  = _mesh->GetNormals();
×
1681
    auto neigbors = _mesh->GetNeighbours();
×
1682

1683
    _isPerimeterLatticeCell1.resize( _mesh->GetNumCells(), false );
×
1684
    _isPerimeterLatticeCell2.resize( _mesh->GetNumCells(), false );
×
1685

1686
    for( unsigned idx_cell = 0; idx_cell < _mesh->GetNumCells(); ++idx_cell ) {
×
1687
        if( abs( cellMids[idx_cell][0] ) < l_1 && abs( cellMids[idx_cell][1] ) < l_1 ) {
×
1688
            // Cell is within perimeter
1689
            for( unsigned idx_nbr = 0; idx_nbr < _mesh->GetNumNodesPerCell(); ++idx_nbr ) {
×
1690
                if( neigbors[idx_cell][idx_nbr] == _mesh->GetNumCells() ) {
×
1691
                    continue;    // Skip boundary - ghost cells
×
1692
                }
1693

NEW
1694
                if( ( abs( cellMids[neigbors[idx_cell][idx_nbr]][0] ) > l_1 && abs( cellMids[idx_cell][0] ) < l_1 ) ||
×
NEW
1695
                    ( abs( cellMids[neigbors[idx_cell][idx_nbr]][1] ) > l_1 && abs( cellMids[idx_cell][1] ) < l_1 ) ) {
×
1696
                    // neighbor is outside perimeter
1697
                    _cellsLatticePerimeter1[idx_cell].push_back( idx_nbr );
×
1698
                    _isPerimeterLatticeCell1[idx_cell] = true;
×
1699
                }
1700
            }
1701
        }
NEW
1702
        else if( abs( cellMids[idx_cell][0] ) < l_2 && abs( cellMids[idx_cell][1] ) < l_2 ) {
×
1703
            // Cell is within perimeter
1704
            for( unsigned idx_nbr = 0; idx_nbr < _mesh->GetNumNodesPerCell(); ++idx_nbr ) {
×
1705
                if( neigbors[idx_cell][idx_nbr] == _mesh->GetNumCells() ) {
×
1706
                    continue;    // Skip boundary - ghost cells
×
1707
                }
NEW
1708
                if( ( abs( cellMids[neigbors[idx_cell][idx_nbr]][0] ) > l_2 && abs( cellMids[idx_cell][0] ) < l_2 ) ||
×
NEW
1709
                    ( abs( cellMids[neigbors[idx_cell][idx_nbr]][1] ) > l_2 && abs( cellMids[idx_cell][1] ) < l_2 ) ) {
×
1710
                    // neighbor is outside perimeter
1711
                    _cellsLatticePerimeter2[idx_cell].push_back( idx_nbr );
×
1712
                    _isPerimeterLatticeCell2[idx_cell] = true;
×
1713
                }
1714
            }
1715
        }
1716
    }
1717
}
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