v0.16.0
Loading...
Searching...
No Matches
JsonConfigManager.cpp
Go to the documentation of this file.
1/** \file JsonConfigManager.cpp
2 * \brief JSON configuration loader for PETSc options and meshsets
3 */
4
5#include <iomanip>
6
7#if BOOST_VERSION < 107500
8#error "JsonConfigManager requires Boost 1.75 or newer"
9#endif
10
11namespace MoFEM {
12
14 static const std::string version =
15 std::to_string(MoFEM_VERSION_MAJOR) + "." +
16 std::to_string(MoFEM_VERSION_MINOR);
17 return version;
18}
19
20namespace {
21
22using JsonArray = boost::json::array;
23using JsonObject = boost::json::object;
24using JsonValue = boost::json::value;
25
26struct ParsedMeshEntry {
27 std::string key;
28 std::string type;
29 std::string fileName;
30};
31
32constexpr int MAX_MESHSET_ATTRIBUTES = 10;
33
34MoFEMErrorCode collectMeshes(const JsonObject &root_object,
35 const std::string &file_name,
36 std::vector<ParsedMeshEntry> &meshes,
37 bool *has_meshsets = nullptr);
38
39std::string toStdString(const boost::json::string &value) {
40 return std::string(value.data(), value.size());
41}
42
43std::string toLowerCopy(std::string value) {
44 std::transform(value.begin(), value.end(), value.begin(),
45 [](unsigned char c) { return std::tolower(c); });
46 return value;
47}
48
49std::string makeContext(const std::string &parent, const std::string &child) {
50 if (parent.empty())
51 return child;
52 return parent + "." + child;
53}
54
55std::string jsonTypeName(const JsonValue &value) {
56 if (value.is_null())
57 return "null";
58 if (value.is_object())
59 return "object";
60 if (value.is_array())
61 return "array";
62 if (value.is_string())
63 return "string";
64 if (value.is_bool())
65 return "boolean";
66 if (value.is_int64() || value.is_uint64())
67 return "integer";
68 if (value.is_double())
69 return "number";
70 return "unknown";
71}
72
73MoFEMErrorCode failConfig(const std::string &file_name,
74 const std::string &context,
75 const std::string &message) {
77 std::ostringstream oss;
78 if (!file_name.empty())
79 oss << file_name;
80 if (!context.empty()) {
81 if (!file_name.empty())
82 oss << ": ";
83 oss << context;
84 }
85 if (!message.empty()) {
86 if (!file_name.empty() || !context.empty())
87 oss << ": ";
88 oss << message;
89 }
90 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "%s", oss.str().c_str());
92}
93
94const JsonObject &requireObject(const JsonValue &value,
95 const std::string &file_name,
96 const std::string &context) {
97 if (!value.is_object()) {
98 CHKERRABORT(PETSC_COMM_SELF,
99 failConfig(file_name, context,
100 "expected object, got " + jsonTypeName(value)));
101 }
102 return value.as_object();
103}
104
105const JsonArray &requireArray(const JsonValue &value, const std::string &file_name,
106 const std::string &context) {
107 if (!value.is_array()) {
108 CHKERRABORT(PETSC_COMM_SELF,
109 failConfig(file_name, context,
110 "expected array, got " + jsonTypeName(value)));
111 }
112 return value.as_array();
113}
114
115std::string requireString(const JsonValue &value, const std::string &file_name,
116 const std::string &context) {
117 if (!value.is_string()) {
118 CHKERRABORT(PETSC_COMM_SELF,
119 failConfig(file_name, context,
120 "expected string, got " + jsonTypeName(value)));
121 }
122 return toStdString(value.as_string());
123}
124
125double requireNumber(const JsonValue &value, const std::string &file_name,
126 const std::string &context) {
127 if (value.is_double())
128 return value.as_double();
129 if (value.is_int64())
130 return static_cast<double>(value.as_int64());
131 if (value.is_uint64())
132 return static_cast<double>(value.as_uint64());
133 CHKERRABORT(PETSC_COMM_SELF,
134 failConfig(file_name, context,
135 "expected number, got " + jsonTypeName(value)));
136 return 0;
137}
138
139int requireInt(const JsonValue &value, const std::string &file_name,
140 const std::string &context) {
141 if (value.is_int64()) {
142 const auto val = value.as_int64();
143 if (val < std::numeric_limits<int>::min() ||
144 val > std::numeric_limits<int>::max()) {
145 CHKERRABORT(
146 PETSC_COMM_SELF,
147 failConfig(file_name, context, "integer value out of int range"));
148 }
149 return static_cast<int>(val);
150 }
151 if (value.is_uint64()) {
152 const auto val = value.as_uint64();
153 if (val > static_cast<std::uint64_t>(std::numeric_limits<int>::max())) {
154 CHKERRABORT(
155 PETSC_COMM_SELF,
156 failConfig(file_name, context, "integer value out of int range"));
157 }
158 return static_cast<int>(val);
159 }
160 CHKERRABORT(PETSC_COMM_SELF,
161 failConfig(file_name, context,
162 "expected integer, got " + jsonTypeName(value)));
163 return 0;
164}
165
166MoFEMErrorCode ensureBlocksetExists(MeshsetsManager &meshsets_manager, int id,
167 const std::string &file_name,
168 const std::string &context) {
170 if (!meshsets_manager.checkMeshset(id, BLOCKSET)) {
171 std::ostringstream oss;
172 oss << "target BLOCKSET id " << id << " does not exist";
173 CHKERR failConfig(file_name, context, oss.str());
174 }
176}
177
178MoFEMErrorCode discardResolvedBlocksetConfiguration(
179 MeshsetsManager &meshsets_manager, const std::string &config_file,
180 const std::set<int> &used_blockset_ids) {
182
183 std::vector<EntityHandle> handled_meshsets;
184 std::vector<int> blockset_ids;
185 std::vector<std::pair<int, std::string>> unused_blocksets;
186
187 for (auto it = meshsets_manager.getBegin(); it != meshsets_manager.getEnd();
188 ++it) {
189 if ((it->getBcType() & CubitBCType(BLOCKSET)).none()) {
190 continue;
191 }
192
193 const auto meshset = it->getMeshset();
194 if (std::find(handled_meshsets.begin(), handled_meshsets.end(), meshset) !=
195 handled_meshsets.end()) {
196 continue;
197 }
198 handled_meshsets.push_back(meshset);
199
200 const auto meshset_id = it->getMeshsetId();
201 blockset_ids.push_back(meshset_id);
202 const bool is_used = used_blockset_ids.count(it->getMeshsetId()) != 0;
203 if (!is_used) {
204 unused_blocksets.emplace_back(meshset_id, it->getName());
205 }
206 }
207
208 for (const auto meshset_id : blockset_ids) {
209 if (used_blockset_ids.count(meshset_id) == 0) {
210 CHKERR meshsets_manager.setName(BLOCKSET, meshset_id, "");
211 }
212 CHKERR meshsets_manager.setAttributes(BLOCKSET, meshset_id, {});
213 }
214
215 if (!unused_blocksets.empty()) {
216 std::ostringstream oss;
217 oss << config_file
218 << ": removing imported names/attributes from unused BLOCKSET meshsets:";
219 for (const auto &entry : unused_blocksets) {
220 oss << " [id=" << entry.first;
221 if (!entry.second.empty()) {
222 oss << ", name='" << entry.second << "'";
223 }
224 oss << "]";
225 }
226 MOFEM_LOG("WORLD", Sev::warning) << oss.str();
227 }
228
230}
231
232MoFEMErrorCode clearPetscParamFileOptionsForJson(const std::string &config_file) {
234
235 char **argv = PETSC_NULLPTR;
236 CHKERR PetscGetArguments(&argv);
237
238 bool has_param_file_arg = false;
239 std::vector<char *> filtered_argv;
240 for (PetscInt i = 0; argv && argv[i]; ++i) {
241 if (std::strcmp(argv[i], "-param_file") == 0) {
242 has_param_file_arg = true;
243 if (argv[i + 1])
244 ++i;
245 continue;
246 }
247 if (std::strcmp(argv[i], "-json_config") == 0) {
248 if (argv[i + 1])
249 ++i;
250 continue;
251 }
252 filtered_argv.push_back(argv[i]);
253 }
254
255 const auto &petsc_options_file = Core::getPetscOptionsFile();
256 if (has_param_file_arg) {
257 MOFEM_LOG("WORLD", Sev::warning)
258 << config_file
259 << ": JSON config active, ignoring PETSc options loaded from -param_file";
260 } else if (!petsc_options_file.empty()) {
261 MOFEM_LOG("WORLD", Sev::warning)
262 << config_file << ": JSON config active, ignoring PETSc options loaded "
263 << "from default PETSc options file '" << petsc_options_file << "'";
264 }
265
266 CHKERR PetscOptionsClear(PETSC_NULLPTR);
267 CHKERR PetscOptionsInsertArgs(PETSC_NULLPTR,
268 static_cast<int>(filtered_argv.size()),
269 filtered_argv.empty() ? PETSC_NULLPTR
270 : filtered_argv.data());
272}
273
274std::string petscScalarToString(const JsonValue &value,
275 const std::string &file_name,
276 const std::string &context) {
277 if (value.is_string())
278 return toStdString(value.as_string());
279 if (value.is_bool())
280 return value.as_bool() ? "true" : "false";
281 if (value.is_int64())
282 return boost::lexical_cast<std::string>(value.as_int64());
283 if (value.is_uint64())
284 return boost::lexical_cast<std::string>(value.as_uint64());
285 if (value.is_double()) {
286 std::ostringstream oss;
287 oss << std::setprecision(std::numeric_limits<double>::max_digits10)
288 << value.as_double();
289 return oss.str();
290 }
291 CHKERRABORT(PETSC_COMM_SELF,
292 failConfig(file_name, context,
293 "PETSc option value must be scalar"));
294 return "";
295}
296
297MoFEMErrorCode setPetscOptionIfUnset(const std::string &option_name,
298 const char *option_value) {
300 PetscBool has_option = PETSC_FALSE;
301 CHKERR PetscOptionsHasName(PETSC_NULLPTR, PETSC_NULLPTR, option_name.c_str(),
302 &has_option);
303 if (!has_option)
304 CHKERR PetscOptionsSetValue(PETSC_NULLPTR, option_name.c_str(),
305 option_value);
307}
308
309MoFEMErrorCode setPetscOptionIfUnset(const std::string &option_name,
310 const std::string &option_value) {
312 CHKERR setPetscOptionIfUnset(option_name, option_value.c_str());
314}
315
316MoFEMErrorCode flattenPetscObject(const JsonObject &obj,
317 const std::string &prefix,
318 const std::string &file_name,
319 const std::string &context,
320 std::map<std::string, std::string>
321 &seen_option_contexts) {
323 for (const auto &item : obj) {
324 const auto key = toStdString(item.key());
325 const auto item_context = makeContext(context, key);
326 const auto option_name =
327 prefix.empty() ? "-" + key : prefix + "_" + key;
328
329 if (item.value().is_object()) {
330 CHKERR flattenPetscObject(item.value().as_object(), option_name, file_name,
331 item_context, seen_option_contexts);
332 continue;
333 }
334
335 if (item.value().is_array() || item.value().is_null()) {
336 CHKERR failConfig(file_name, item_context,
337 "PETSc option value must be scalar or object");
338 }
339
340 if (const auto seen_it = seen_option_contexts.find(option_name);
341 seen_it != seen_option_contexts.end()) {
342 MOFEM_LOG("WORLD", Sev::warning)
343 << file_name << ": duplicate PETSc option '" << option_name
344 << "' in JSON config; keeping first value from "
345 << seen_it->second << " and ignoring duplicate from " << item_context;
346 continue;
347 }
348
349 seen_option_contexts.emplace(option_name, item_context);
350
351 if (item.value().is_bool()) {
352 if (item.value().as_bool()) {
353 CHKERR setPetscOptionIfUnset(option_name, PETSC_NULLPTR);
354 } else {
355 CHKERR setPetscOptionIfUnset(option_name, "false");
356 }
357 continue;
358 }
359
360 CHKERR setPetscOptionIfUnset(
361 option_name, petscScalarToString(item.value(), file_name, item_context));
362 }
364}
365
366// Per-executable program selection for shared JSON config files.
368
369// Mesh-type parsing and validation are split out so new mesh sources can be
370// added without growing this core manager file.
372
373// JSON meshsets are generic BLOCKSET assignments. Type-specific Cubit
374// material/BC data structures stay outside the JSON config layer.
376
377} // namespace
378
380JsonConfigManager::query_interface(boost::typeindex::type_index type_index,
381 UnknownInterface **iface) const {
382 *iface = const_cast<JsonConfigManager *>(this);
383 return 0;
384}
385
387 : cOre(const_cast<Core &>(core)) {}
388
392
393MoFEMErrorCode JsonConfigManager::loadFromFile(const std::string &file_name) {
395
396 std::ifstream input(file_name.c_str(), std::ifstream::in);
397 if (!input.good()) {
398 CHKERR failConfig(file_name, "", "unable to open JSON config file");
399 }
400
401 std::ostringstream buffer;
402 buffer << input.rdbuf();
403
404 boost::system::error_code ec;
405 auto root = boost::json::parse(buffer.str(), ec);
406 if (ec) {
407 CHKERR failConfig(file_name, "", "invalid JSON: " + ec.message());
408 }
409
410 const auto &root_object = requireObject(root, file_name, "root");
411 boost::json::value selected_config;
412 CHKERR selectProgramConfig(root_object, file_name, selected_config);
413 const auto &config_object = requireObject(selected_config, file_name, "root");
414
415 bool has_version = false;
416 for (const auto &item : config_object) {
417 const auto key = toStdString(item.key());
418 if (key == "$schema")
419 continue;
420 if (key == "version") {
421 has_version = true;
422 const auto version =
423 requireString(item.value(), file_name, makeContext("root", key));
424 if (version != supportedVersion()) {
425 CHKERR failConfig(file_name, makeContext("root", key),
426 "unsupported config version '" + version +
427 "', supported version is '" + supportedVersion() +
428 "'");
429 }
430 continue;
431 }
432 if (key == "petsc") {
433 requireObject(item.value(), file_name, makeContext("root", key));
434 continue;
435 }
436 if (key == "mofem") {
437 requireObject(item.value(), file_name, makeContext("root", key));
438 continue;
439 }
440 if (key == "meshes" || key == "input_files") {
441 requireArray(item.value(), file_name, makeContext("root", key));
442 continue;
443 }
444 if (key == "file_name") {
445 CHKERR failConfig(
446 file_name, makeContext("root", key),
447 "legacy root-level file_name is not supported; use "
448 "root.input_files[0].file_name or root.meshes[0].file_name");
449 }
450 if (key == "meshsets") {
451 CHKERR failConfig(
452 file_name, makeContext("root", key),
453 "legacy root-level meshsets is not supported; use "
454 "root.input_files[i].meshsets or root.meshes[i].meshsets");
455 }
456 CHKERR failConfig(file_name, makeContext("root", key),
457 "unknown top-level key");
458 }
459 if (!has_version) {
460 CHKERR failConfig(file_name, "root.version",
461 "missing required version field");
462 }
463 hasMeshsets = false;
464
465 std::vector<ParsedMeshEntry> new_meshes;
466 bool config_has_meshsets = false;
467 CHKERR collectMeshes(config_object, file_name, new_meshes,
468 &config_has_meshsets);
469
470 configRoot = std::move(selected_config);
471 configFileName = file_name;
472 configLoaded = true;
473 moabMeshesByKey.clear();
474 pythonScriptsByKey.clear();
475 for (const auto &entry : new_meshes) {
476 if (entry.type == MOAB_MESH_TYPE && !entry.key.empty()) {
477 moabMeshesByKey[entry.key] = entry.fileName;
478 }
479 if (isPythonScriptMeshType(entry.type)) {
480 pythonScriptsByKey[entry.key] = entry.fileName;
481 }
482 }
483 hasMeshsets = config_has_meshsets;
484 meshsetsApplied = false;
486
488}
489
492 if (configLoaded) {
493 const auto &root_object = configRoot.as_object();
494 std::map<std::string, std::string> seen_option_contexts;
495 const char *section_key = nullptr;
496 if (const auto *meshes_array =
497 getMeshesArray(root_object, configFileName, &section_key);
498 meshes_array && !meshes_array->empty()) {
499 const auto primary_mesh_context = meshContext(0, section_key);
500 const auto &primary_mesh = requireObject((*meshes_array)[0], configFileName,
501 primary_mesh_context);
502 CHKERR setPetscOptionIfUnset(
503 "-file_name",
504 requireString(primary_mesh.at("file_name"), configFileName,
505 makeContext(primary_mesh_context, "file_name")));
506 }
507
508 if (const auto petsc_it = root_object.find("petsc");
509 petsc_it != root_object.end()) {
510 CHKERR flattenPetscObject(petsc_it->value().as_object(), "",
511 configFileName, "petsc",
512 seen_option_contexts);
513 }
514 if (const auto mofem_it = root_object.find("mofem");
515 mofem_it != root_object.end()) {
516 CHKERR flattenPetscObject(mofem_it->value().as_object(), "",
517 configFileName, "mofem",
518 seen_option_contexts);
519 }
520 }
522}
523
527 auto &meshsets_manager = cOre.getInterface<MeshsetsManager &>();
529 if (const auto *primary_meshsets =
531 primary_meshsets && !primary_meshsets->empty()) {
532 const char *section_key =
534 const auto primary_mesh_context = meshContext(0, section_key);
535 std::vector<ParsedMeshsetEntry> parsed_primary_meshsets;
536 std::set<int> used_blockset_ids;
537 CHKERR parseMeshsets(*primary_meshsets, primary_mesh_context, configFileName,
538 &meshsets_manager, parsed_primary_meshsets);
539 CHKERR cacheResolvedBlocksetParams(parsed_primary_meshsets, configFileName,
541 used_blockset_ids);
542
543 // JSON stays authoritative for block attributes. Imported blockset names
544 // are kept only for meshsets that JSON actually refers to.
545 CHKERR discardResolvedBlocksetConfiguration(
546 meshsets_manager, configFileName, used_blockset_ids);
547 CHKERR applyParsedMeshsets(meshsets_manager, parsed_primary_meshsets,
549 CHKERR cacheAppliedBlocksetParams(parsed_primary_meshsets, configFileName,
551 }
552 const char *section_key = nullptr;
553 if (const auto *meshes_array =
554 getMeshesArray(configRoot.as_object(), configFileName, &section_key);
555 meshes_array) {
556 for (size_t mesh_index = 1; mesh_index != meshes_array->size();
557 ++mesh_index) {
558 if (const auto *meshsets =
560 mesh_index);
561 meshsets && !meshsets->empty()) {
562 CHKERR validateMeshsets(*meshsets, meshContext(mesh_index, section_key),
564 }
565 }
566 }
567 meshsetsApplied = true;
568 }
570}
571
572std::string
574 if (const auto it = pythonScriptsByKey.find(key);
575 it != pythonScriptsByKey.end()) {
576 return it->second;
577 }
578 return "";
579}
580
581std::string JsonConfigManager::getMoabMeshByKey(const std::string &key) const {
582 if (const auto it = moabMeshesByKey.find(key); it != moabMeshesByKey.end()) {
583 return it->second;
584 }
585 return "";
586}
587
588std::map<std::string, double>
589JsonConfigManager::getParamsFromBlockset(const std::string &type_name,
590 int meshset_id) const {
591 const auto it =
592 primaryMeshsetParamsByKey.find({toLowerCopy(type_name), meshset_id});
593 if (it != primaryMeshsetParamsByKey.end()) {
594 return it->second;
595 }
596 return {};
597}
598
601 if (!configLoaded) {
602 char json_file_name[PETSC_MAX_PATH_LEN] = "";
603 PetscBool has_json = PETSC_FALSE;
604 CHKERR PetscOptionsGetString(PETSC_NULLPTR, PETSC_NULLPTR, "-json_config",
605 json_file_name, sizeof(json_file_name),
606 &has_json);
607 if (has_json) {
608 // IMPORTANT !!!
609 // Clear any PETSc options that might have been set by param_file.petsc
610 CHKERR clearPetscParamFileOptionsForJson(json_file_name);
611 CHKERR loadFromFile(json_file_name);
612
613 if (hasMeshsets) {
614 char meshsets_cfg_file[PETSC_MAX_PATH_LEN] = "";
615 PetscBool has_meshsets_cfg = PETSC_FALSE;
616 CHKERR PetscOptionsGetString(PETSC_NULLPTR, PETSC_NULLPTR,
617 "-meshsets_config", meshsets_cfg_file,
618 sizeof(meshsets_cfg_file),
619 &has_meshsets_cfg);
620 if (has_meshsets_cfg) {
621 CHKERR failConfig(
622 configFileName, "meshsets",
623 "JSON meshsets cannot be used together with -meshsets_config");
624 }
625 }
626
628 // Consume and apply any log_* options injected from JSON after PETSc
629 // initialization so they do not remain as "unused database options".
631 }
632 }
634}
635
636} // namespace MoFEM
std::string meshContext(const size_t mesh_index, const char *section_key=MESHES_KEY)
const JsonArray * getMeshsetsArray(const JsonObject &root_object, const std::string &file_name, const size_t mesh_index)
MoFEMErrorCode collectMeshes(const JsonObject &root_object, const std::string &file_name, std::vector< ParsedMeshEntry > &meshes, bool *has_meshsets)
bool isPythonScriptMeshType(const std::string &type)
const char * getMeshSectionKey(const JsonObject &root_object, const std::string &file_name)
const JsonArray * getMeshesArray(const JsonObject &root_object, const std::string &file_name, const char **section_key=nullptr)
constexpr auto MOAB_MESH_TYPE
MoFEMErrorCode validateMeshsets(const JsonArray &meshsets, const std::string &mesh_context, const std::string &file_name)
MoFEMErrorCode applyParsedMeshsets(MeshsetsManager &meshsets_manager, std::vector< ParsedMeshsetEntry > &parsed_meshsets, const std::string &file_name)
MoFEMErrorCode cacheResolvedBlocksetParams(const std::vector< ParsedMeshsetEntry > &parsed_meshsets, const std::string &file_name, BlocksetParamsByKey &params_by_key, std::set< int > &used_blockset_ids)
MoFEMErrorCode parseMeshsets(const JsonArray &meshsets, const std::string &mesh_context, const std::string &file_name, MeshsetsManager *meshsets_manager_ptr, std::vector< ParsedMeshsetEntry > &parsed_meshsets)
MoFEMErrorCode cacheAppliedBlocksetParams(const std::vector< ParsedMeshsetEntry > &parsed_meshsets, const std::string &file_name, BlocksetParamsByKey &params_by_key)
MoFEMErrorCode selectProgramConfig(const JsonObject &root_object, const std::string &file_name, boost::json::value &selected_config)
std::string type
std::string key
std::string fileName
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ BLOCKSET
@ MOFEM_DATA_INCONSISTENCY
Definition definitions.h:31
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
#define MoFEMFunctionBeginHot
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#define MOFEM_LOG(channel, severity)
Log.
FTensor::Index< 'i', SPACE_DIM > i
const double c
speed of light (cm/ns)
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
std::bitset< 32 > CubitBCType
Definition Types.hpp:52
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
PetscErrorCode PetscOptionsGetString(PetscOptions *, const char pre[], const char name[], char str[], size_t size, PetscBool *set)
Core (interface) class.
Definition Core.hpp:83
static const std::string & getPetscOptionsFile()
Definition Core.cpp:121
static const std::string & supportedVersion()
std::string getPythonScriptByKey(const std::string &key) const
std::map< std::string, std::string > moabMeshesByKey
std::string getMoabMeshByKey(const std::string &key) const
std::map< std::string, double > getParamsFromBlockset(const std::string &type_name, int meshset_id) const
MoFEMErrorCode query_interface(boost::typeindex::type_index type_index, UnknownInterface **iface) const
JsonConfigManager(const MoFEM::Core &core)
std::map< std::string, std::string > pythonScriptsByKey
MoFEMErrorCode loadFromFile(const std::string &file_name)
MoFEMErrorCode getSubInterfaceOptions()
std::map< MeshsetKey, MeshsetParams > primaryMeshsetParamsByKey
boost::json::value configRoot
MoFEMErrorCode loadFromCommandLine()
static MoFEMErrorCode getOptions()
Get logger option.
Interface for managing meshsets containing materials and boundary conditions.
base class for all interface classes
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.