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

CSMMLab / KiT-RT / #143

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

push

travis-ci

web-flow
Merge b308cf063 into 3bfa2c39b

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

19 existing lines in 2 files now uncovered.

5474 of 9580 relevant lines covered (57.14%)

31176.1 hits per line

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

74.86
/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 ) {
80✔
28

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

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

36
    _baseConfig = true;
80✔
37

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

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

43
    SetPointersNull();
80✔
44

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

47
    SetConfigOptions();
80✔
48

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

51
    SetConfigParsing( case_filename );
80✔
52

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

55
    SetDefault();
80✔
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();
80✔
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();
80✔
74
}
80✔
75

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

79
    // delete _option map values proberly
80
    for( auto const& x : _optionMap ) {
5,904✔
81
        delete x.second;
5,832✔
82
        //_optionMap.erase( x.first );
83
    }
84
}
72✔
85

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

88
// Simple Options
89
void Config::AddBoolOption( const string name, bool& option_field, bool default_value ) {
1,120✔
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,120✔
93

94
    // Add this option to the list of all the options
95
    _allOptions.insert( pair<string, bool>( name, true ) );
1,120✔
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,120✔
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,120✔
106
}
1,120✔
107

108
void Config::AddDoubleOption( const string name, double& option_field, double default_value ) {
2,000✔
109
    assert( _optionMap.find( name ) == _optionMap.end() );
2,000✔
110
    _allOptions.insert( pair<string, bool>( name, true ) );
2,000✔
111
    OptionBase* val = new OptionDouble( name, option_field, default_value );
2,000✔
112
    _optionMap.insert( pair<string, OptionBase*>( name, val ) );
2,000✔
113
}
2,000✔
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 ) {
800✔
130
    assert( _optionMap.find( name ) == _optionMap.end() );
800✔
131
    _allOptions.insert( pair<string, bool>( name, true ) );
800✔
132
    OptionBase* val = new OptionString( name, option_field, default_value );
800✔
133
    _optionMap.insert( pair<string, OptionBase*>( name, val ) );
800✔
134
}
800✔
135

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

143
void Config::AddUnsignedShortOption( const string name, unsigned short& option_field, unsigned short default_value ) {
960✔
144
    assert( _optionMap.find( name ) == _optionMap.end() );
960✔
145
    _allOptions.insert( pair<string, bool>( name, true ) );
960✔
146
    OptionBase* val = new OptionUShort( name, option_field, default_value );
960✔
147
    _optionMap.insert( pair<string, OptionBase*>( name, val ) );
960✔
148
}
960✔
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 ) {
640✔
153
    assert( _optionMap.find( name ) == _optionMap.end() );
640✔
154
    _allOptions.insert( pair<string, bool>( name, true ) );
640✔
155
    OptionBase* val = new OptionEnum<Tenum>( name, enum_map, option_field, default_value );
640✔
156
    _optionMap.insert( pair<string, OptionBase*>( name, val ) );
640✔
157
    return;
1,280✔
158
}
159

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

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

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

187
// ---- Getter Functions ----
80✔
188

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

80✔
196
// ---- Setter Functions ----
80✔
197

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

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

80✔
206
void Config::SetConfigOptions() {
160✔
207

208
    /* BEGIN_CONFIG_OPTIONS */
80✔
209

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

80✔
213
    // File Structure related options
160✔
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" ) );
160✔
218
    /*! @brief LOG_DIR \n DESCRIPTION: Relative Directory of log files \n DEFAULT "/out" @ingroup Config.*/
160✔
219
    AddStringOption( "LOG_DIR", _logDir, string( "/out/logs" ) );
160✔
220
    /*! @brief LOG_DIR \n DESCRIPTION: Name of log files \n DEFAULT "/out" @ingroup Config.*/
160✔
221
    AddStringOption( "LOG_FILE", _logFileName, string( "use_date" ) );
160✔
222
    /*! @brief MESH_FILE \n DESCRIPTION: Name of mesh file \n DEFAULT "" \ingroup Config.*/
160✔
223
    AddStringOption( "MESH_FILE", _meshFile, string( "mesh.su2" ) );
224
    /*! @brief MESH_FILE \n DESCRIPTION: Name of mesh file \n DEFAULT "" \ingroup Config.*/
160✔
225
    AddStringOption( "CT_FILE", _ctFile, string( "/home/pia/kitrt/examples/meshes/phantom.png" ) );
160✔
226
    /*! @brief FORCE_CONNECTIVITY_RECOMPUTE \n DESCRIPTION:If true, mesh recomputes connectivity instead of loading from file \n DEFAULT false
160✔
227
     * \ingroup Config.*/
160✔
228
    AddBoolOption( "FORCE_CONNECTIVITY_RECOMPUTE", _forcedConnectivityWrite, false );
160✔
229
    /*! @brief RESTART_SOLUTION \n DESCRIPTION:If true, simulation loads a restart solution from file \n DEFAULT false
160✔
230
     * \ingroup Config.*/
231
    AddBoolOption( "LOAD_RESTART_SOLUTION", _loadrestartSolution, false );
232
    AddUnsignedLongOption( "SAVE_RESTART_SOLUTION_FREQUENCY", _saveRestartSolutionFrequency, false );
240✔
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
240✔
237
     */
240✔
238
    AddEnumOption( "QUAD_TYPE", _quadName, Quadrature_Map, QUAD_MonteCarlo );
240✔
239
    /*!\brief QUAD_ORDER \n DESCRIPTION: Order of Quadrature rule \n DEFAULT 2 \ingroup Config.*/
240✔
240
    AddUnsignedShortOption( "QUAD_ORDER", _quadOrder, 1 );
240✔
241

240✔
242
    // Solver related options
160✔
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 */
160✔
247
    AddUnsignedShortOption( "MAX_MOMENT_SOLVER", _maxMomentDegree, 1 );
160✔
248
    /*! @brief CFL \n DESCRIPTION: CFL number \n DEFAULT 1.0 @ingroup Config.*/
160✔
249
    AddDoubleOption( "CFL_NUMBER", _CFL, 1.0 );
160✔
250
    /*! @brief TIME_FINAL \n DESCRIPTION: Final time for simulation \n DEFAULT 1.0 @ingroup Config.*/
160✔
251
    AddDoubleOption( "TIME_FINAL", _tEnd, 1.0 );
160✔
252
    /*! @brief Problem \n DESCRIPTION: Type of problem setting \n DEFAULT PROBLEM_ElectronRT @ingroup Config.*/
80✔
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.*/
80✔
257
    AddUnsignedShortOption( "RECONS_ORDER", _reconsOrder, 1 );
80✔
258
    /*! @brief CleanFluxMatrices \n DESCRIPTION:  If true, very low entries (10^-10 or smaller) of the flux matrices will be set to zero,
80✔
259
     * to improve floating point accuracy \n DEFAULT false \ingroup Config */
80✔
260
    AddBoolOption( "CLEAN_FLUX_MATRICES", _cleanFluxMat, false );
80✔
261
    /*! @brief Realizability Step for MN solver \n DESCRIPTION: If true, MN solvers use a realizability reconstruction step in each time step. Also
80✔
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 );
44✔
266

60✔
267
    // Problem Related Options
59✔
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 */
1✔
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.
80✔
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 */
5,542✔
278
    AddStringOption( "STOPPING_POWER_FILE", _stoppingPowerFile, string( "stopping_power.txt" ) );
5,462✔
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 );
80✔
281

282
    // Linesource Testcase Options
80✔
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 */
80✔
292
    AddDoubleOption( "MAX_ENERGY_CSD", _maxEnergyCSD, 5.0 );
293

80✔
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
80✔
296
     * DEFAULT  10.0 \ingroup Config */
297
    AddDoubleOption( "LATTICE_DSGN_ABSORPTION_BLUE", _dsgnAbsBlue, 10.0 );
80✔
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 */
80✔
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
80✔
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
80✔
305
     * lower right (row major). \n DEFAULT \ingroup Config */
306
    AddDoubleListOption( "LATTICE_DSGN_SCATTER_INDIVIDUAL", _nDsgnScatterIndividual, _dsgnScatterIndividual );
307

80✔
308
    // Hohlraum related options
80✔
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 );
80✔
315
    AddDoubleOption( "POS_RED_LEFT_BOTTOM", _posRedLeftBottom, -0.4 );
316
    AddDoubleOption( "POS_BORDER_RED_LEFT", _posRedLeftBorder, -0.65 );
80✔
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 );
80✔
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
80✔
324
     * false \ingroup Config */
325
    AddBoolOption( "ENTROPY_DYNAMIC_CLOSURE", _entropyDynamicClosure, true );
80✔
326

327
    // Newton optimizer related options
80✔
328
    /*! @brief Regularization Parameter \n DESCRIPTION:  Regularization Parameter for the regularized entropy closure. Must not be negative \n DEFAULT
329
     * 1e-2 \ingroup Config */
80✔
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 */
80✔
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 */
80✔
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 );
80✔
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 );
80✔
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 */
80✔
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 );
80✔
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 );
80✔
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

80✔
353
    // Mesh related options
354
    // Boundary Markers
80✔
355
    /*!\brief BC_DIRICHLET\n DESCRIPTION: Dirichlet wall boundary marker(s) \ingroup Config*/
356
    AddStringListOption( "BC_DIRICHLET", _nMarkerDirichlet, _MarkerDirichlet );
80✔
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 */
80✔
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 */
80✔
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 */
80✔
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 );
80✔
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 */
80✔
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 );
80✔
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 */
80✔
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 );
80✔
386
    /*! @brief Determines, if TRAINING_SET_SIZE is counted by dimension \n DESCRIPTION: Determines, if TRAINING_SET_SIZE is counted by dimension   \n
80✔
387
     * DEFAULT true \ingroup Config */
80✔
388
    AddBoolOption( "SIZE_BY_DIMENSION", _sizeByDimension, true );
80✔
389
    /*! @brief Size of training data set \n DESCRIPTION: Size of training data set  \n DEFAULT 10 \ingroup Config */
80✔
390
    AddUnsignedLongOption( "MAX_VALUE_FIRST_MOMENT", _maxValFirstMoment, 10 );
80✔
391
    /*! @brief Data generator mode \n DESCRIPTION: Check, if data generator mode is active. If yes, no solver is called, but instead the data
80✔
392
     *         generator is executed \n DEFAULT false \ingroup Config */
80✔
393
    AddBoolOption( "DATA_GENERATOR_MODE", _dataGeneratorMode, false );
80✔
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 );
80✔
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 */
80✔
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 */
80✔
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
80✔
407
     * \ingroup Config */
408
    AddBoolOption( "UNIFORM_SAMPLING", _sampleUniform, true );
80✔
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 */
80✔
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
80✔
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 */
80✔
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 );
80✔
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 );
80✔
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
}
80✔
426

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

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

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

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

440
    string errorString;
441

80✔
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;
80✔
446

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

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

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

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

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

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

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

80✔
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() ) {
80✔
476
                string newString;
477
                newString.append( option_name );
478
                newString.append( ": option appears twice" );
80✔
479
                newString.append( "\n" );
480
                errorString.append( newString );
481
                err_count++;
80✔
482
                continue;
483
            }
484

80✔
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 ) );
80✔
488
            _allOptions.erase( option_name );
489

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

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

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

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

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

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

×
514
void Config::SetPostprocessing() {
515

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

521
    // setup relative paths
160✔
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();
3,000✔
526
    _ctFile            = std::filesystem::path( _inputDir ).append( _ctFile ).lexically_normal();
527
    _hydrogenFile      = std::filesystem::path( _inputDir ).append( _hydrogenFile ).lexically_normal();
2,920✔
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_directories( _outputDir );
534

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

538
    // Regroup Boundary Conditions to  std::vector<std::pair<std::string, BOUNDARY_TYPE>> _boundaries;
1,018✔
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,018✔
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,018✔
564
    }
1,018✔
565

566
    // Quadrature Postprocessing
567
    {
568
        QuadratureBase* quad                      = QuadratureBase::Create( this );
2,036✔
569
        std::vector<unsigned short> supportedDims = quad->GetSupportedDims();
1,018✔
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
80✔
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 ) + ".";
80✔
584
            ErrorMessages::Error( msg, CURRENT_FUNCTION );
80✔
585
        }
586
    }
80✔
587

588
    // --- Solver setup ---
80✔
589
    {
590
        if( GetSolverName() == PN_SOLVER && GetSphericalBasisName() != SPHERICAL_HARMONICS ) {
80✔
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 );
80✔
594
        }
80✔
595

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

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

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

608
        if( GetSolverName() == PN_SOLVER || GetSolverName() == CSD_PN_SOLVER ) {
609
            _dim        = 3;
80✔
610
            auto log    = spdlog::get( "event" );
611
            auto logCSV = spdlog::get( "tabular" );
612
            log->info(
80✔
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." );
115✔
616
        }
35✔
617
    }
618

129✔
619
    // --- Output Postprocessing ---
49✔
620

621
    // Volume Output Postprocessing
622
    {
623
        // Check for doublicates in VOLUME OUTPUT
80✔
624
        std::map<VOLUME_OUTPUT, int> dublicate_map;
5✔
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] );
5✔
628
            if( it == dublicate_map.end() ) {
5✔
629
                dublicate_map.insert( std::pair<VOLUME_OUTPUT, int>( _volumeOutput[idx_volOutput], 0 ) );
75✔
630
            }
631
            else {
632
                it->second++;
633
            }
80✔
634
        }
8✔
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 );
8✔
639
            }
72✔
640
        }
641

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

80✔
645
        for( unsigned short idx_volOutput = 0; idx_volOutput < _nVolumeOutput; idx_volOutput++ ) {
160✔
646
            switch( _solverName ) {
647
                case SN_SOLVER:
80✔
648
                    if( _problemName == PROBLEM_Linesource )
649
                        supportedGroups = { MINIMAL, ANALYTIC };
×
650
                    else {
×
651
                        supportedGroups = { MINIMAL };
652
                        if( _HPC ) supportedGroups = { MINIMAL, MOMENTS };
80✔
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.",
80✔
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
80✔
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
80✔
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++ ) {
80✔
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 );
80✔
681
                    }
×
682
                    break;
683
                case PN_SOLVER:
684
                    supportedGroups = { MINIMAL, MOMENTS, ANALYTIC };
80✔
685
                    if( supportedGroups.end() == std::find( supportedGroups.begin(), supportedGroups.end(), _volumeOutput[idx_volOutput] ) ) {
4✔
686

12✔
687
                        ErrorMessages::Error( "PN_SOLVER only supports volume output ANALYTIC, MINIMAL and MOMENTS.\nPlease check your .cfg file.",
12✔
688
                                              CURRENT_FUNCTION );
4✔
689
                    }
690
                    if( _volumeOutput[idx_volOutput] == ANALYTIC && _problemName != PROBLEM_Linesource ) {
4✔
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.",
160✔
701
                                              CURRENT_FUNCTION );
702
                    }
111✔
703
                    break;
31✔
704
                case CSD_PN_SOLVER:
31✔
705
                    supportedGroups = { MINIMAL, MEDICAL, MOMENTS };
31✔
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
                    }
111✔
712
                    break;
31✔
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 );
160✔
720
                    }
721
                    break;
111✔
722
                default:
31✔
723
                    ErrorMessages::Error( "Solver output check not implemented for this Solver.\nThis is the fault of the coder.", CURRENT_FUNCTION );
21✔
724
            }
21✔
725
        }
9✔
726

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

734
    // Screen Output Postprocessing
735
    {
736
        // Check for doublicates in SCALAR OUTPUT
21✔
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() ) {
21✔
742
                dublicate_map.insert( std::pair<SCALAR_OUTPUT, int>( _screenOutput[idx_screenOutput], 0 ) );
4✔
743
            }
744
            else {
4✔
745
                it->second++;
×
746
            }
4✔
747
        }
3✔
748
        for( auto& e : dublicate_map ) {
749
            if( e.second > 0 ) {
1✔
750
                ErrorMessages::Error( "Each output field for option SCREEN_OUTPUT can only be set once.\nPlease check your .cfg file.",
4✔
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 ) {
4✔
759
                case PROBLEM_HalfLattice:
2✔
760
                case PROBLEM_Lattice:
2✔
761
                    legalOutputs = { ITER,
2✔
762
                                     WALL_TIME,
763
                                     SIM_TIME,
×
764
                                     MASS,
765
                                     RMS_FLUX,
766
                                     VTK_OUTPUT,
2✔
767
                                     CSV_OUTPUT,
×
768
                                     CUR_OUTFLOW,
769
                                     TOTAL_OUTFLOW,
770
                                     CUR_OUTFLOW_P1,
771
                                     TOTAL_OUTFLOW_P1,
2✔
772
                                     CUR_OUTFLOW_P2,
×
773
                                     TOTAL_OUTFLOW_P2,
×
774
                                     MAX_OUTFLOW,
×
775
                                     CUR_PARTICLE_ABSORPTION,
776
                                     TOTAL_PARTICLE_ABSORPTION,
×
777
                                     MAX_PARTICLE_ABSORPTION };
778
                    it           = std::find( legalOutputs.begin(), legalOutputs.end(), _screenOutput[idx_screenOutput] );
779
                    if( it == legalOutputs.end() ) {
×
780
                        std::string foundKey = findKey( ScalarOutput_Map, _screenOutput[idx_screenOutput] );
4✔
781
                        ErrorMessages::Error(
4✔
782
                            "Illegal output field <" + foundKey +
4✔
783
                                "> for option SCREEN_OUTPUT for this test case.\n"
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
                    }
4✔
789
                    break;
×
790
                case PROBLEM_QuarterHohlraum:
×
791
                case PROBLEM_SymmetricHohlraum:
×
792
                    legalOutputs = {
793
                        ITER,
×
794
                        SIM_TIME,
795
                        WALL_TIME,
796
                        MASS,
797
                        RMS_FLUX,
×
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,
80✔
805
                        TOTAL_PARTICLE_ABSORPTION_HORIZONTAL,
51✔
806
                        TOTAL_PARTICLE_ABSORPTION,
51✔
807
                        PROBE_MOMENT_TIME_TRACE,
808
                        VAR_ABSORPTION_GREEN,
809
                        AVG_ABSORPTION_GREEN_BLOCK_INTEGRATED,
810
                        VAR_ABSORPTION_GREEN_BLOCK_INTEGRATED,
811
                    };
812

813
                    it = std::find( legalOutputs.begin(), legalOutputs.end(), _screenOutput[idx_screenOutput] );
160✔
814

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

829
                default:
830
                    legalOutputs = { ITER, SIM_TIME, WALL_TIME, MASS, RMS_FLUX, VTK_OUTPUT, CSV_OUTPUT, CUR_OUTFLOW, TOTAL_OUTFLOW, MAX_OUTFLOW };
831
                    it           = std::find( legalOutputs.begin(), legalOutputs.end(), _screenOutput[idx_screenOutput] );
107✔
832

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

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

865
            it = find( _screenOutput.begin(), _screenOutput.end(), PROBE_MOMENT_TIME_TRACE );
6✔
866

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

876
            it = find( _screenOutput.begin(), _screenOutput.end(), PROBE_MOMENT_TIME_TRACE );
877

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

886
    // History Output Postprocessing
887
    {
6✔
888
        // Check for doublicates in HISTORY OUTPUT
889
        std::map<SCALAR_OUTPUT, int> dublicate_map;
6✔
890

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

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

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

967
                    it = std::find( legalOutputs.begin(), legalOutputs.end(), _historyOutput[idx_historyOutput] );
130✔
968

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

983
                default:
984
                    legalOutputs = { ITER, WALL_TIME, SIM_TIME, MASS, RMS_FLUX, VTK_OUTPUT, CSV_OUTPUT, CUR_OUTFLOW, TOTAL_OUTFLOW, MAX_OUTFLOW };
130✔
985
                    it           = std::find( legalOutputs.begin(), legalOutputs.end(), _historyOutput[idx_historyOutput] );
100✔
986

50✔
987
                    if( it == legalOutputs.end() ) {
988
                        std::string foundKey = findKey( ScalarOutput_Map, _historyOutput[idx_historyOutput] );
50✔
989
                        ErrorMessages::Error(
17✔
990
                            "Illegal output field <" + foundKey +
UNCOV
991
                                "> for option SCREEN_OUTPUT for this test case.\n"
×
992
                                "Supported fields are: ITER, SIM_TIME, WALL_TIME, MASS RMS_FLUX, VTK_OUTPUT, CSV_OUTPUT, CUR_OUTFLOW, TOTAL_OUTFLOW, MAX_OUTFLOW \n"
993
                                "Please check your .cfg file.",
994
                            CURRENT_FUNCTION );
995
                    }
996
                    break;
997
            }
998
        }
999

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

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

1037
        if( _problemName == PROBLEM_SymmetricHohlraum || _problemName == PROBLEM_QuarterHohlraum ) {
1038
            std::vector<SCALAR_OUTPUT>::iterator it;
1039
            it = find( _historyOutput.begin(), _historyOutput.end(), ABSORPTION_GREEN_LINE );
1040
            if( it != _historyOutput.end() ) {
1041
                _historyOutput.erase( it );
18✔
1042
                _nHistoryOutput += _nProbingCellsLineGreenHohlraum - 1;    // extend the screen output by the number of probing points
1043
                for( unsigned i = 0; i < _nProbingCellsLineGreenHohlraum; i++ ) _historyOutput.push_back( ABSORPTION_GREEN_LINE );
18✔
1044
            }
1045

18✔
UNCOV
1046
            it = find( _historyOutput.begin(), _historyOutput.end(), ABSORPTION_GREEN_BLOCK );
×
1047
            if( it != _historyOutput.end() ) {
×
1048
                _historyOutput.erase( it );
×
1049
                _nHistoryOutput += 44 - 1;    // extend the screen output by the number of probing points
1050
                for( unsigned i = 0; i < 44; i++ ) _historyOutput.push_back( ABSORPTION_GREEN_BLOCK );
1051
            }
1052

1053
        }
1054
    }
1055

1056
    // Mesh postprocessing
1057
    {
18✔
1058
        if( _dim < (unsigned short)1 || _dim > (unsigned short)3 ) {
1059
            std::string msg = "Dimension " + std::to_string( _dim ) + "not supported.\n";
15✔
1060
            ErrorMessages::Error( msg, CURRENT_FUNCTION );
15✔
1061
        }
15✔
1062
    }
1063

15✔
UNCOV
1064
    // Data generator postprocessing
×
1065
    {
×
1066
        if( _alphaBound <= 0 ) {
×
1067
            std::string msg = "Norm boundary for alpha sampling must be positive.\n Current choice: " + std::to_string( _alphaSampling ) +
1068
                              ". Check choice of ALPHA_SAMPLING_BOUND.";
1069
            ErrorMessages::Error( msg, CURRENT_FUNCTION );
1070
        }
1071
        if( _minEVAlphaSampling <= 0 ) {
1072
            std::string msg =
15✔
1073
                "Minimal Eigenvalue threshold of the entropy hession must be positive.\n Current choice: " + std::to_string( _alphaSampling ) +
1074
                ". Check choice of MIN_EIGENVALUE_THRESHOLD.";
1075
            ErrorMessages::Error( msg, CURRENT_FUNCTION );
1076
        }
1077
    }
80✔
1078

5✔
1079
    // Optimizer postprocessing
5✔
1080
    {
5✔
1081
        if( _regularizerGamma <= 0.0 ) {
5✔
1082
            ErrorMessages::Error( "REGULARIZER_GAMMA must be positive.", CURRENT_FUNCTION );
1083
        }
1084

80✔
1085
        if( _entropyOptimizerName == ML ) {
75✔
1086
            // set regularizer gamma to the correct value
75✔
1087
            switch( _neuralGamma ) {
75✔
1088
                case 0: _regularizerGamma = 0; break;
75✔
1089
                case 1: _regularizerGamma = 0.1; break;
75✔
1090
                case 2: _regularizerGamma = 0.01; break;
75✔
1091
                case 3: _regularizerGamma = 0.001; break;
1092
            }
1093
        }
1094
        if( _entropyOptimizerName == NEWTON ) {
80✔
1095
            _regularizerGamma = 0.0;
1✔
1096
        }
1✔
1097
    }
1✔
1098
}
1✔
1099

1✔
1100
void Config::SetOutput() {
13✔
1101
    // Set Output for settings, i.e. feedback on what has been chosen
1102
}
1103

80✔
UNCOV
1104
bool Config::TokenizeString( string& str, string& option_name, vector<string>& option_value ) {
×
1105
    const string delimiters( " (){}:,\t\n\v\f\r" );
×
1106
    // check for comments or empty string
×
1107
    string::size_type pos, last_pos;
×
1108
    pos = str.find_first_of( "%" );
×
1109
    if( ( str.length() == 0 ) || ( pos == 0 ) ) {
×
1110
        // str is empty or a comment line, so no option here
1111
        return false;
1112
    }
1113
    if( pos != string::npos ) {
80✔
1114
        // remove comment at end if necessary
1✔
1115
        str.erase( pos );
1✔
1116
    }
1✔
1117

1✔
1118
    // look for line composed on only delimiters (usually whitespace)
1✔
1119
    pos = str.find_first_not_of( delimiters );
21✔
1120
    if( pos == string::npos ) {
1121
        return false;
1122
    }
1✔
1123

1✔
1124
    // find the equals sign and split string
1✔
1125
    string name_part, value_part;
1✔
1126
    pos = str.find( "=" );
45✔
1127
    if( pos == string::npos ) {
1128
        string errmsg = "Error in Config::TokenizeString(): line in the configuration file with no \"=\" sign.  ";
1129
        errmsg += "\nLook for: \n  str.length() = " + std::to_string( str.length() );
1130
        spdlog::error( errmsg );
1131
        throw( -1 );
1132
    }
1133
    name_part  = str.substr( 0, pos );
1134
    value_part = str.substr( pos + 1, string::npos );
80✔
1135

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

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

80✔
1175
    // look for ';' DV delimiters attached to values
1176
    vector<string>::iterator it;
80✔
1177
    it = option_value.begin();
1178
    while( it != option_value.end() ) {
80✔
1179
        if( it->compare( ";" ) == 0 ) {
1180
            it++;
2,920✔
1181
            continue;
5,840✔
1182
        }
1183

1184
        pos = it->find( ';' );
2,920✔
1185
        if( pos != string::npos ) {
2,920✔
1186
            string before_semi = it->substr( 0, pos );
1187
            string after_semi  = it->substr( pos + 1, string::npos );
1,902✔
1188
            if( before_semi.empty() ) {
1189
                *it = ";";
1,018✔
1190
                it++;
1191
                option_value.insert( it, after_semi );
1✔
1192
            }
1193
            else {
1194
                *it = before_semi;
1195
                it++;
1,018✔
1196
                vector<string> to_insert;
1,018✔
1197
                to_insert.push_back( ";" );
×
1198
                if( !after_semi.empty() ) to_insert.push_back( after_semi );
1199
                option_value.insert( it, to_insert.begin(), to_insert.end() );
1200
            }
1201
            it = option_value.begin();    // go back to beginning; not efficient
2,036✔
1202
            continue;
1,018✔
1203
        }
1,018✔
1204
        else {
×
1205
            it++;
×
1206
        }
×
1207
    }
×
1208

1209
    // remove any consecutive ";"
1,018✔
1210
    it                = option_value.begin();
1,018✔
1211
    bool semi_at_prev = false;
1212
    while( it != option_value.end() ) {
1213
        if( semi_at_prev ) {
1,018✔
1214
            if( it->compare( ";" ) == 0 ) {
1,018✔
1215
                option_value.erase( it );
1,018✔
1216
                it           = option_value.begin();
×
1217
                semi_at_prev = false;
×
1218
                continue;
×
1219
            }
×
1220
        }
1221
        if( it->compare( ";" ) == 0 ) {
1,018✔
1222
            semi_at_prev = true;
1,018✔
1223
        }
1,018✔
1224
        else {
1,018✔
1225
            semi_at_prev = false;
×
1226
        }
×
1227
        it++;
×
1228
    }
×
1229

1230
    return true;
1,018✔
1231
}
1232

1233
void Config::InitLogger() {
1,018✔
1234
    int rank = 0;
1,018✔
1235
#ifdef IMPORT_MPI
1,018✔
1236
    MPI_Comm_rank( MPI_COMM_WORLD, &rank );    // Initialize MPI
2,128✔
1237
#endif
1238

1,110✔
1239
    if( rank == 0 ) {
1240

1,110✔
1241
        // Declare Logger
1242
        spdlog::level::level_enum terminalLogLvl;
1,110✔
1243
        spdlog::level::level_enum fileLogLvl;
1244

1,018✔
1245
        // Choose Logger
×
1246
#ifdef BUILD_TESTING
×
1247
        terminalLogLvl = spdlog::level::err;
×
1248
        fileLogLvl     = spdlog::level::info;
×
1249
#elif NDEBUG
1250
        terminalLogLvl = spdlog::level::info;
1251
        fileLogLvl     = spdlog::level::info;
1252
#else
1,018✔
1253
        terminalLogLvl = spdlog::level::debug;
1,018✔
1254
        fileLogLvl     = spdlog::level::debug;
2,128✔
1255
#endif
1,110✔
1256

×
1257
        // create log dir if not existent
×
1258
        if( !std::filesystem::exists( _logDir ) ) {
1259
            std::filesystem::create_directories( _logDir );
1260
        }
1,110✔
1261

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

×
1278
                // if( pe == 0 ) {
×
1279
                //  get date and time
1280
                time_t now = time( nullptr );
1281
                struct tm tstruct;
1,110✔
1282
                char buf[80];
1283
                tstruct = *localtime( &now );
1284
                strftime( buf, sizeof( buf ), "%Y-%m-%d_%X", &tstruct );
1285

1286
                // set filename
1,018✔
1287
                std::string filepathStr;
1,018✔
1288
                if( _logFileName.compare( "use_date" ) == 0 ) {
2,128✔
1289
                    _logFileName = buf;    // set filename to date and time
1,110✔
1290
                    filepathStr  = _logDir + _logFileName;
×
1291
                }
×
1292
                else {
×
1293
                    std::filesystem::path filePath( _logDir + _logFileName );
×
1294
                    std::string baseFilename( _logDir + _logFileName );
×
1295
                    filepathStr = _logDir + _logFileName;
1296
                    // Check if the file with the original name exists
1297
                    if( std::filesystem::exists( filePath ) ) {
1,110✔
1298
                        // Extract the stem and extension
×
1299
                        std::string stem      = filePath.stem().string();
1300
                        std::string extension = filePath.extension().string();
1301

1,110✔
1302
                        // Counter for incrementing the filename
1303
                        int counter = 1;
1,110✔
1304

1305
                        // Keep incrementing the counter until a unique filename is found
1306
                        while( std::filesystem::exists( filePath ) ) {
1,018✔
1307
                            stem = baseFilename + std::to_string( counter );
1308
                            filePath.replace_filename( stem + extension );
1309
                            counter++;
80✔
1310
                        }
80✔
1311
                    }
1312
                    filepathStr = filePath.string();
1313
                }
1314
                //}
1315
                // MPI_Bcast( &cfilename, sizeof( cfilename ), MPI_CHAR, 0, MPI_COMM_WORLD );
80✔
1316
                // MPI_Barrier( MPI_COMM_WORLD );
1317

1318
                // create spdlog file sink
1319
                auto fileSink = std::make_shared<spdlog::sinks::basic_file_sink_mt>( filepathStr );
1320
                fileSink->set_level( fileLogLvl );
1321
                fileSink->set_pattern( "%Y-%m-%d %H:%M:%S.%f | %v" );
1322
                sinks.push_back( fileSink );
1323
            }
80✔
1324

80✔
1325
            // register all sinks
1326
            auto event_logger = std::make_shared<spdlog::logger>( "event", begin( sinks ), end( sinks ) );
1327
            spdlog::register_logger( event_logger );
1328
            spdlog::flush_every( std::chrono::seconds( 5 ) );
1329
        }
1330

1331
        if( !spdlog::get( "tabular" ) ) {
1332
            // create sinks if level is not off
1333
            std::vector<spdlog::sink_ptr> sinks;
1334
            if( fileLogLvl != spdlog::level::off ) {
80✔
1335
                // define filename on root
3✔
1336
                // int pe = 0;
1337
                // MPI_Comm_rank( MPI_COMM_WORLD, &pe );
1338
                // char cfilename[1024];
80✔
1339

1340
                // if( pe == 0 ) {
14✔
1341
                //  get date and time
7✔
1342
                time_t now = time( nullptr );
1343
                struct tm tstruct;
7✔
1344
                char buf[80];
7✔
1345
                tstruct = *localtime( &now );
7✔
1346
                strftime( buf, sizeof( buf ), "%Y-%m-%d_%X.csv", &tstruct );
7✔
1347

1348
                // set filename
7✔
1349
                // set filename
1350
                std::string filepathStr;
1351
                if( _logFileName.compare( "use_date" ) == 0 ) {
1352
                    _logFileName = buf;    // set filename to date and time
1353
                    filepathStr  = _logDir + _logFileName + ".csv";
1354
                }
1355
                else {
1356
                    std::filesystem::path filePath( _logDir + _logFileName + ".csv" );
7✔
1357
                    std::string baseFilename( _logDir + _logFileName );
1358
                    filepathStr = _logDir + _logFileName + ".csv";
1359
                    // Check if the file with the original name exists
7✔
1360
                    if( std::filesystem::exists( filePath ) ) {
7✔
1361
                        // Extract the stem and extension
1362
                        std::string stem      = filePath.stem().string();
1363
                        std::string extension = filePath.extension().string();
14✔
1364

7✔
1365
                        // Counter for incrementing the filename
1✔
1366
                        int counter = 1;
1✔
1367

1368
                        // Keep incrementing the counter until a unique filename is found
1369
                        while( std::filesystem::exists( filePath ) ) {
12✔
1370
                            stem = baseFilename + std::to_string( counter );
6✔
1371
                            filePath.replace_filename( stem + extension );
6✔
1372
                            counter++;
1373
                        }
6✔
1374
                    }
1375
                    filepathStr = filePath.string();
×
1376
                }
×
1377
                //}
1378
                // MPI_Bcast( &cfilename, sizeof( cfilename ), MPI_CHAR, 0, MPI_COMM_WORLD );
1379
                // MPI_Barrier( MPI_COMM_WORLD );
×
1380

1381
                // create spdlog file sink
1382
                auto fileSink = std::make_shared<spdlog::sinks::basic_file_sink_mt>( filepathStr );
×
1383
                fileSink->set_level( fileLogLvl );
×
1384
                fileSink->set_pattern( "%Y-%m-%d %H:%M:%S.%f ,%v" );
×
1385
                sinks.push_back( fileSink );
×
1386
            }
1387

1388
            // register all sinks
6✔
1389
            auto tabular_logger = std::make_shared<spdlog::logger>( "tabular", begin( sinks ), end( sinks ) );
1390
            spdlog::register_logger( tabular_logger );
1391
            spdlog::flush_every( std::chrono::seconds( 5 ) );
1392
        }
1393
    }
1394
#ifdef IMPORT_MPI
1395
    MPI_Barrier( MPI_COMM_WORLD );
7✔
1396
#endif
7✔
1397
}
7✔
1398

7✔
1399
// Function to find the key for a given value in a map
1400
template <typename K, typename V> K Config::findKey( const std::map<K, V>& myMap, const V& valueToFind ) {
1401
    for( const auto& pair : myMap ) {
1402
        if( pair.second == valueToFind ) {
7✔
1403
            return pair.first;    // Return the key if the value is found
7✔
1404
        }
7✔
1405
    }
1406
    // If the value is not found, you can return a default value or throw an exception
1407
    throw std::out_of_range( "Value not found in the map" );
80✔
1408
}
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