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

CSMMLab / KiT-RT / #95

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

push

travis-ci

web-flow
Release 2025 (#44)

* New neural models (#30)

* extend kitrt script

* added new neural models

* extend to m3 models

* added M3_2D models

* added M2 and M4 models

* configure ml optimizer for high order models

* added configuration for high order models

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

* started rotational symmetric postprocessing

* added rotational invariance postprocessing for m2 and m1 models

* fix post merge bugs

* created hohlraum mesh

* add hohlraum tes case

* add hohlraum test case

* add hohlraum cfg filees

* fixed hohlraum testcase

* add hohlraum cfg files

* changed hohlraum cfg

* changed hohlraum testcase to isotropic inflow source boundary condition

* added ghost cell bonudary for hohlraum testcase

* update readme and linesource mesh creator

* added proper scaling for linesource reference solution

* regularized newton debugging

* Data generator with reduced objective functional (#33)

* added reduced optimizer for sampling

* remove old debugging comments

* mesh acceleration (#38)

* added new ansatz (#36)

* added new ansatz

* debug new ansatz

* branch should be abandoned here

* debug new ansatz

* fix scaling error new ansatz

* fix config errors

* temporarily fixed dynamic ansatz rotation bug

* fix inheritance error for new ansatz

* mesh acceleration

* add structured hohlraum

* Mesh acc (#41)

* mesh acceleration

* added floor value for starmap moment methods

* enable accelleration

* delete minimum value starmap

* Update README.md

* Spherical harmonics nn (#40)

* added new ansatz

* debug new ansatz

* branch should be abandoned here

* debug new ansatz

* fix scaling error new ansatz

* fix config errors

* temporarily fixed dynamic ansatz rotation bug

* fix inheritance error for new ansatz

* mesh acceleration

* add structured hohlraum

* added sph... (continued)

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

131 existing lines in 8 files now uncovered.

4422 of 9478 relevant lines covered (46.66%)

57163.05 hits per line

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

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
UNCOV
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✔
UNCOV
570

×
UNCOV
571
        if( std::find( supportedDims.begin(), supportedDims.end(), _dim ) == supportedDims.end() ) {
×
UNCOV
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✔
UNCOV
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 )
NEW
649
                        supportedGroups = { MINIMAL, ANALYTIC };
×
NEW
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✔
NEW
658
                            CURRENT_FUNCTION );
×
UNCOV
659
                    }
×
UNCOV
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✔
NEW
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✔
NEW
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✔
UNCOV
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

UNCOV
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✔
UNCOV
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✔
UNCOV
732
    }
×
733

734
    // Screen Output Postprocessing
735
    {
736
        // Check for doublicates in SCALAR OUTPUT
6✔
UNCOV
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✔
UNCOV
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✔
UNCOV
751
                                      CURRENT_FUNCTION );
×
UNCOV
752
            }
×
UNCOV
753
        }
×
754
        // Check if the choice of screen output is compatible to the problem
NEW
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
                                     MASS,
×
764
                                     RMS_FLUX,
765
                                     VTK_OUTPUT,
766
                                     CSV_OUTPUT,
4✔
NEW
767
                                     CUR_OUTFLOW,
×
768
                                     TOTAL_OUTFLOW,
769
                                     CUR_OUTFLOW_P1,
770
                                     TOTAL_OUTFLOW_P1,
771
                                     CUR_OUTFLOW_P2,
4✔
NEW
772
                                     TOTAL_OUTFLOW_P2,
×
NEW
773
                                     MAX_OUTFLOW,
×
NEW
774
                                     CUR_PARTICLE_ABSORPTION,
×
775
                                     TOTAL_PARTICLE_ABSORPTION,
NEW
776
                                     MAX_PARTICLE_ABSORPTION };
×
777
                    it           = std::find( legalOutputs.begin(), legalOutputs.end(), _screenOutput[idx_screenOutput] );
778
                    if( it == legalOutputs.end() ) {
NEW
779
                        std::string foundKey = findKey( ScalarOutput_Map, _screenOutput[idx_screenOutput] );
×
780
                        ErrorMessages::Error(
8✔
781
                            "Illegal output field <" + foundKey +
8✔
782
                                "> for option SCREEN_OUTPUT for this test case.\n"
8✔
783
                                "Supported fields are: ITER, MASS, RMS_FLUX, VTK_OUTPUT, CSV_OUTPUT, FINAL_TIME_OUTFLOW, TOTAL_OUTFLOW, MAX_OUTFLOW, "
NEW
784
                                "FINAL_TIME_PARTICLE_ABSORPTION, TOTAL_PARTICLE_ABSORPTION, MAX_PARTICLE_ABSORPTION\n"
×
785
                                "Please check your .cfg file.",
786
                            CURRENT_FUNCTION );
787
                    }
788
                    break;
8✔
NEW
789
                case PROBLEM_QuarterHohlraum:
×
NEW
790
                case PROBLEM_SymmetricHohlraum:
×
NEW
791
                    legalOutputs = {
×
792
                        ITER,
NEW
793
                        WALL_TIME,
×
794
                        MASS,
795
                        RMS_FLUX,
796
                        VTK_OUTPUT,
NEW
797
                        CSV_OUTPUT,
×
NEW
798
                        CUR_OUTFLOW,
×
NEW
799
                        TOTAL_OUTFLOW,
×
800
                        MAX_OUTFLOW,
801
                        TOTAL_PARTICLE_ABSORPTION_CENTER,
802
                        TOTAL_PARTICLE_ABSORPTION_VERTICAL,
803
                        TOTAL_PARTICLE_ABSORPTION_HORIZONTAL,
804
                        TOTAL_PARTICLE_ABSORPTION,
86✔
805
                        PROBE_MOMENT_TIME_TRACE,
64✔
806
                        VAR_ABSORPTION_GREEN,
64✔
807
                    };
808

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

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

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

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

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

860
            it = find( _screenOutput.begin(), _screenOutput.end(), PROBE_MOMENT_TIME_TRACE );
861

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

871
            it = find( _screenOutput.begin(), _screenOutput.end(), PROBE_MOMENT_TIME_TRACE );
872

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

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

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

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

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

958
                    it = std::find( legalOutputs.begin(), legalOutputs.end(), _historyOutput[idx_historyOutput] );
959

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

30✔
NEW
973
                default:
×
974
                    legalOutputs = { ITER, WALL_TIME, MASS, RMS_FLUX, VTK_OUTPUT, CSV_OUTPUT, CUR_OUTFLOW, TOTAL_OUTFLOW, MAX_OUTFLOW };
975
                    it           = std::find( legalOutputs.begin(), legalOutputs.end(), _historyOutput[idx_historyOutput] );
976

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

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

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

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

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

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

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

86✔
1068
    // Optimizer postprocessing
6✔
1069
    {
6✔
1070
        if( _regularizerGamma <= 0.0 ) {
6✔
1071
            ErrorMessages::Error( "REGULARIZER_GAMMA must be positive.", CURRENT_FUNCTION );
6✔
1072
        }
1073

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

×
UNCOV
1089
void Config::SetOutput() {
×
UNCOV
1090
    // Set Output for settings, i.e. feedback on what has been chosen
×
1091
}
1092

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

×
UNCOV
1107
    // look for line composed on only delimiters (usually whitespace)
×
UNCOV
1108
    pos = str.find_first_not_of( delimiters );
×
UNCOV
1109
    if( pos == string::npos ) {
×
1110
        return false;
1111
    }
UNCOV
1112

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

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

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

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

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

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

1219
    return true;
1,020✔
1220
}
1221

1222
void Config::InitLogger() {
1,020✔
1223
    int rank = 0;
1,020✔
1224
#ifdef IMPORT_MPI
1,020✔
1225
    MPI_Comm_rank( MPI_COMM_WORLD, &rank );    // Initialize MPI
2,102✔
1226
#endif
1227

1,082✔
1228
    if( rank == 0 ) {
1229

1,082✔
1230
        // Declare Logger
1231
        spdlog::level::level_enum terminalLogLvl;
1,082✔
1232
        spdlog::level::level_enum fileLogLvl;
1233

1,020✔
NEW
1234
        // Choose Logger
×
UNCOV
1235
#ifdef BUILD_TESTING
×
NEW
1236
        terminalLogLvl = spdlog::level::err;
×
NEW
1237
        fileLogLvl     = spdlog::level::info;
×
1238
#elif NDEBUG
1239
        terminalLogLvl = spdlog::level::info;
1240
        fileLogLvl     = spdlog::level::info;
1241
#else
1,020✔
1242
        terminalLogLvl = spdlog::level::debug;
1,020✔
1243
        fileLogLvl     = spdlog::level::debug;
2,102✔
1244
#endif
1,082✔
UNCOV
1245

×
NEW
1246
        // create log dir if not existent
×
1247
        if( !std::filesystem::exists( _logDir ) ) {
1248
            std::filesystem::create_directory( _logDir );
1249
        }
1,082✔
1250

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

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

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

1,082✔
1291
                        // Counter for incrementing the filename
1292
                        int counter = 1;
1,082✔
1293

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

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

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

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

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

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

10✔
1354
                        // Counter for incrementing the filename
2✔
1355
                        int counter = 1;
2✔
1356

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

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

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

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