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

CSMMLab / KiT-RT / #110

09 Oct 2025 07:43PM UTC coverage: 46.626% (-0.03%) from 46.655%
#110

push

travis-ci

web-flow
Merge 740a903b1 into 5a519d0c8

2 of 12 new or added lines in 2 files covered. (16.67%)

24 existing lines in 2 files now uncovered.

4422 of 9484 relevant lines covered (46.63%)

57126.88 hits per line

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

69.26
/src/common/config.cpp
1
/*!
2
 * \file config.cpp
3
 * \brief Class for different Options in rtsn
4
 * \author S. Schotthoefer
5
 *
6
 * Disclaimer: This class structure was copied and modifed with open source permission from SU2 v7.0.3 https://su2code.github.io/
7
 */
8
#ifdef IMPORT_MPI
9
#include <mpi.h>
10
#endif
11
#include "common/config.hpp"
12
#include "common/globalconstants.hpp"
13
#include "common/optionstructure.hpp"
14
#include "quadratures/quadraturebase.hpp"
15
#include "toolboxes/errormessages.hpp"
16
#include "toolboxes/textprocessingtoolbox.hpp"
17

18
// externals
19
#include "spdlog/sinks/basic_file_sink.h"
20
#include "spdlog/sinks/stdout_sinks.h"
21
#include "spdlog/spdlog.h"
22
#include <filesystem>
23
#include <fstream>
24

25
using namespace std;
26

27
Config::Config( string case_filename ) {
86✔
28

29
    /*--- Set the case name to the base config file name without extension ---*/
30

31
    auto cwd     = std::filesystem::current_path();
172✔
32
    auto relPath = std::filesystem::relative( std::filesystem::path( case_filename ), cwd );
172✔
33
    _fileName    = relPath.filename().string();
86✔
34
    _inputDir    = cwd.string() + "/" + relPath.parent_path().string();
86✔
35

36
    _baseConfig = true;
86✔
37

38
    /*--- Store MPI rank and size ---*/
39
    // TODO with MPI implementation
40

41
    /*--- Initialize pointers to Null---*/
42

43
    SetPointersNull();
86✔
44

45
    /*--- Reading config options  ---*/
46

47
    SetConfigOptions();
86✔
48

49
    /*--- Parsing the config file  ---*/
50

51
    SetConfigParsing( case_filename );
86✔
52

53
    /*--- Set the default values for all of the options that weren't set ---*/
54

55
    SetDefault();
86✔
56

57
    /*--- Get the Mesh Value--- */
58

59
    // val_nDim = GetnDim(Mesh_FileName, Mesh_FileFormat);
60
    // TODO
61

62
    /*--- Configuration file postprocessing ---*/
63

64
    SetPostprocessing();
86✔
65

66
    /*--- Configuration file boundaries/markers setting ---*/
67

68
    // SetBoundary(); IDK how boundaries are implemented, but i think this should be treated here
69

70
    /*--- Configuration file output ---*/
71

72
    // if ((rank == MASTER_NODE))
73
    SetOutput();
86✔
74
}
86✔
75

76
Config::~Config( void ) {
24✔
77
    // Delete all introduced arrays!
78

79
    // delete _option map values proberly
80
    for( auto const& x : _optionMap ) {
1,968✔
81
        delete x.second;
1,944✔
82
        //_optionMap.erase( x.first );
83
    }
84
}
24✔
85

86
// ---- Add Options ----
87

88
// Simple Options
89
void Config::AddBoolOption( const string name, bool& option_field, bool default_value ) {
1,204✔
90
    // Check if the key is already in the map. If this fails, it is coder error
91
    // and not user error, so throw.
92
    assert( _optionMap.find( name ) == _optionMap.end() );
1,204✔
93

94
    // Add this option to the list of all the options
95
    _allOptions.insert( pair<string, bool>( name, true ) );
1,204✔
96

97
    // Create the parser for a bool option with a reference to the option_field and the desired
98
    // default value. This will take the string in the config file, convert it to a bool, and
99
    // place that bool in the memory location specified by the reference.
100
    OptionBase* val = new OptionBool( name, option_field, default_value );
1,204✔
101

102
    // Create an association between the option name ("CFL") and the parser generated above.
103
    // During configuration, the parsing script will get the option name, and use this map
104
    // to find how to parse that option.
105
    _optionMap.insert( pair<string, OptionBase*>( name, val ) );
1,204✔
106
}
1,204✔
107

108
void Config::AddDoubleOption( const string name, double& option_field, double default_value ) {
2,150✔
109
    assert( _optionMap.find( name ) == _optionMap.end() );
2,150✔
110
    _allOptions.insert( pair<string, bool>( name, true ) );
2,150✔
111
    OptionBase* val = new OptionDouble( name, option_field, default_value );
2,150✔
112
    _optionMap.insert( pair<string, OptionBase*>( name, val ) );
2,150✔
113
}
2,150✔
114

115
void Config::AddIntegerOption( const string name, int& option_field, int default_value ) {
×
116
    assert( _optionMap.find( name ) == _optionMap.end() );
×
117
    _allOptions.insert( pair<string, bool>( name, true ) );
×
118
    OptionBase* val = new OptionInt( name, option_field, default_value );
×
119
    _optionMap.insert( pair<string, OptionBase*>( name, val ) );
×
120
}
121

122
void Config::AddLongOption( const string name, long& option_field, long default_value ) {
×
123
    assert( _optionMap.find( name ) == _optionMap.end() );
×
124
    _allOptions.insert( pair<string, bool>( name, true ) );
×
125
    OptionBase* val = new OptionLong( name, option_field, default_value );
×
126
    _optionMap.insert( pair<string, OptionBase*>( name, val ) );
×
127
}
128

129
void Config::AddStringOption( const string name, string& option_field, string default_value ) {
860✔
130
    assert( _optionMap.find( name ) == _optionMap.end() );
860✔
131
    _allOptions.insert( pair<string, bool>( name, true ) );
860✔
132
    OptionBase* val = new OptionString( name, option_field, default_value );
860✔
133
    _optionMap.insert( pair<string, OptionBase*>( name, val ) );
860✔
134
}
860✔
135

136
void Config::AddUnsignedLongOption( const string name, unsigned long& option_field, unsigned long default_value ) {
430✔
137
    assert( _optionMap.find( name ) == _optionMap.end() );
430✔
138
    _allOptions.insert( pair<string, bool>( name, true ) );
430✔
139
    OptionBase* val = new OptionULong( name, option_field, default_value );
430✔
140
    _optionMap.insert( pair<string, OptionBase*>( name, val ) );
430✔
141
}
430✔
142

143
void Config::AddUnsignedShortOption( const string name, unsigned short& option_field, unsigned short default_value ) {
1,032✔
144
    assert( _optionMap.find( name ) == _optionMap.end() );
1,032✔
145
    _allOptions.insert( pair<string, bool>( name, true ) );
1,032✔
146
    OptionBase* val = new OptionUShort( name, option_field, default_value );
1,032✔
147
    _optionMap.insert( pair<string, OptionBase*>( name, val ) );
1,032✔
148
}
1,032✔
149

150
// enum types work differently than all of the others because there are a small number of valid
151
// string entries for the type. One must also provide a list of all the valid strings of that type.
152
template <class Tenum> void Config::AddEnumOption( const string name, Tenum& option_field, const map<string, Tenum>& enum_map, Tenum default_value ) {
688✔
153
    assert( _optionMap.find( name ) == _optionMap.end() );
688✔
154
    _allOptions.insert( pair<string, bool>( name, true ) );
688✔
155
    OptionBase* val = new OptionEnum<Tenum>( name, enum_map, option_field, default_value );
688✔
156
    _optionMap.insert( pair<string, OptionBase*>( name, val ) );
688✔
157
    return;
1,376✔
158
}
159

86✔
160
// List Options
86✔
161
void Config::AddStringListOption( const string name, unsigned short& num_marker, std::vector<std::string>& option_field ) {
86✔
162
    assert( _optionMap.find( name ) == _optionMap.end() );
86✔
163
    _allOptions.insert( pair<string, bool>( name, true ) );
86✔
164
    OptionBase* val = new OptionStringList( name, num_marker, option_field );
172✔
165
    _optionMap.insert( pair<string, OptionBase*>( name, val ) );
166
}
86✔
167

86✔
168
void Config::AddDoubleListOption( const string name, unsigned short& num_marker, std::vector<double>& option_field ) {
86✔
169
    assert( _optionMap.find( name ) == _optionMap.end() );
86✔
170
    _allOptions.insert( pair<string, bool>( name, true ) );
86✔
171
    OptionBase* val = new OptionDoubleList( name, num_marker, option_field );
172✔
172
    _optionMap.insert( pair<string, OptionBase*>( name, val ) );
173
}
86✔
174

86✔
175
template <class Tenum>
86✔
176
void Config::AddEnumListOption( const std::string name,
86✔
177
                                unsigned short& input_size,
86✔
178
                                std::vector<Tenum>& option_field,
172✔
179
                                const map<std::string, Tenum>& enum_map ) {
180
    input_size = 0;
86✔
181
    assert( _optionMap.find( name ) == _optionMap.end() );
86✔
182
    _allOptions.insert( pair<string, bool>( name, true ) );
86✔
183
    OptionBase* val = new OptionEnumList<Tenum>( name, enum_map, option_field, input_size );
86✔
184
    _optionMap.insert( pair<string, OptionBase*>( name, val ) );
86✔
185
}
172✔
186

187
// ---- Getter Functions ----
86✔
188

86✔
189
BOUNDARY_TYPE Config::GetBoundaryType( std::string name ) const {
86✔
190
    for( unsigned i = 0; i < _boundaries.size(); ++i ) {
86✔
191
        if( name == _boundaries[i].first ) return _boundaries[i].second;
86✔
192
    }
172✔
193
    return BOUNDARY_TYPE::INVALID;
194
}
86✔
195

86✔
196
// ---- Setter Functions ----
86✔
197

86✔
198
void Config::SetDefault() {
86✔
199
    /*--- Set the default values for all of the options that weren't set ---*/
172✔
200

201
    for( map<string, bool>::iterator iter = _allOptions.begin(); iter != _allOptions.end(); ++iter ) {
86✔
202
        if( _optionMap[iter->first]->GetValue().size() == 0 ) _optionMap[iter->first]->SetDefault();
86✔
203
    }
86✔
204
}
86✔
205

86✔
206
void Config::SetConfigOptions() {
172✔
207

208
    /* BEGIN_CONFIG_OPTIONS */
86✔
209

86✔
210
    /*! @par CONFIG_CATEGORY: Problem Definition \ingroup Config */
86✔
211
    /*--- Options related to problem definition and partitioning ---*/
86✔
212

86✔
213
    // File Structure related options
172✔
214
    /*! @brief OUTPUT_DIR \n DESCRIPTION: Relative Directory of output files \n DEFAULT "/out" @ingroup Config.*/
215
    AddStringOption( "OUTPUT_DIR", _outputDir, string( "/out" ) );
216
    /*! @brief OUTPUT_FILE \n DESCRIPTION: Name of output file \n DEFAULT "output" @ingroup Config.*/
217
    AddStringOption( "OUTPUT_FILE", _outputFile, string( "output" ) );
172✔
218
    /*! @brief LOG_DIR \n DESCRIPTION: Relative Directory of log files \n DEFAULT "/out" @ingroup Config.*/
172✔
219
    AddStringOption( "LOG_DIR", _logDir, string( "/out/logs" ) );
172✔
220
    /*! @brief LOG_DIR \n DESCRIPTION: Name of log files \n DEFAULT "/out" @ingroup Config.*/
172✔
221
    AddStringOption( "LOG_FILE", _logFileName, string( "use_date" ) );
172✔
222
    /*! @brief MESH_FILE \n DESCRIPTION: Name of mesh file \n DEFAULT "" \ingroup Config.*/
172✔
223
    AddStringOption( "MESH_FILE", _meshFile, string( "mesh.su2" ) );
224
    /*! @brief MESH_FILE \n DESCRIPTION: Name of mesh file \n DEFAULT "" \ingroup Config.*/
172✔
225
    AddStringOption( "CT_FILE", _ctFile, string( "/home/pia/kitrt/examples/meshes/phantom.png" ) );
172✔
226
    /*! @brief FORCE_CONNECTIVITY_RECOMPUTE \n DESCRIPTION:If true, mesh recomputes connectivity instead of loading from file \n DEFAULT false
172✔
227
     * \ingroup Config.*/
172✔
228
    AddBoolOption( "FORCE_CONNECTIVITY_RECOMPUTE", _forcedConnectivityWrite, false );
172✔
229
    /*! @brief RESTART_SOLUTION \n DESCRIPTION:If true, simulation loads a restart solution from file \n DEFAULT false
172✔
230
     * \ingroup Config.*/
231
    AddBoolOption( "LOAD_RESTART_SOLUTION", _loadrestartSolution, false );
232
    AddUnsignedLongOption( "SAVE_RESTART_SOLUTION_FREQUENCY", _saveRestartSolutionFrequency, false );
258✔
233

234
    // Quadrature relatated options
235
    /*! @brief QUAD_TYPE \n DESCRIPTION: Type of Quadrature rule \n Options: see @link QUAD_NAME \endlink \n DEFAULT: QUAD_MonteCarlo
236
     * \ingroup Config
258✔
237
     */
258✔
238
    AddEnumOption( "QUAD_TYPE", _quadName, Quadrature_Map, QUAD_MonteCarlo );
258✔
239
    /*!\brief QUAD_ORDER \n DESCRIPTION: Order of Quadrature rule \n DEFAULT 2 \ingroup Config.*/
258✔
240
    AddUnsignedShortOption( "QUAD_ORDER", _quadOrder, 1 );
258✔
241

258✔
242
    // Solver related options
172✔
243
    /*! @brief HPC_SOLVER \n DESCRIPTION: If true, the SN Solver uses hpc implementation. \n DEFAULT false \ingroup Config */
244
    AddBoolOption( "HPC_SOLVER", _HPC, false );
245

246
    /*! @brief MAX_MOMENT_ORDER \n: DESCRIPTON: Specifies the maximal order of Moments for PN and SN Solver */
172✔
247
    AddUnsignedShortOption( "MAX_MOMENT_SOLVER", _maxMomentDegree, 1 );
172✔
248
    /*! @brief CFL \n DESCRIPTION: CFL number \n DEFAULT 1.0 @ingroup Config.*/
172✔
249
    AddDoubleOption( "CFL_NUMBER", _CFL, 1.0 );
172✔
250
    /*! @brief TIME_FINAL \n DESCRIPTION: Final time for simulation \n DEFAULT 1.0 @ingroup Config.*/
172✔
251
    AddDoubleOption( "TIME_FINAL", _tEnd, 1.0 );
172✔
252
    /*! @brief Problem \n DESCRIPTION: Type of problem setting \n DEFAULT PROBLEM_ElectronRT @ingroup Config.*/
86✔
253
    AddEnumOption( "PROBLEM", _problemName, Problem_Map, PROBLEM_Linesource );
254
    /*! @brief Solver \n DESCRIPTION: Solver used for problem \n DEFAULT SN_SOLVER @ingroup Config. */
255
    AddEnumOption( "SOLVER", _solverName, Solver_Map, SN_SOLVER );
256
    /*! @brief RECONS_ORDER \n DESCRIPTION: Reconstruction order for solver (spatial flux) \n DEFAULT 1 \ingroup Config.*/
86✔
257
    AddUnsignedShortOption( "RECONS_ORDER", _reconsOrder, 1 );
86✔
258
    /*! @brief CleanFluxMatrices \n DESCRIPTION:  If true, very low entries (10^-10 or smaller) of the flux matrices will be set to zero,
86✔
259
     * to improve floating point accuracy \n DEFAULT false \ingroup Config */
86✔
260
    AddBoolOption( "CLEAN_FLUX_MATRICES", _cleanFluxMat, false );
86✔
261
    /*! @brief Realizability Step for MN solver \n DESCRIPTION: If true, MN solvers use a realizability reconstruction step in each time step. Also
86✔
262
     * applicable in regression sampling \n DEFAULT false \ingroup Config */
263
    AddBoolOption( "REALIZABILITY_RECONSTRUCTION", _realizabilityRecons, false );
264
    /*! @brief Runge Kutta Staes  \n DESCRIPTION: Sets number of Runge Kutta Stages for time integration \n DEFAULT 1 \ingroup Config */
265
    AddUnsignedShortOption( "TIME_INTEGRATION_ORDER", _rungeKuttaStages, 1 );
42✔
266

54✔
267
    // Problem Related Options
54✔
268
    /*! @brief MaterialDir \n DESCRIPTION: Relative Path to the data directory (used in the ICRU database class), starting from the directory of the
269
     * cfg file . \n DEFAULT "../data/material/" \ingroup Config */
×
270
    AddStringOption( "DATA_DIR", _dataDir, string( "../data/" ) );
271
    /*! @brief HydogenFile \n DESCRIPTION: If the continuous slowing down approximation is used, this referes to the cross section file for hydrogen.
272
     * . \n DEFAULT "h.dat" \ingroup Config */
273
    AddStringOption( "HYDROGEN_FILE", _hydrogenFile, string( "ENDL_H.txt" ) );
274
    /*! @brief OxygenFile \n DESCRIPTION: If the continuous slowing down approximation is used, this referes to the cross section file for oxygen.
86✔
275
     * . \n DEFAULT "o.dat" \ingroup Config */
276
    AddStringOption( "OXYGEN_FILE", _oxygenFile, string( "ENDL_O.txt" ) );
277
    /*! @brief StoppingPowerFile \n DESCRIPTION: Only temporary added. \ingroup Config */
6,032✔
278
    AddStringOption( "STOPPING_POWER_FILE", _stoppingPowerFile, string( "stopping_power.txt" ) );
5,946✔
279
    /*! @brief SN_ALL_GAUSS_PTS \n DESCRIPTION: If true, the SN Solver uses all Gauss Quadrature Points for 2d. \n DEFAULT false \ingroup Config */
280
    AddBoolOption( "SN_ALL_GAUSS_PTS", _allGaussPts, false );
86✔
281

282
    // Linesource Testcase Options
86✔
283
    /*! @brief SCATTER_COEFF \n DESCRIPTION: Sets the scattering coefficient for the Linesource test case. \n DEFAULT 1.0 \ingroup Config */
284
    AddDoubleOption( "SCATTER_COEFF", _sigmaS, 1.0 );
285

286
    // Checkerboard Testcase Options
287
    /*! @brief SCATTER_COEFF \n DESCRIPTION: Sets the Source magnitude for the checkerboard testcase. \n DEFAULT 1.0 \ingroup Config */
288
    AddDoubleOption( "SOURCE_MAGNITUDE", _magQ, 1.0 );
289

290
    // CSD related options
291
    /*! @brief MAX_ENERGY_CSD \n DESCRIPTION: Sets maximum energy for the CSD simulation.\n DEFAULT \ingroup Config */
86✔
292
    AddDoubleOption( "MAX_ENERGY_CSD", _maxEnergyCSD, 5.0 );
293

86✔
294
    // Lattice related options
295
    /*! @brief LATTICE_DSGN_ABSORPTION_BLUE \n DESCRIPTION: Sets absorption rate for the blue blocks (absorption blocks) in the lattice test case. \n
86✔
296
     * DEFAULT  10.0 \ingroup Config */
297
    AddDoubleOption( "LATTICE_DSGN_ABSORPTION_BLUE", _dsgnAbsBlue, 10.0 );
86✔
298
    /*! @brief LATTICE_DSGN_SCATTER_WHITE \n DESCRIPTION: Sets absorption rate for the white blocks (scattering blocks) in the lattice test case. \n
299
     * DEFAULT 1.0 \ingroup Config */
86✔
300
    AddDoubleOption( "LATTICE_DSGN_SCATTER_WHITE", _dsgnScatterWhite, 1.0 );
301
    /*! @brief LATTICE_DSGN_ABSORPTION_INDIVIDUAL \n DESCRIPTION: Sets absorption rate all 7x7 blocks in the lattice test case. Order from upper left
86✔
302
     * to lower right (row major). \n DEFAULT \ingroup Config */
303
    AddDoubleListOption( "LATTICE_DSGN_ABSORPTION_INDIVIDUAL", _nDsgnAbsIndividual, _dsgnAbsIndividual );
304
    /*! @brief LATTICE_DSGN_SCATTER_INDIVIDUAL \n DESCRIPTION: Sets scattering rate all 7x7 blocks in the lattice test case. Order from upper left to
86✔
305
     * lower right (row major). \n DEFAULT \ingroup Config */
306
    AddDoubleListOption( "LATTICE_DSGN_SCATTER_INDIVIDUAL", _nDsgnScatterIndividual, _dsgnScatterIndividual );
307

86✔
308
    // Hohlraum related options
86✔
309
    AddUnsignedShortOption( "N_SAMPLING_PTS_LINE_GREEN", _nProbingCellsLineGreenHohlraum, 4 );
310
    AddDoubleOption( "POS_CENTER_X", _posCenterXHohlraum, 0.0 );
311
    AddDoubleOption( "POS_CENTER_Y", _posCenterYHohlraum, 0.0 );
312
    AddDoubleOption( "POS_RED_RIGHT_TOP", _posRedRightTop, 0.4 );
313
    AddDoubleOption( "POS_RED_RIGHT_BOTTOM", _posRedRightBottom, -0.4 );
314
    AddDoubleOption( "POS_RED_LEFT_TOP", _posRedLeftTop, 0.4 );
86✔
315
    AddDoubleOption( "POS_RED_LEFT_BOTTOM", _posRedLeftBottom, -0.4 );
316
    AddDoubleOption( "POS_BORDER_RED_LEFT", _posRedLeftBorder, -0.65 );
86✔
317
    AddDoubleOption( "POS_BORDER_RED_RIGHT", _posRedRightBorder, 0.65 );
318
    // Entropy related options
319
    /*! @brief Entropy Functional \n DESCRIPTION: Entropy functional used for the MN_Solver \n DEFAULT QUADRTATIC @ingroup Config. */
320
    AddEnumOption( "ENTROPY_FUNCTIONAL", _entropyName, Entropy_Map, QUADRATIC );
86✔
321
    /*! @brief Optimizer Name \n DESCRIPTION:  Optimizer used to determine the minimal Entropy reconstruction \n DEFAULT NEWTON \ingroup Config */
322
    AddEnumOption( "ENTROPY_OPTIMIZER", _entropyOptimizerName, Optimizer_Map, NEWTON );
323
    /*! @brief Sets Flag for dynamic ansatz for normalized mn entropy closure \n DESCRIPTION:  True = enable ansatz, False = disable ansatz \n DEFAULT
86✔
324
     * false \ingroup Config */
325
    AddBoolOption( "ENTROPY_DYNAMIC_CLOSURE", _entropyDynamicClosure, true );
86✔
326

327
    // Newton optimizer related options
86✔
328
    /*! @brief Regularization Parameter \n DESCRIPTION:  Regularization Parameter for the regularized entropy closure. Must not be negative \n DEFAULT
329
     * 1e-2 \ingroup Config */
86✔
330
    AddDoubleOption( "REGULARIZER_GAMMA", _regularizerGamma, 1e-2 );
331
    /*! @brief Newton Optimizer Epsilon \n DESCRIPTION:  Convergencce Epsilon for Newton Optimizer \n DEFAULT 1e-3 \ingroup Config */
86✔
332
    AddDoubleOption( "NEWTON_EPSILON", _optimizerEpsilon, 0.001 );
333
    /*! @brief Max Iter Newton Optmizers \n DESCRIPTION: Max number of newton iterations \n DEFAULT 10 \ingroup Config */
86✔
334
    AddUnsignedLongOption( "NEWTON_ITER", _newtonIter, 1000 );
335
    /*! @brief Step Size Newton Optmizers \n DESCRIPTION: Step size for Newton optimizer \n DEFAULT 10 \ingroup Config */
336
    AddDoubleOption( "NEWTON_STEP_SIZE", _newtonStepSize, 1 );
86✔
337
    /*! @brief Max Iter for line search in Newton Optmizers \n DESCRIPTION: Max number of line search iter for newton optimizer \n DEFAULT 10
338
     * \ingroup Config */
339
    AddUnsignedLongOption( "NEWTON_LINE_SEARCH_ITER", _newtonLineSearchIter, 1000 );
86✔
340
    /*! @brief Newton Fast mode \n DESCRIPTION:  If true, we skip the Newton optimizer for Quadratic entropy and set alpha = u \n DEFAULT false
341
     * \ingroup Config */
86✔
342
    AddBoolOption( "NEWTON_FAST_MODE", _newtonFastMode, false );
343
    // Neural Entropy Closure options
344
    /*! @brief Neural Model \n DESCRIPTION:  Specifies the neural netwok architecture \n DEFAULT 11 (values: 11=input convex, 12 non-convex)
345
     * \ingroup Config */
346
    AddUnsignedShortOption( "NEURAL_MODEL_MK", _neuralModel, 11 );
86✔
347
    /*! @brief Neural Model Gamma \n DESCRIPTION:  Specifies regularization parameter for neural networks \n DEFAULT 0 (values: 0,1,2,3)
348
    \ingroup Config */
349
    AddUnsignedShortOption( "NEURAL_MODEL_GAMMA", _neuralGamma, 0 );
86✔
350
    /*! @brief NEURAL_MODEL_ENFORCE_ROTATION_SYMMETRY \n DESCRIPTION:  Flag to enforce rotational symmetry \n DEFAULT false \ingroup Config */
351
    AddBoolOption( "NEURAL_MODEL_ENFORCE_ROTATION_SYMMETRY", _enforceNeuralRotationalSymmetry, false );
352

86✔
353
    // Mesh related options
354
    // Boundary Markers
86✔
355
    /*!\brief BC_DIRICHLET\n DESCRIPTION: Dirichlet wall boundary marker(s) \ingroup Config*/
356
    AddStringListOption( "BC_DIRICHLET", _nMarkerDirichlet, _MarkerDirichlet );
86✔
357
    AddStringListOption( "BC_NEUMANN", _nMarkerNeumann, _MarkerNeumann );
358
    AddUnsignedShortOption( "SPATIAL_DIM", _dim, 3 );
359

360
    /*! @brief Scattering kernel \n DESCRIPTION: Describes used scattering kernel \n DEFAULT KERNEL_Isotropic \ingroup Config */
86✔
361
    AddEnumOption( "KERNEL", _kernelName, Kernel_Map, KERNEL_Isotropic );
362

363
    /*! @brief Spherical Basis \n DESCRIPTION: Describes the chosen set of basis functions for on the unit sphere (e.g. for Moment methods) \n DEFAULT
364
     * SPHERICAL_HARMONICS \ingroup Config */
86✔
365
    AddEnumOption( "SPHERICAL_BASIS", _sphericalBasisName, SphericalBasis_Map, SPHERICAL_HARMONICS );
366

367
    // Output related options
368
    /*! @brief Volume output \n DESCRIPTION: Describes output groups to write to vtk \ingroup Config */
86✔
369
    AddEnumListOption( "VOLUME_OUTPUT", _nVolumeOutput, _volumeOutput, VolOutput_Map );
370
    /*! @brief Volume output Frequency \n DESCRIPTION: Describes output write frequency \n DEFAULT 0 ,i.e. only last value \ingroup Config */
371
    AddUnsignedShortOption( "VOLUME_OUTPUT_FREQUENCY", _volumeOutputFrequency, 0 );
372
    /*! @brief Screen output \n DESCRIPTION: Describes screen output fields \ingroup Config */
373
    AddEnumListOption( "SCREEN_OUTPUT", _nScreenOutput, _screenOutput, ScalarOutput_Map );
86✔
374
    /*! @brief Screen output Frequency \n DESCRIPTION: Describes screen output write frequency \n DEFAULT 1 \ingroup Config */
375
    AddUnsignedShortOption( "SCREEN_OUTPUT_FREQUENCY", _screenOutputFrequency, 1 );
376
    /*! @brief History output \n DESCRIPTION: Describes history output fields \ingroup Config */
86✔
377
    AddEnumListOption( "HISTORY_OUTPUT", _nHistoryOutput, _historyOutput, ScalarOutput_Map );
378
    /*! @brief History output Frequency \n DESCRIPTION: Describes history output write frequency \n DEFAULT 1 \ingroup Config */
379
    AddUnsignedShortOption( "HISTORY_OUTPUT_FREQUENCY", _historyOutputFrequency, 1 );
86✔
380

381
    // Data generator related options
382
    /*! @brief Choice of sampling method \n DESCRIPTION:  Choose between creating a regression and a classification dataset. \ingroup Config */
86✔
383
    AddEnumOption( "SAMPLER_NAME", _sampler, SamplerName_MAP, REGRESSION_SAMPLER );
384
    /*! @brief Size of training data set \n DESCRIPTION: Size of training data set  \n DEFAULT 1 \ingroup Config */
385
    AddUnsignedLongOption( "TRAINING_SET_SIZE", _tainingSetSize, 1 );
86✔
386
    /*! @brief Determines, if TRAINING_SET_SIZE is counted by dimension \n DESCRIPTION: Determines, if TRAINING_SET_SIZE is counted by dimension   \n
86✔
387
     * DEFAULT true \ingroup Config */
86✔
388
    AddBoolOption( "SIZE_BY_DIMENSION", _sizeByDimension, true );
86✔
389
    /*! @brief Size of training data set \n DESCRIPTION: Size of training data set  \n DEFAULT 10 \ingroup Config */
86✔
390
    AddUnsignedLongOption( "MAX_VALUE_FIRST_MOMENT", _maxValFirstMoment, 10 );
86✔
391
    /*! @brief Data generator mode \n DESCRIPTION: Check, if data generator mode is active. If yes, no solver is called, but instead the data
86✔
392
     *         generator is executed \n DEFAULT false \ingroup Config */
86✔
393
    AddBoolOption( "DATA_GENERATOR_MODE", _dataGeneratorMode, false );
86✔
394
    /*! @brief Distance to 0 of the sampled moments to the boundary of the realizable set  \n DESCRIPTION: Distance to the boundary of the
395
     * realizable set  \n DEFAULT 0.1 \ingroup Config */
396
    AddDoubleOption( "REALIZABLE_SET_EPSILON_U0", _RealizableSetEpsilonU0, 0.1 );
86✔
397
    /*! @brief norm(u_1)/u_0 is enforced to be smaller than _RealizableSetEpsilonU1 \n DESCRIPTION: Distance to the boundary of the realizable set  \n
398
     * DEFAULT 0.1 \ingroup Config */
86✔
399
    AddDoubleOption( "REALIZABLE_SET_EPSILON_U1", _RealizableSetEpsilonU1, 0.9 );
400
    /*! @brief Flag for sampling of normalized moments, i.e. u_0 =1  \n DESCRIPTION: Flag for sampling of normalized moments, i.e. u_0 =1  \n
401
     * DEFAULT False \ingroup Config */
86✔
402
    AddBoolOption( "NORMALIZED_SAMPLING", _normalizedSampling, false );
403
    /*! @brief Flag for sampling the space of Legendre multipliers instead of the moments  \n DESCRIPTION: Sample alpha instead of u \n DEFAULT False
404
     * \ingroup Config */
405
    AddBoolOption( "ALPHA_SAMPLING", _alphaSampling, false );
406
    /*! @brief Switch for sampling distribution  \n DESCRIPTION: Uniform (true) or trunctaded normal (false) \n DEFAULT true
86✔
407
     * \ingroup Config */
408
    AddBoolOption( "UNIFORM_SAMPLING", _sampleUniform, true );
86✔
409
    /*! @brief Boundary for the sampling region of the Lagrange multipliers  \n DESCRIPTION: Norm sampling boundary for alpha \n DEFAULT 20.0
410
     * \ingroup Config */
86✔
411
    AddDoubleOption( "ALPHA_SAMPLING_BOUND", _alphaBound, 20.0 );
412
    /*! @brief Rejection sampling threshold based on the minimal Eigenvalue of the Hessian of the entropy functions  \n DESCRIPTION: Rejection
86✔
413
     * sampling threshold \n DEFAULT 1e-8 \ingroup Config */
414
    AddDoubleOption( "MIN_EIGENVALUE_THRESHOLD", _minEVAlphaSampling, 1e-8 );
415
    /*! @brief Boundary for the velocity integral  \n DESCRIPTION: Upper boundary for the velocity integral \n DEFAULT 5.0  * \ingroup Config */
86✔
416
    AddDoubleOption( "MAX_VELOCITY", _maxSamplingVelocity, 5.0 );
417
    ///*! @brief Boundary for the velocity integral  \n DESCRIPTION: Lower boundary for the velocity integral \n DEFAULT 5.0  * \ingroup Config */
418
    // AddDoubleOption( "MIN_VELOCITY", _minSamplingVelocity, -5.0 );
86✔
419
    /*! @brief Boundary for the sampling temperature  \n DESCRIPTION: Upper boundary for the sampling temperature \n DEFAULT 1.0  * \ingroup Config */
420
    AddDoubleOption( "MAX_TEMPERATURE", _maxSamplingTemperature, 1 );
421
    /*! @brief Boundary for the sampling temperature  \n DESCRIPTION: Lower boundary for the sampling temperature \n DEFAULT 0.1  * \ingroup Config */
422
    AddDoubleOption( "MIN_TEMPERATURE", _minSamplingTemperature, 0.1 );
86✔
423
    /*! @brief Number of temperature samples  \n DESCRIPTION: Number of temperature samples for the sampler \n DEFAULT 10  * \ingroup Config */
424
    AddUnsignedShortOption( "N_TEMPERATURES", _nTemperatures, 10 );
425
}
86✔
426

427
void Config::SetConfigParsing( string case_filename ) {
86✔
428
    string text_line, option_name;
429
    ifstream case_file;
430
    vector<string> option_value;
431

432
    /*--- Read the configuration file ---*/
86✔
433

86✔
434
    case_file.open( case_filename, ios::in );
86✔
435

436
    if( case_file.fail() ) {
437
        ErrorMessages::Error( "The configuration file (.cfg) is missing!!", CURRENT_FUNCTION );
86✔
438
    }
439

440
    string errorString;
441

86✔
442
    int err_count     = 0;     // How many errors have we found in the config file
443
    int max_err_count = 30;    // Maximum number of errors to print before stopping
444

445
    map<string, bool> included_options;
86✔
446

447
    /*--- Parse the configuration file and set the options ---*/
86✔
448

449
    while( getline( case_file, text_line ) ) {
86✔
450

451
        if( err_count >= max_err_count ) {
86✔
452
            errorString.append( "too many errors. Stopping parse" );
453

86✔
454
            cout << errorString << endl;
455
            throw( 1 );
86✔
456
        }
457

458
        if( TokenizeString( text_line, option_name, option_value ) ) {
459

86✔
460
            /*--- See if it's a python option ---*/
461

86✔
462
            if( _optionMap.find( option_name ) == _optionMap.end() ) {
463
                string newString;
464
                newString.append( option_name );
86✔
465
                newString.append( ": invalid option name" );
466
                newString.append( ". Check current KiT-RT options in config_template.cfg." );
86✔
467
                newString.append( "\n" );
468
                errorString.append( newString );
469
                err_count++;
86✔
470
                continue;
471
            }
472

86✔
473
            /*--- Option exists, check if the option has already been in the config file ---*/
474

475
            if( included_options.find( option_name ) != included_options.end() ) {
86✔
476
                string newString;
477
                newString.append( option_name );
478
                newString.append( ": option appears twice" );
86✔
479
                newString.append( "\n" );
480
                errorString.append( newString );
481
                err_count++;
86✔
482
                continue;
483
            }
484

86✔
485
            /*--- New found option. Add it to the map, and delete from all options ---*/
486

487
            included_options.insert( pair<string, bool>( option_name, true ) );
86✔
488
            _allOptions.erase( option_name );
489

490
            /*--- Set the value and check error ---*/
86✔
491

492
            string out = _optionMap[option_name]->SetValue( option_value );
86✔
493
            if( out.compare( "" ) != 0 ) {
494
                errorString.append( out );
495
                errorString.append( "\n" );
496
                err_count++;
86✔
497
            }
498
        }
86✔
499
    }
500

86✔
501
    /*--- See if there were any errors parsing the config file ---*/
86✔
502

503
    if( errorString.size() != 0 ) {
86✔
504
        ErrorMessages::ParsingError( errorString, CURRENT_FUNCTION );
172✔
505
    }
172✔
506

172✔
507
    case_file.close();
508
}
509

510
void Config::SetPointersNull( void ) {
86✔
511
    // All pointer valued options should be set to NULL here
512
}
86✔
513

×
514
void Config::SetPostprocessing() {
515

516
    // append '/' to all dirs to allow for simple path addition
172✔
517
    if( _logDir[_logDir.size() - 1] != '/' ) _logDir.append( "/" );
518
    if( _outputDir[_outputDir.size() - 1] != '/' ) _outputDir.append( "/" );
86✔
519
    if( _inputDir[_inputDir.size() - 1] != '/' ) _inputDir.append( "/" );
86✔
520

521
    // setup relative paths
172✔
522
    _logDir            = std::filesystem::path( _inputDir ).append( _logDir ).lexically_normal();
523
    _outputDir         = std::filesystem::path( _inputDir ).append( _outputDir ).lexically_normal();
524
    _meshFile          = std::filesystem::path( _inputDir ).append( _meshFile ).lexically_normal();
525
    _outputFile        = std::filesystem::path( _outputDir ).append( _outputFile ).lexically_normal();
2,904✔
526
    _ctFile            = std::filesystem::path( _inputDir ).append( _ctFile ).lexically_normal();
527
    _hydrogenFile      = std::filesystem::path( _inputDir ).append( _hydrogenFile ).lexically_normal();
2,818✔
528
    _oxygenFile        = std::filesystem::path( _inputDir ).append( _oxygenFile ).lexically_normal();
×
529
    _stoppingPowerFile = std::filesystem::path( _inputDir ).append( _stoppingPowerFile ).lexically_normal();
530
    _dataDir           = std::filesystem::path( _inputDir ).append( _dataDir ).lexically_normal();
×
531

×
532
    // create directories if they dont exist
533
    if( !std::filesystem::exists( _outputDir ) ) std::filesystem::create_directory( _outputDir );
534

2,818✔
535
    // init logger
536
    InitLogger();
537

538
    // Regroup Boundary Conditions to  std::vector<std::pair<std::string, BOUNDARY_TYPE>> _boundaries;
1,020✔
539
    for( int i = 0; i < _nMarkerDirichlet; i++ ) {
×
540
        _boundaries.push_back( std::pair<std::string, BOUNDARY_TYPE>( _MarkerDirichlet[i], DIRICHLET ) );
×
541
    }
×
542
    for( int i = 0; i < _nMarkerNeumann; i++ ) {
×
543
        _boundaries.push_back( std::pair<std::string, BOUNDARY_TYPE>( _MarkerNeumann[i], NEUMANN ) );
×
544
    }
×
545

×
546
    // Set option ISCSD
×
547
    switch( _solverName ) {
548
        case CSD_SN_SOLVER:    // Fallthrough
549
        case CSD_PN_SOLVER:    // Fallthrough
550
        case CSD_MN_SOLVER:    // Fallthrough
551
            _csd = true;
1,020✔
552
            break;
×
553
        default: _csd = false;
×
554
    }
×
555

×
556
    // Set option MomentSolver
×
557
    switch( _solverName ) {
×
558
        case MN_SOLVER:
×
559
        case MN_SOLVER_NORMALIZED:
560
        case CSD_MN_SOLVER:
561
        case PN_SOLVER:
562
        case CSD_PN_SOLVER: _isMomentSolver = true; break;
563
        default: _isMomentSolver = false;
1,020✔
564
    }
1,020✔
565

566
    // Quadrature Postprocessing
567
    {
568
        QuadratureBase* quad                      = QuadratureBase::Create( this );
2,040✔
569
        std::vector<unsigned short> supportedDims = quad->GetSupportedDims();
1,020✔
570

×
571
        if( std::find( supportedDims.begin(), supportedDims.end(), _dim ) == supportedDims.end() ) {
×
572
            // Dimension not supported
×
573
            std::string msg = "Chosen spatial dimension not supported for this Quadrature.\nChosen spatial dimension " + std::to_string( _dim ) + ".";
574
            ErrorMessages::Error( msg, CURRENT_FUNCTION );
575
        }
576
        delete quad;
577
    }
578

579
    // Optimizer Postprocessing
86✔
580
    {
×
581
        if( ( _entropyOptimizerName == REDUCED_NEWTON || _entropyOptimizerName == REDUCED_PART_REGULARIZED_NEWTON ) &&
582
            _entropyName != MAXWELL_BOLTZMANN ) {
583
            std::string msg = "Reduction of the optimization problen only possible with Maxwell Boltzmann Entropy" + std::to_string( _dim ) + ".";
86✔
584
            ErrorMessages::Error( msg, CURRENT_FUNCTION );
86✔
585
        }
586
    }
86✔
587

588
    // --- Solver setup ---
86✔
589
    {
590
        if( GetSolverName() == PN_SOLVER && GetSphericalBasisName() != SPHERICAL_HARMONICS ) {
86✔
591
            ErrorMessages::Error(
592
                "PN Solver only works with spherical harmonics basis.\nThis should be the default setting for option SPHERICAL_BASIS.",
593
                CURRENT_FUNCTION );
86✔
594
        }
86✔
595

86✔
596
        if( GetSolverName() == CSD_MN_SOLVER && GetSphericalBasisName() != SPHERICAL_HARMONICS ) {
597
            ErrorMessages::Error( "CSD_MN_SOLVER only works with Spherical Harmonics currently.", CURRENT_FUNCTION );
598
        }
86✔
599

86✔
600
        if( GetSpatialOrder() > 2 ) {
86✔
601
            ErrorMessages::Error( "Solvers only work with 1st and 2nd order spatial fluxes.", CURRENT_FUNCTION );
86✔
602
        }
86✔
603

86✔
604
        if( GetOptimizerName() == ML && GetSolverName() != MN_SOLVER_NORMALIZED ) {
86✔
605
            ErrorMessages::Error( "ML Optimizer only works with normalized MN Solver.", CURRENT_FUNCTION );
86✔
606
        }
86✔
607

608
        if( GetSolverName() == PN_SOLVER || GetSolverName() == CSD_PN_SOLVER ) {
609
            _dim        = 3;
86✔
610
            auto log    = spdlog::get( "event" );
611
            auto logCSV = spdlog::get( "tabular" );
612
            log->info(
86✔
613
                "| Spherical harmonics based solver currently use 3D Spherical functions and a projection. Thus spatial dimension is set to 3." );
614
            logCSV->info(
615
                "| Spherical harmonics based solver currently use 3D Spherical functions and a projection. Thus spatial dimension is set to 3." );
120✔
616
        }
34✔
617
    }
618

112✔
619
    // --- Output Postprocessing ---
26✔
620

621
    // Volume Output Postprocessing
622
    {
623
        // Check for doublicates in VOLUME OUTPUT
86✔
624
        std::map<VOLUME_OUTPUT, int> dublicate_map;
10✔
625

626
        for( unsigned short idx_volOutput = 0; idx_volOutput < _nVolumeOutput; idx_volOutput++ ) {
627
            std::map<VOLUME_OUTPUT, int>::iterator it = dublicate_map.find( _volumeOutput[idx_volOutput] );
10✔
628
            if( it == dublicate_map.end() ) {
10✔
629
                dublicate_map.insert( std::pair<VOLUME_OUTPUT, int>( _volumeOutput[idx_volOutput], 0 ) );
76✔
630
            }
631
            else {
632
                it->second++;
633
            }
86✔
634
        }
16✔
635
        for( auto& e : dublicate_map ) {
636
            if( e.second > 0 ) {
637
                ErrorMessages::Error( "Each output group for option VOLUME_OUTPUT can only be set once.\nPlease check your .cfg file.",
638
                                      CURRENT_FUNCTION );
16✔
639
            }
70✔
640
        }
641

642
        // Check, if the choice of volume output is compatible to the solver
643
        std::vector<VOLUME_OUTPUT> supportedGroups;
644

86✔
645
        for( unsigned short idx_volOutput = 0; idx_volOutput < _nVolumeOutput; idx_volOutput++ ) {
172✔
646
            switch( _solverName ) {
647
                case SN_SOLVER:
86✔
648
                    if( _problemName == PROBLEM_Linesource )
649
                        supportedGroups = { MINIMAL, ANALYTIC };
×
650
                    else {
×
651
                        supportedGroups = { MINIMAL };
652
                        if( _HPC ) supportedGroups = { MINIMAL, MOMENTS };
86✔
653
                    }
654

655
                    if( supportedGroups.end() == std::find( supportedGroups.begin(), supportedGroups.end(), _volumeOutput[idx_volOutput] ) ) {
656
                        ErrorMessages::Error(
657
                            "SN_SOLVER only supports volume output MINIMAL and ANALYTIC (and experimentally MOMENTS).\nPlease check your .cfg file.",
86✔
658
                            CURRENT_FUNCTION );
×
659
                    }
×
660
                    if( _volumeOutput[idx_volOutput] == ANALYTIC && _problemName != PROBLEM_Linesource ) {
×
661
                        ErrorMessages::Error( "Analytical solution (VOLUME_OUTPUT=ANALYTIC) is only available for the PROBLEM=LINESOURCE.\nPlease "
662
                                              "check your .cfg file.",
663
                                              CURRENT_FUNCTION );
664
                    }
665
                    break;
666
                case MN_SOLVER:    // Fallthrough
86✔
667
                case MN_SOLVER_NORMALIZED:
×
668
                    if( _problemName == PROBLEM_SymmetricHohlraum )
669
                        supportedGroups = { MINIMAL, MOMENTS, DUAL_MOMENTS };
670
                    else if( _problemName == PROBLEM_Linesource )
671
                        supportedGroups = { MINIMAL, ANALYTIC, MOMENTS, DUAL_MOMENTS };
672
                    else
86✔
673
                        supportedGroups = { MINIMAL, MOMENTS, DUAL_MOMENTS };
×
674
                    if( supportedGroups.end() == std::find( supportedGroups.begin(), supportedGroups.end(), _volumeOutput[idx_volOutput] ) ) {
675
                        std::string supportedGroupStr = "";
676
                        for( unsigned i = 0; i < supportedGroups.size(); i++ ) {
86✔
677
                            supportedGroupStr += findKey( VolOutput_Map, supportedGroups[i] ) + ", ";
×
678
                        }
679
                        ErrorMessages::Error( "MN_SOLVER supports volume outputs" + supportedGroupStr + ".\nPlease check your .cfg file.",
680
                                              CURRENT_FUNCTION );
86✔
681
                    }
×
682
                    break;
683
                case PN_SOLVER:
684
                    supportedGroups = { MINIMAL, MOMENTS, ANALYTIC };
86✔
685
                    if( supportedGroups.end() == std::find( supportedGroups.begin(), supportedGroups.end(), _volumeOutput[idx_volOutput] ) ) {
8✔
686

24✔
687
                        ErrorMessages::Error( "PN_SOLVER only supports volume output ANALYTIC, MINIMAL and MOMENTS.\nPlease check your .cfg file.",
24✔
688
                                              CURRENT_FUNCTION );
8✔
689
                    }
690
                    if( _volumeOutput[idx_volOutput] == ANALYTIC && _problemName != PROBLEM_Linesource ) {
8✔
691
                        ErrorMessages::Error( "Analytical solution (VOLUME_OUTPUT=ANALYTIC) is only available for the PROBLEM=LINESOURCE.\nPlease "
692
                                              "check your .cfg file.",
693
                                              CURRENT_FUNCTION );
694
                    }
695
                    break;
696
                case CSD_SN_SOLVER:
697
                    supportedGroups = { MINIMAL, MEDICAL };
698
                    if( supportedGroups.end() == std::find( supportedGroups.begin(), supportedGroups.end(), _volumeOutput[idx_volOutput] ) ) {
699

700
                        ErrorMessages::Error( "CSD_SN_SOLVER types only supports volume output MEDICAL and MINIMAL.\nPlease check your .cfg file.",
172✔
701
                                              CURRENT_FUNCTION );
702
                    }
112✔
703
                    break;
26✔
704
                case CSD_PN_SOLVER:
26✔
705
                    supportedGroups = { MINIMAL, MEDICAL, MOMENTS };
26✔
706
                    if( supportedGroups.end() == std::find( supportedGroups.begin(), supportedGroups.end(), _volumeOutput[idx_volOutput] ) ) {
707

708
                        ErrorMessages::Error(
×
709
                            "CSD_PN_SOLVER types only supports volume output MEDICAL, MOMENTS and MINIMAL.\nPlease check your .cfg file.",
710
                            CURRENT_FUNCTION );
711
                    }
112✔
712
                    break;
26✔
713
                case CSD_MN_SOLVER:
×
714
                    supportedGroups = { MINIMAL, MEDICAL, MOMENTS, DUAL_MOMENTS };
715
                    if( supportedGroups.end() == std::find( supportedGroups.begin(), supportedGroups.end(), _volumeOutput[idx_volOutput] ) ) {
716

717
                        ErrorMessages::Error( "CSD_MN_SOLVER types only supports volume output MEDICAL, MOMENTS, DUAL_MOMENTS and MINIMAL.\nPlease "
718
                                              "check your .cfg file.",
719
                                              CURRENT_FUNCTION );
172✔
720
                    }
721
                    break;
112✔
722
                default:
26✔
723
                    ErrorMessages::Error( "Solver output check not implemented for this Solver.\nThis is the fault of the coder.", CURRENT_FUNCTION );
6✔
724
            }
6✔
725
        }
4✔
726

727
        // Set default volume output
2✔
728
        if( _nVolumeOutput == 0 ) {    // If no specific output is chosen,  use "MINIMAL"
2✔
729
            _nVolumeOutput = 1;
730
            _volumeOutput.push_back( MINIMAL );
731
        }
6✔
732
    }
×
733

734
    // Screen Output Postprocessing
735
    {
736
        // Check for doublicates in SCALAR OUTPUT
6✔
737
        std::map<SCALAR_OUTPUT, int> dublicate_map;
×
738

739
        for( unsigned short idx_screenOutput = 0; idx_screenOutput < _nScreenOutput; idx_screenOutput++ ) {
740
            std::map<SCALAR_OUTPUT, int>::iterator it = dublicate_map.find( _screenOutput[idx_screenOutput] );
741
            if( it == dublicate_map.end() ) {
6✔
742
                dublicate_map.insert( std::pair<SCALAR_OUTPUT, int>( _screenOutput[idx_screenOutput], 0 ) );
8✔
743
            }
744
            else {
8✔
745
                it->second++;
×
746
            }
8✔
747
        }
6✔
748
        for( auto& e : dublicate_map ) {
749
            if( e.second > 0 ) {
2✔
750
                ErrorMessages::Error( "Each output field for option SCREEN_OUTPUT can only be set once.\nPlease check your .cfg file.",
8✔
751
                                      CURRENT_FUNCTION );
×
752
            }
×
753
        }
×
754
        // Check if the choice of screen output is compatible to the problem
755
        for( unsigned short idx_screenOutput = 0; idx_screenOutput < _nScreenOutput; idx_screenOutput++ ) {
×
756
            std::vector<SCALAR_OUTPUT> legalOutputs;
757
            std::vector<SCALAR_OUTPUT>::iterator it;
758
            switch( _problemName ) {
8✔
759
                case PROBLEM_HalfLattice:
4✔
760
                case PROBLEM_Lattice:
4✔
761
                    legalOutputs = { ITER,
4✔
762
                                     WALL_TIME,
NEW
763
                                     SIM_TIME,
×
764
                                     MASS,
765
                                     RMS_FLUX,
766
                                     VTK_OUTPUT,
4✔
UNCOV
767
                                     CSV_OUTPUT,
×
768
                                     CUR_OUTFLOW,
769
                                     TOTAL_OUTFLOW,
770
                                     CUR_OUTFLOW_P1,
771
                                     TOTAL_OUTFLOW_P1,
4✔
UNCOV
772
                                     CUR_OUTFLOW_P2,
×
773
                                     TOTAL_OUTFLOW_P2,
×
774
                                     MAX_OUTFLOW,
×
775
                                     CUR_PARTICLE_ABSORPTION,
UNCOV
776
                                     TOTAL_PARTICLE_ABSORPTION,
×
777
                                     MAX_PARTICLE_ABSORPTION };
778
                    it           = std::find( legalOutputs.begin(), legalOutputs.end(), _screenOutput[idx_screenOutput] );
UNCOV
779
                    if( it == legalOutputs.end() ) {
×
780
                        std::string foundKey = findKey( ScalarOutput_Map, _screenOutput[idx_screenOutput] );
8✔
781
                        ErrorMessages::Error(
8✔
782
                            "Illegal output field <" + foundKey +
8✔
783
                                "> for option SCREEN_OUTPUT for this test case.\n"
NEW
784
                                "Supported fields are: ITER, SIM_TIME, WALL_TIME, MASS, RMS_FLUX, VTK_OUTPUT, CSV_OUTPUT, FINAL_TIME_OUTFLOW, TOTAL_OUTFLOW, MAX_OUTFLOW, "
×
785
                                "FINAL_TIME_PARTICLE_ABSORPTION, TOTAL_PARTICLE_ABSORPTION, MAX_PARTICLE_ABSORPTION\n"
786
                                "Please check your .cfg file.",
787
                            CURRENT_FUNCTION );
788
                    }
8✔
UNCOV
789
                    break;
×
790
                case PROBLEM_QuarterHohlraum:
×
791
                case PROBLEM_SymmetricHohlraum:
×
792
                    legalOutputs = {
UNCOV
793
                        ITER,
×
794
                        SIM_TIME,
795
                        WALL_TIME,
796
                        MASS,
UNCOV
797
                        RMS_FLUX,
×
UNCOV
798
                        VTK_OUTPUT,
×
799
                        CSV_OUTPUT,
×
800
                        CUR_OUTFLOW,
801
                        TOTAL_OUTFLOW,
802
                        MAX_OUTFLOW,
803
                        TOTAL_PARTICLE_ABSORPTION_CENTER,
804
                        TOTAL_PARTICLE_ABSORPTION_VERTICAL,
86✔
805
                        TOTAL_PARTICLE_ABSORPTION_HORIZONTAL,
64✔
806
                        TOTAL_PARTICLE_ABSORPTION,
64✔
807
                        PROBE_MOMENT_TIME_TRACE,
808
                        VAR_ABSORPTION_GREEN,
809
                    };
810

811
                    it = std::find( legalOutputs.begin(), legalOutputs.end(), _screenOutput[idx_screenOutput] );
812

813
                    if( it == legalOutputs.end() ) {
172✔
814
                        std::string foundKey = findKey( ScalarOutput_Map, _screenOutput[idx_screenOutput] );
815
                        ErrorMessages::Error(
116✔
816
                            "Illegal output field <" + foundKey +
30✔
817
                                "> for option SCREEN_OUTPUT for this test case.\n"
30✔
818
                                "Supported fields are: ITER, SIM_TIME, WALL_TIME, MASS, RMS_FLUX, VTK_OUTPUT, CSV_OUTPUT, TOTAL_PARTICLE_ABSORPTION_CENTER, \n"
30✔
819
                                "TOTAL_PARTICLE_ABSORPTION_VERTICAL, TOTAL_PARTICLE_ABSORPTION_HORIZONTAL, PROBE_MOMENT_TIME_TRACE, CUR_OUTFLOW, \n "
820
                                "TOTAL_OUTFLOW, MAX_OUTFLOW, VAR_ABSORPTION_GREEN \n"
UNCOV
821
                                "Please check your .cfg file.",
×
822
                            CURRENT_FUNCTION );
823
                    }
824
                    break;
116✔
825

30✔
UNCOV
826
                default:
×
827
                    legalOutputs = { ITER, SIM_TIME, WALL_TIME, MASS, RMS_FLUX, VTK_OUTPUT, CSV_OUTPUT, CUR_OUTFLOW, TOTAL_OUTFLOW, MAX_OUTFLOW };
828
                    it           = std::find( legalOutputs.begin(), legalOutputs.end(), _screenOutput[idx_screenOutput] );
829

830
                    if( it == legalOutputs.end() ) {
831
                        std::string foundKey = findKey( ScalarOutput_Map, _screenOutput[idx_screenOutput] );
116✔
832
                        ErrorMessages::Error(
60✔
833
                            "Illegal output field <" + foundKey +
30✔
834
                                "> for option SCREEN_OUTPUT for this test case.\n"
30✔
NEW
835
                                "Supported fields are: ITER, SIM_TIME, WALL_TIME, MASS RMS_FLUX, VTK_OUTPUT, CSV_OUTPUT, CUR_OUTFLOW, TOTAL_OUTFLOW, MAX_OUTFLOW \n"
×
836
                                "Please check your .cfg file.",
837
                            CURRENT_FUNCTION );
×
838
                    }
839
                    break;
840
            }
841
        }
842
        // Set ITER always to index 0 . Assume only one instance of iter is chosen
843
        if( _nScreenOutput > 0 ) {
844
            std::vector<SCALAR_OUTPUT>::iterator it;
845
            it = find( _screenOutput.begin(), _screenOutput.end(), ITER );
846
            _screenOutput.erase( it );
847
            _screenOutput.insert( _screenOutput.begin(), ITER );
848
        }
849
        // Set default screen output
850
        if( _nScreenOutput == 0 ) {
851
            _nScreenOutput = 4;
852
            _screenOutput.push_back( ITER );
UNCOV
853
            _screenOutput.push_back( RMS_FLUX );
×
854
            _screenOutput.push_back( MASS );
×
855
            _screenOutput.push_back( VTK_OUTPUT );
×
856
        }
×
857

×
858
        // Postprocessing for probing moments in symmetric Hohlraum. Make it four outputs
×
859
        if( _problemName == PROBLEM_SymmetricHohlraum ) {
860
            std::vector<SCALAR_OUTPUT>::iterator it;
861

862
            it = find( _screenOutput.begin(), _screenOutput.end(), PROBE_MOMENT_TIME_TRACE );
863

864
            if( it != _screenOutput.end() ) {
UNCOV
865
                _screenOutput.erase( it );
×
866
                _nScreenOutput += 3;    // extend the screen output by the number of probing points
×
867
                for( unsigned i = 0; i < 4; i++ ) _screenOutput.push_back( PROBE_MOMENT_TIME_TRACE );
UNCOV
868
            }
×
869
        }
870
        if( _problemName == PROBLEM_QuarterHohlraum ) {
871
            std::vector<SCALAR_OUTPUT>::iterator it;
872

873
            it = find( _screenOutput.begin(), _screenOutput.end(), PROBE_MOMENT_TIME_TRACE );
874

875
            if( it != _screenOutput.end() ) {
876
                _screenOutput.erase( it );
877
                _nScreenOutput += 1;    // extend the screen output by the number of probing points
878
                for( unsigned i = 0; i < 2; i++ ) _screenOutput.push_back( PROBE_MOMENT_TIME_TRACE );
879
            }
880
        }
881
    }
882

883
    // History Output Postprocessing
884
    {
885
        // Check for doublicates in HISTORY OUTPUT
886
        std::map<SCALAR_OUTPUT, int> dublicate_map;
887

×
888
        for( unsigned idx_historyOutput = 0; idx_historyOutput < _nHistoryOutput; idx_historyOutput++ ) {
889
            std::map<SCALAR_OUTPUT, int>::iterator it = dublicate_map.find( _historyOutput[idx_historyOutput] );
×
890
            if( it == dublicate_map.end() ) {
×
891
                dublicate_map.insert( std::pair<SCALAR_OUTPUT, int>( _historyOutput[idx_historyOutput], 0 ) );
×
892
            }
×
893
            else {
894
                it->second++;
895
            }
896
        }
897
        for( auto& e : dublicate_map ) {
898
            if( e.second > 0 ) {
899
                ErrorMessages::Error( "Each output field for option HISTORY_OUTPUT can only be set once.\nPlease check your .cfg file.",
900
                                      CURRENT_FUNCTION );
×
901
            }
902
        }
30✔
903

30✔
904
        // Check if the choice of history output is compatible to the problem
30✔
905
        for( unsigned short idx_historyOutput = 0; idx_historyOutput < _nHistoryOutput; idx_historyOutput++ ) {
906
            std::vector<SCALAR_OUTPUT> legalOutputs;
30✔
907
            std::vector<SCALAR_OUTPUT>::iterator it;
×
908

×
909
            switch( _problemName ) {
×
910
                case PROBLEM_HalfLattice:
911
                case PROBLEM_Lattice:
912
                    legalOutputs = { ITER,
913
                                     WALL_TIME,
914
                                     SIM_TIME,
915
                                     MASS,
30✔
916
                                     RMS_FLUX,
917
                                     VTK_OUTPUT,
918
                                     CSV_OUTPUT,
919
                                     CUR_OUTFLOW,
86✔
920
                                     TOTAL_OUTFLOW,
6✔
921
                                     CUR_OUTFLOW_P1,
6✔
922
                                     TOTAL_OUTFLOW_P1,
6✔
923
                                     CUR_OUTFLOW_P2,
6✔
924
                                     TOTAL_OUTFLOW_P2,
925
                                     MAX_OUTFLOW,
926
                                     CUR_PARTICLE_ABSORPTION,
86✔
927
                                     TOTAL_PARTICLE_ABSORPTION,
80✔
928
                                     MAX_PARTICLE_ABSORPTION };
80✔
929
                    it           = std::find( legalOutputs.begin(), legalOutputs.end(), _historyOutput[idx_historyOutput] );
80✔
930
                    if( it == legalOutputs.end() ) {
80✔
931
                        std::string foundKey = findKey( ScalarOutput_Map, _historyOutput[idx_historyOutput] );
80✔
932
                        ErrorMessages::Error(
933
                            "Illegal output field <" + foundKey +
934
                                "> for option HISTORY_OUTPUT for this test case.\n"
935
                                "Supported fields are: ITER, SIM_TIME, WALL_TIME, MASS, RMS_FLUX, VTK_OUTPUT, CSV_OUTPUT, FINAL_TIME_OUTFLOW,\n"
86✔
UNCOV
936
                                "TOTAL_OUTFLOW, MAX_OUTFLOW, FINAL_TIME_PARTICLE_ABSORPTION, TOTAL_PARTICLE_ABSORPTION, MAX_PARTICLE_ABSORPTION\n"
×
937
                                "Please check your .cfg file.",
UNCOV
938
                            CURRENT_FUNCTION );
×
939
                    }
UNCOV
940
                    break;
×
941
                case PROBLEM_QuarterHohlraum:
×
942
                case PROBLEM_SymmetricHohlraum:
×
943
                    legalOutputs = { ITER,
×
944
                                     WALL_TIME,
945
                                     SIM_TIME,
946
                                     MASS,
86✔
UNCOV
947
                                     RMS_FLUX,
×
948
                                     VTK_OUTPUT,
949
                                     CSV_OUTPUT,
×
950
                                     CUR_OUTFLOW,
951
                                     TOTAL_OUTFLOW,
×
UNCOV
952
                                     MAX_OUTFLOW,
×
953
                                     TOTAL_PARTICLE_ABSORPTION_CENTER,
×
954
                                     TOTAL_PARTICLE_ABSORPTION_VERTICAL,
×
955
                                     TOTAL_PARTICLE_ABSORPTION_HORIZONTAL,
956
                                     TOTAL_PARTICLE_ABSORPTION,
957
                                     PROBE_MOMENT_TIME_TRACE,
958
                                     VAR_ABSORPTION_GREEN,
959
                                     ABSORPTION_GREEN_BLOCK,
960
                                     ABSORPTION_GREEN_LINE };
961

962
                    it = std::find( legalOutputs.begin(), legalOutputs.end(), _historyOutput[idx_historyOutput] );
172✔
963

964
                    if( it == legalOutputs.end() ) {
116✔
965
                        std::string foundKey = findKey( ScalarOutput_Map, _historyOutput[idx_historyOutput] );
30✔
966
                        ErrorMessages::Error(
30✔
967
                            "Illegal output field <" + foundKey +
30✔
968
                                "> for option HISTORY_OUTPUT for this test case.\n"
969
                                "Supported fields are: ITER, SIM_TIME, WALL_TIME, MASS RMS_FLUX, VTK_OUTPUT, CSV_OUTPUT, TOTAL_PARTICLE_ABSORPTION_CENTER, \n "
UNCOV
970
                                "TOTAL_PARTICLE_ABSORPTION_VERTICAL, TOTAL_PARTICLE_ABSORPTION_HORIZONTAL,PROBE_MOMENT_TIME_TRACE,  CUR_OUTFLOW, \n"
×
971
                                "TOTAL_OUTFLOW, MAX_OUTFLOW , VAR_ABSORPTION_GREEN, ABSORPTION_GREEN_BLOCK, ABSORPTION_GREEN_LINE \n"
972
                                "Please check your .cfg file.",
973
                            CURRENT_FUNCTION );
116✔
974
                    }
30✔
UNCOV
975
                    break;
×
976

977
                default:
978
                    legalOutputs = { ITER, WALL_TIME, SIM_TIME, MASS, RMS_FLUX, VTK_OUTPUT, CSV_OUTPUT, CUR_OUTFLOW, TOTAL_OUTFLOW, MAX_OUTFLOW };
979
                    it           = std::find( legalOutputs.begin(), legalOutputs.end(), _historyOutput[idx_historyOutput] );
980

981
                    if( it == legalOutputs.end() ) {
116✔
982
                        std::string foundKey = findKey( ScalarOutput_Map, _historyOutput[idx_historyOutput] );
60✔
983
                        ErrorMessages::Error(
30✔
984
                            "Illegal output field <" + foundKey +
985
                                "> for option SCREEN_OUTPUT for this test case.\n"
30✔
NEW
986
                                "Supported fields are: ITER, SIM_TIME, WALL_TIME, MASS RMS_FLUX, VTK_OUTPUT, CSV_OUTPUT, CUR_OUTFLOW, TOTAL_OUTFLOW, MAX_OUTFLOW \n"
×
987
                                "Please check your .cfg file.",
988
                            CURRENT_FUNCTION );
×
989
                    }
990
                    break;
991
            }
992
        }
993

994
        // Set ITER always to index 0 . Assume only one instance of iter is chosen
995
        if( _nHistoryOutput > 0 ) {
996
            std::vector<SCALAR_OUTPUT>::iterator it;
997
            it = find( _historyOutput.begin(), _historyOutput.end(), ITER );
998
            _historyOutput.erase( it );
999
            _historyOutput.insert( _historyOutput.begin(), ITER );
1000
        }
1001
        // Set default screen output
1002
        if( _nHistoryOutput == 0 ) {
1003
            _nHistoryOutput = 5;
UNCOV
1004
            _historyOutput.push_back( ITER );
×
1005
            _historyOutput.push_back( MASS );
×
1006
            _historyOutput.push_back( RMS_FLUX );
×
1007
            _historyOutput.push_back( VTK_OUTPUT );
×
1008
            _historyOutput.push_back( CSV_OUTPUT );
×
1009
        }
×
1010

1011
        // Postprocessing for probing moments in symmetric Hohlraum. Make it four outputs
1012
        if( _problemName == PROBLEM_SymmetricHohlraum ) {
1013
            std::vector<SCALAR_OUTPUT>::iterator it;
1014
            it = find( _historyOutput.begin(), _historyOutput.end(), PROBE_MOMENT_TIME_TRACE );
1015
            if( it != _historyOutput.end() ) {
UNCOV
1016
                _historyOutput.erase( it );
×
1017
                _nHistoryOutput += 11;    // extend the screen output by the number of probing points
×
1018
                for( unsigned i = 0; i < 12; i++ ) _historyOutput.push_back( PROBE_MOMENT_TIME_TRACE );
UNCOV
1019
            }
×
1020
        }
1021
        if( _problemName == PROBLEM_QuarterHohlraum ) {
1022
            std::vector<SCALAR_OUTPUT>::iterator it;
1023
            it = find( _historyOutput.begin(), _historyOutput.end(), PROBE_MOMENT_TIME_TRACE );
1024
            if( it != _historyOutput.end() ) {
1025
                _historyOutput.erase( it );
1026
                _nHistoryOutput += 5;    // extend the screen output by the number of probing points
1027
                for( unsigned i = 0; i < 6; i++ ) _historyOutput.push_back( PROBE_MOMENT_TIME_TRACE );
1028
            }
1029
        }
1030

1031
        if( _problemName == PROBLEM_SymmetricHohlraum || _problemName == PROBLEM_QuarterHohlraum ) {
1032
            std::vector<SCALAR_OUTPUT>::iterator it;
1033
            it = find( _historyOutput.begin(), _historyOutput.end(), ABSORPTION_GREEN_LINE );
1034
            if( it != _historyOutput.end() ) {
1035
                _historyOutput.erase( it );
1036
                _nHistoryOutput += _nProbingCellsLineGreenHohlraum - 1;    // extend the screen output by the number of probing points
×
1037
                for( unsigned i = 0; i < _nProbingCellsLineGreenHohlraum; i++ ) _historyOutput.push_back( ABSORPTION_GREEN_LINE );
1038
            }
×
1039

1040
            it = find( _historyOutput.begin(), _historyOutput.end(), ABSORPTION_GREEN_BLOCK );
×
1041
            if( it != _historyOutput.end() ) {
×
1042
                _historyOutput.erase( it );
×
1043
                _nHistoryOutput += 44 - 1;    // extend the screen output by the number of probing points
×
1044
                for( unsigned i = 0; i < 44; i++ ) _historyOutput.push_back( ABSORPTION_GREEN_BLOCK );
1045
            }
1046
        }
1047
    }
1048

1049
    // Mesh postprocessing
1050
    {
1051
        if( _dim < (unsigned short)1 || _dim > (unsigned short)3 ) {
×
1052
            std::string msg = "Dimension " + std::to_string( _dim ) + "not supported.\n";
1053
            ErrorMessages::Error( msg, CURRENT_FUNCTION );
30✔
1054
        }
30✔
1055
    }
30✔
1056

1057
    // Data generator postprocessing
30✔
1058
    {
×
1059
        if( _alphaBound <= 0 ) {
×
1060
            std::string msg = "Norm boundary for alpha sampling must be positive.\n Current choice: " + std::to_string( _alphaSampling ) +
×
1061
                              ". Check choice of ALPHA_SAMPLING_BOUND.";
1062
            ErrorMessages::Error( msg, CURRENT_FUNCTION );
1063
        }
1064
        if( _minEVAlphaSampling <= 0 ) {
1065
            std::string msg =
1066
                "Minimal Eigenvalue threshold of the entropy hession must be positive.\n Current choice: " + std::to_string( _alphaSampling ) +
30✔
1067
                ". Check choice of MIN_EIGENVALUE_THRESHOLD.";
1068
            ErrorMessages::Error( msg, CURRENT_FUNCTION );
1069
        }
1070
    }
1071

86✔
1072
    // Optimizer postprocessing
6✔
1073
    {
6✔
1074
        if( _regularizerGamma <= 0.0 ) {
6✔
1075
            ErrorMessages::Error( "REGULARIZER_GAMMA must be positive.", CURRENT_FUNCTION );
6✔
1076
        }
1077

1078
        if( _entropyOptimizerName == ML ) {
86✔
1079
            // set regularizer gamma to the correct value
80✔
1080
            switch( _neuralGamma ) {
80✔
1081
                case 0: _regularizerGamma = 0; break;
80✔
1082
                case 1: _regularizerGamma = 0.1; break;
80✔
1083
                case 2: _regularizerGamma = 0.01; break;
80✔
1084
                case 3: _regularizerGamma = 0.001; break;
80✔
1085
            }
1086
        }
1087
        if( _entropyOptimizerName == NEWTON ) {
1088
            _regularizerGamma = 0.0;
86✔
1089
        }
×
1090
    }
×
1091
}
×
1092

×
1093
void Config::SetOutput() {
×
1094
    // Set Output for settings, i.e. feedback on what has been chosen
×
1095
}
1096

1097
bool Config::TokenizeString( string& str, string& option_name, vector<string>& option_value ) {
86✔
1098
    const string delimiters( " (){}:,\t\n\v\f\r" );
×
1099
    // check for comments or empty string
×
1100
    string::size_type pos, last_pos;
×
1101
    pos = str.find_first_of( "%" );
×
1102
    if( ( str.length() == 0 ) || ( pos == 0 ) ) {
×
1103
        // str is empty or a comment line, so no option here
×
1104
        return false;
1105
    }
1106
    if( pos != string::npos ) {
1107
        // remove comment at end if necessary
86✔
1108
        str.erase( pos );
×
1109
    }
×
1110

×
1111
    // look for line composed on only delimiters (usually whitespace)
×
1112
    pos = str.find_first_not_of( delimiters );
×
1113
    if( pos == string::npos ) {
×
1114
        return false;
1115
    }
1116

×
1117
    // find the equals sign and split string
×
1118
    string name_part, value_part;
×
1119
    pos = str.find( "=" );
×
1120
    if( pos == string::npos ) {
×
1121
        string errmsg = "Error in Config::TokenizeString(): line in the configuration file with no \"=\" sign.  ";
1122
        errmsg += "\nLook for: \n  str.length() = " + std::to_string( str.length() );
1123
        spdlog::error( errmsg );
1124
        throw( -1 );
1125
    }
1126
    name_part  = str.substr( 0, pos );
1127
    value_part = str.substr( pos + 1, string::npos );
86✔
1128

×
1129
    // the first_part should consist of one string with no interior delimiters
×
1130
    last_pos = name_part.find_first_not_of( delimiters, 0 );
1131
    pos      = name_part.find_first_of( delimiters, last_pos );
1132
    if( ( name_part.length() == 0 ) || ( last_pos == string::npos ) ) {
1133
        string errmsg = "Error in Config::TokenizeString(): ";
1134
        errmsg += "line in the configuration file with no name before the \"=\" sign.\n";
1135
        spdlog::error( errmsg );
86✔
1136
        throw( -1 );
×
1137
    }
×
1138
    if( pos == string::npos ) pos = name_part.length();
×
1139
    option_name = name_part.substr( last_pos, pos - last_pos );
1140
    last_pos    = name_part.find_first_not_of( delimiters, pos );
86✔
1141
    if( last_pos != string::npos ) {
1142
        string errmsg = "Error in  Config::TokenizeString(): ";
×
1143
        errmsg += "two or more options before an \"=\" sign in the configuration file.";
×
1144
        spdlog::error( errmsg );
×
1145
        throw( -1 );
1146
    }
1147
    TextProcessingToolbox::StringToUpperCase( option_name );
1148

1149
    // now fill the option value vector
1150
    option_value.clear();
86✔
1151
    last_pos = value_part.find_first_not_of( delimiters, 0 );
×
1152
    pos      = value_part.find_first_of( delimiters, last_pos );
1153
    while( string::npos != pos || string::npos != last_pos ) {
1154
        // add token to the vector<string>
86✔
1155
        option_value.push_back( value_part.substr( last_pos, pos - last_pos ) );
1156
        // skip delimiters
×
1157
        last_pos = value_part.find_first_not_of( delimiters, pos );
×
1158
        // find next "non-delimiter"
×
1159
        pos = value_part.find_first_of( delimiters, last_pos );
×
1160
    }
×
1161
    if( option_value.size() == 0 ) {
1162
        string errmsg = "Error in  Config::TokenizeString(): ";
1163
        errmsg += "option " + option_name + " in configuration file with no value assigned.\n";
86✔
1164
        spdlog::error( errmsg );
78✔
1165
        throw( -1 );
1166
    }
1167

86✔
1168
    // look for ';' DV delimiters attached to values
1169
    vector<string>::iterator it;
86✔
1170
    it = option_value.begin();
1171
    while( it != option_value.end() ) {
86✔
1172
        if( it->compare( ";" ) == 0 ) {
1173
            it++;
2,818✔
1174
            continue;
5,636✔
1175
        }
1176

1177
        pos = it->find( ';' );
2,818✔
1178
        if( pos != string::npos ) {
2,818✔
1179
            string before_semi = it->substr( 0, pos );
1180
            string after_semi  = it->substr( pos + 1, string::npos );
1,798✔
1181
            if( before_semi.empty() ) {
1182
                *it = ";";
1,020✔
1183
                it++;
1184
                option_value.insert( it, after_semi );
2✔
1185
            }
1186
            else {
1187
                *it = before_semi;
1188
                it++;
1,020✔
1189
                vector<string> to_insert;
1,020✔
1190
                to_insert.push_back( ";" );
×
1191
                if( !after_semi.empty() ) to_insert.push_back( after_semi );
1192
                option_value.insert( it, to_insert.begin(), to_insert.end() );
1193
            }
1194
            it = option_value.begin();    // go back to beginning; not efficient
2,040✔
1195
            continue;
1,020✔
1196
        }
1,020✔
1197
        else {
×
1198
            it++;
×
1199
        }
×
1200
    }
×
1201

1202
    // remove any consecutive ";"
1,020✔
1203
    it                = option_value.begin();
1,020✔
1204
    bool semi_at_prev = false;
1205
    while( it != option_value.end() ) {
1206
        if( semi_at_prev ) {
1,020✔
1207
            if( it->compare( ";" ) == 0 ) {
1,020✔
1208
                option_value.erase( it );
1,020✔
1209
                it           = option_value.begin();
×
1210
                semi_at_prev = false;
×
1211
                continue;
×
1212
            }
×
1213
        }
1214
        if( it->compare( ";" ) == 0 ) {
1,020✔
1215
            semi_at_prev = true;
1,020✔
1216
        }
1,020✔
1217
        else {
1,020✔
1218
            semi_at_prev = false;
×
1219
        }
×
1220
        it++;
×
1221
    }
×
1222

1223
    return true;
1,020✔
1224
}
1225

1226
void Config::InitLogger() {
1,020✔
1227
    int rank = 0;
1,020✔
1228
#ifdef IMPORT_MPI
1,020✔
1229
    MPI_Comm_rank( MPI_COMM_WORLD, &rank );    // Initialize MPI
2,102✔
1230
#endif
1231

1,082✔
1232
    if( rank == 0 ) {
1233

1,082✔
1234
        // Declare Logger
1235
        spdlog::level::level_enum terminalLogLvl;
1,082✔
1236
        spdlog::level::level_enum fileLogLvl;
1237

1,020✔
1238
        // Choose Logger
×
1239
#ifdef BUILD_TESTING
×
1240
        terminalLogLvl = spdlog::level::err;
×
1241
        fileLogLvl     = spdlog::level::info;
×
1242
#elif NDEBUG
1243
        terminalLogLvl = spdlog::level::info;
1244
        fileLogLvl     = spdlog::level::info;
1245
#else
1,020✔
1246
        terminalLogLvl = spdlog::level::debug;
1,020✔
1247
        fileLogLvl     = spdlog::level::debug;
2,102✔
1248
#endif
1,082✔
1249

×
1250
        // create log dir if not existent
×
1251
        if( !std::filesystem::exists( _logDir ) ) {
1252
            std::filesystem::create_directory( _logDir );
1253
        }
1,082✔
1254

1,082✔
1255
        if( !spdlog::get( "event" ) ) {
×
1256
            // create sinks if level is not off
×
1257
            std::vector<spdlog::sink_ptr> sinks;
×
1258
            if( terminalLogLvl != spdlog::level::off ) {
×
1259
                // create spdlog terminal sink
×
1260
                auto terminalSink = std::make_shared<spdlog::sinks::stdout_sink_mt>();
×
1261
                terminalSink->set_level( terminalLogLvl );
1262
                terminalSink->set_pattern( "%v" );
1263
                sinks.push_back( terminalSink );
×
1264
            }
×
1265
            if( fileLogLvl != spdlog::level::off ) {
×
1266
                // define filename on root
×
1267
                // int pe = 0;
×
1268
                // MPI_Comm_rank( MPI_COMM_WORLD, &pe );
×
1269
                // char cfilename[1024];
1270

×
1271
                // if( pe == 0 ) {
×
1272
                //  get date and time
1273
                time_t now = time( nullptr );
1274
                struct tm tstruct;
1,082✔
1275
                char buf[80];
1276
                tstruct = *localtime( &now );
1277
                strftime( buf, sizeof( buf ), "%Y-%m-%d_%X", &tstruct );
1278

1279
                // set filename
1,020✔
1280
                std::string filepathStr;
1,020✔
1281
                if( _logFileName.compare( "use_date" ) == 0 ) {
2,102✔
1282
                    _logFileName = buf;    // set filename to date and time
1,082✔
1283
                    filepathStr  = _logDir + _logFileName;
×
1284
                }
×
1285
                else {
×
1286
                    std::filesystem::path filePath( _logDir + _logFileName );
×
1287
                    std::string baseFilename( _logDir + _logFileName );
×
1288
                    filepathStr = _logDir + _logFileName;
1289
                    // Check if the file with the original name exists
1290
                    if( std::filesystem::exists( filePath ) ) {
1,082✔
1291
                        // Extract the stem and extension
×
1292
                        std::string stem      = filePath.stem().string();
1293
                        std::string extension = filePath.extension().string();
1294

1,082✔
1295
                        // Counter for incrementing the filename
1296
                        int counter = 1;
1,082✔
1297

1298
                        // Keep incrementing the counter until a unique filename is found
1299
                        while( std::filesystem::exists( filePath ) ) {
1,020✔
1300
                            stem = baseFilename + std::to_string( counter );
1301
                            filePath.replace_filename( stem + extension );
1302
                            counter++;
86✔
1303
                        }
86✔
1304
                    }
1305
                    filepathStr = filePath.string();
1306
                }
1307
                //}
1308
                // MPI_Bcast( &cfilename, sizeof( cfilename ), MPI_CHAR, 0, MPI_COMM_WORLD );
86✔
1309
                // MPI_Barrier( MPI_COMM_WORLD );
1310

1311
                // create spdlog file sink
1312
                auto fileSink = std::make_shared<spdlog::sinks::basic_file_sink_mt>( filepathStr );
1313
                fileSink->set_level( fileLogLvl );
1314
                fileSink->set_pattern( "%Y-%m-%d %H:%M:%S.%f | %v" );
1315
                sinks.push_back( fileSink );
1316
            }
86✔
1317

86✔
1318
            // register all sinks
1319
            auto event_logger = std::make_shared<spdlog::logger>( "event", begin( sinks ), end( sinks ) );
1320
            spdlog::register_logger( event_logger );
1321
            spdlog::flush_every( std::chrono::seconds( 5 ) );
1322
        }
1323

1324
        if( !spdlog::get( "tabular" ) ) {
1325
            // create sinks if level is not off
1326
            std::vector<spdlog::sink_ptr> sinks;
1327
            if( fileLogLvl != spdlog::level::off ) {
86✔
1328
                // define filename on root
3✔
1329
                // int pe = 0;
1330
                // MPI_Comm_rank( MPI_COMM_WORLD, &pe );
1331
                // char cfilename[1024];
86✔
1332

1333
                // if( pe == 0 ) {
20✔
1334
                //  get date and time
10✔
1335
                time_t now = time( nullptr );
1336
                struct tm tstruct;
10✔
1337
                char buf[80];
10✔
1338
                tstruct = *localtime( &now );
10✔
1339
                strftime( buf, sizeof( buf ), "%Y-%m-%d_%X.csv", &tstruct );
10✔
1340

1341
                // set filename
10✔
1342
                // set filename
1343
                std::string filepathStr;
1344
                if( _logFileName.compare( "use_date" ) == 0 ) {
1345
                    _logFileName = buf;    // set filename to date and time
1346
                    filepathStr  = _logDir + _logFileName + ".csv";
1347
                }
1348
                else {
1349
                    std::filesystem::path filePath( _logDir + _logFileName + ".csv" );
10✔
1350
                    std::string baseFilename( _logDir + _logFileName );
1351
                    filepathStr = _logDir + _logFileName + ".csv";
1352
                    // Check if the file with the original name exists
10✔
1353
                    if( std::filesystem::exists( filePath ) ) {
10✔
1354
                        // Extract the stem and extension
1355
                        std::string stem      = filePath.stem().string();
1356
                        std::string extension = filePath.extension().string();
20✔
1357

10✔
1358
                        // Counter for incrementing the filename
2✔
1359
                        int counter = 1;
2✔
1360

1361
                        // Keep incrementing the counter until a unique filename is found
1362
                        while( std::filesystem::exists( filePath ) ) {
16✔
1363
                            stem = baseFilename + std::to_string( counter );
8✔
1364
                            filePath.replace_filename( stem + extension );
8✔
1365
                            counter++;
1366
                        }
8✔
1367
                    }
1368
                    filepathStr = filePath.string();
×
1369
                }
×
1370
                //}
1371
                // MPI_Bcast( &cfilename, sizeof( cfilename ), MPI_CHAR, 0, MPI_COMM_WORLD );
1372
                // MPI_Barrier( MPI_COMM_WORLD );
×
1373

1374
                // create spdlog file sink
1375
                auto fileSink = std::make_shared<spdlog::sinks::basic_file_sink_mt>( filepathStr );
×
1376
                fileSink->set_level( fileLogLvl );
×
1377
                fileSink->set_pattern( "%Y-%m-%d %H:%M:%S.%f ,%v" );
×
1378
                sinks.push_back( fileSink );
×
1379
            }
1380

1381
            // register all sinks
8✔
1382
            auto tabular_logger = std::make_shared<spdlog::logger>( "tabular", begin( sinks ), end( sinks ) );
1383
            spdlog::register_logger( tabular_logger );
1384
            spdlog::flush_every( std::chrono::seconds( 5 ) );
1385
        }
1386
    }
1387
#ifdef IMPORT_MPI
1388
    MPI_Barrier( MPI_COMM_WORLD );
10✔
1389
#endif
10✔
1390
}
10✔
1391

10✔
1392
// Function to find the key for a given value in a map
1393
template <typename K, typename V> K Config::findKey( const std::map<K, V>& myMap, const V& valueToFind ) {
1394
    for( const auto& pair : myMap ) {
1395
        if( pair.second == valueToFind ) {
10✔
1396
            return pair.first;    // Return the key if the value is found
10✔
1397
        }
10✔
1398
    }
1399
    // If the value is not found, you can return a default value or throw an exception
1400
    throw std::out_of_range( "Value not found in the map" );
86✔
1401
}
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