10 #include <boost/algorithm/string/predicate.hpp>
20 bool const use_thermal_physics = database.get<
bool>(
"physics.thermal");
22 bool const use_mechanical_physics = database.get<
bool>(
"physics.mechanical");
23 ASSERT_THROW(use_thermal_physics || use_mechanical_physics,
24 "Both thermal and mechanical physics are disabled");
32 std::string delimiter =
",";
33 auto parse_boundary_type = [&](std::string
const &boundary,
35 bool &thermal_bc,
bool &mechanical_bc)
37 if (boundary ==
"adiabatic")
41 "adiabatic condition cannot be combined with another type "
42 "of thermal boundary condition.");
48 if (boundary ==
"radiative")
51 "adiabatic condition cannot be combined with another type "
52 "of thermal boundary condition.");
57 else if (boundary ==
"convective")
60 "adiabatic condition cannot be combined with another type "
61 "of thermal boundary condition.");
66 else if (boundary ==
"clamped")
70 "Mechanical boundary conditions cannot be combined together.");
74 else if (boundary ==
"traction_free")
78 "Mechanical boundary conditions cannot be combined together.");
88 auto const boundary_database = database.get_child(
"boundary");
89 bool clamped_boundary =
false;
90 for (
auto const &child_pair : boundary_database)
93 bool thermal_bc =
false;
94 bool mechanical_bc =
false;
96 std::string boundary_type_str =
"invalid";
97 if (child_pair.first ==
"type")
99 boundary_type_str = child_pair.second.data();
104 boundary_database.get<std::string>(child_pair.first +
".type");
107 while ((pos_str = boundary_type_str.find(delimiter)) != std::string::npos)
109 std::string boundary = boundary_type_str.substr(0, pos_str);
110 parse_boundary_type(boundary, line_boundary_type, thermal_bc,
112 boundary_type_str.erase(0, pos_str + delimiter.length());
114 parse_boundary_type(boundary_type_str, line_boundary_type, thermal_bc,
118 clamped_boundary =
true;
120 if (use_thermal_physics)
122 ASSERT_THROW(thermal_bc,
"Missing thermal boundary condition.");
124 if (use_mechanical_physics)
126 ASSERT_THROW(mechanical_bc,
"Missing mechanical boundary condition.");
129 if (use_mechanical_physics)
132 "At least one boundary needs to be clamped!");
136 if (use_thermal_physics)
139 unsigned int const fe_degree =
140 database.get<
unsigned int>(
"discretization.thermal.fe_degree");
142 "fe_degree should be between 1 and 5.");
145 boost::optional<std::string> quadrature_type_optional =
146 database.get_optional<std::string>(
"discretization.thermal.quadrature");
148 if (quadrature_type_optional)
150 std::string quadrature_type = quadrature_type_optional.get();
151 if (!((boost::iequals(quadrature_type,
"gauss") ||
152 (boost::iequals(quadrature_type,
"lobatto")))))
160 unsigned int dim = database.get<
unsigned int>(
"geometry.dim");
161 ASSERT_THROW((dim == 2) || (dim == 3),
"dim should be 2 or 3");
163 bool use_powder = database.get(
"geometry.use_powder",
false);
167 double powder_layer = database.get<
double>(
"geometry.powder_layer");
168 ASSERT_THROW(powder_layer >= 0.0,
"powder_layer must be non-negative.");
171 bool material_deposition =
172 database.get(
"geometry.material_deposition",
false);
174 if (material_deposition)
177 database.get<std::string>(
"geometry.material_deposition_method");
180 (method ==
"file" || method ==
"scan_paths"),
181 "Method type for material deposition, '" + method +
182 "', is not recognized. Valid options are: 'file' and 'scan_paths'");
184 if (method ==
"file")
186 ASSERT_THROW(database.count(
"geometry.material_deposition_file") != 0,
187 "If the material deposition method is 'file', "
188 "'material_deposition_file' must be given.");
192 ASSERT_THROW(database.get_child(
"geometry").count(
"deposition_length") !=
194 "If the material deposition method is 'scan_path', "
195 "'deposition_length' must be given.");
196 ASSERT_THROW(database.get_child(
"geometry").count(
"deposition_height") !=
198 "If the material deposition method is 'scan_path', "
199 "'deposition_height' must be given.");
202 ASSERT_THROW(database.get_child(
"geometry").count(
"deposition_width") !=
204 "If the material deposition method is 'scan_path', "
205 "'deposition_width' must be given.");
208 database.get_child(
"geometry").count(
"deposition_lead_time") != 0,
209 "If the material deposition method is 'scan_path', "
210 "'deposition_lead_time' must be given.");
214 bool import_mesh = database.get<
bool>(
"geometry.import_mesh");
217 ASSERT_THROW(database.get_child(
"geometry").count(
"mesh_file") != 0,
218 "If the the mesh is imported, 'mesh_file' must be given.");
219 ASSERT_THROW(database.get_child(
"geometry").count(
"mesh_format") != 0,
220 "If the the mesh is imported, 'mesh_format' must be given.");
224 ASSERT_THROW(database.get_child(
"geometry").count(
"length") != 0,
225 "If the the mesh is not imported, 'length' must be given.");
226 ASSERT_THROW(database.get_child(
"geometry").count(
"height") != 0,
227 "If the the mesh is not imported, 'height' must be given.");
230 ASSERT_THROW(database.get_child(
"geometry").count(
"width") != 0,
231 "If the the mesh is not imported, 'width' must be given.");
236 unsigned int n_materials =
237 database.get<
unsigned int>(
"materials.n_materials");
239 std::string property_format =
240 database.get<std::string>(
"materials.property_format");
242 (property_format ==
"polynomial"),
243 "property_format should be table or polynomial.");
245 for (dealii::types::material_id
id = 0;
id < n_materials; ++id)
248 .count(
"material_" + std::to_string(
id)) != 0,
249 "Number of material subtrees does not match the set number of "
252 bool has_a_valid_state =
false;
253 for (
unsigned int state_index = 0;
256 if (database.get_child(
"materials")
257 .get_child(
"material_" + std::to_string(
id))
260 has_a_valid_state =
true;
263 .get_child(
"material_" + std::to_string(
id))
265 .count(
"density") != 0,
266 "Each state needs a user-specified density.");
268 .get_child(
"material_" + std::to_string(
id))
270 .count(
"specific_heat") != 0,
271 "Each state needs a user-specified specific heat.");
273 .get_child(
"material_" + std::to_string(
id))
275 .count(
"thermal_conductivity_x") != 0,
276 "Each state needs a user-specified specific thermal "
279 .get_child(
"material_" + std::to_string(
id))
281 .count(
"thermal_conductivity_z") != 0,
282 "Each state needs a user-specified specific thermal "
288 .get_child(
"material_" + std::to_string(
id))
290 .count(
"thermal_conductivity_y") != 0,
291 "Each state needs a user-specified specific thermal "
298 .get_child(
"material_" + std::to_string(
id))
300 .count(
"convection_heat_transfer_coef") != 0,
301 "Convective BCs require a user-specified convection "
302 "heat transfer coefficient.");
308 .get_child(
"material_" + std::to_string(
id))
310 .count(
"emissivity") != 0,
311 "Radiative BCs require a user-specified emissivity.");
321 has_a_valid_state ==
true,
322 "Material without any valid state (solid, powder, or liquid).");
327 database.get_child(
"materials")
328 .get_child(
"material_" + std::to_string(
id))
329 .count(
"convection_temperature_infty") != 0,
330 "Convective BCs require setting 'convection_temperature_infty'.");
336 database.get_child(
"materials")
337 .get_child(
"material_" + std::to_string(
id))
338 .count(
"radiation_temperature_infty") != 0,
339 "Radiative BCs require setting 'radiation_temperature_infty'.");
344 boost::optional<std::string> memory_space_optional =
345 database.get_optional<std::string>(
"memory_space");
346 if (memory_space_optional)
348 std::string memory_space = memory_space_optional.get();
350 (memory_space ==
"device" || memory_space ==
"host"),
351 "Method type for memory space, '" + memory_space +
352 "', is not recognized. Valid options are: 'host' and 'device'");
356 ASSERT_THROW(database.get_child(
"post_processor").count(
"filename_prefix") !=
358 "The filename prefix for the postprocessor must be specified.");
362 "A refinement section of the input file must exist.");
365 unsigned int n_beams = database.get<
unsigned int>(
"sources.n_beams");
366 for (
unsigned int beam_index = 0; beam_index < n_beams; ++beam_index)
368 std::string beam_type = database.get<std::string>(
369 "sources.beam_" + std::to_string(beam_index) +
".type");
371 boost::iequals(beam_type,
"electron_beam") ||
372 boost::iequals(beam_type,
"cube"),
373 "Beam type, '" + beam_type +
374 "', is not recognized. Valid options are: 'goldak', "
375 "'electron_beam', and 'cube'.");
377 .get_child(
"beam_" + std::to_string(beam_index))
378 .count(
"scan_path_file") != 0,
379 "A scan path file for each beam must be given.");
381 std::string file_format =
382 database.get<std::string>(
"sources.beam_" + std::to_string(beam_index) +
383 ".scan_path_file_format");
385 boost::iequals(file_format,
"event_series"),
386 "Scan path file format, '" + file_format +
387 "', is not recognized. Valid options are: 'segment' and "
390 std::to_string(beam_index) +
".depth") >=
392 "Heat source depth must be non-negative.");
394 double absorption_efficiency =
395 database.get<
double>(
"sources.beam_" + std::to_string(beam_index) +
396 ".absorption_efficiency");
397 ASSERT_THROW(absorption_efficiency >= 0.0 && absorption_efficiency <= 1.0,
398 "Heat source absorption efficiency must be between 0 and 1.");
402 std::string time_stepping_method =
403 database.get<std::string>(
"time_stepping.method");
404 ASSERT_THROW(boost::iequals(time_stepping_method,
"forward_euler") ||
405 boost::iequals(time_stepping_method,
"rk_third_order") ||
406 boost::iequals(time_stepping_method,
"rk_fourth_order"),
407 "Time stepping method, '" + time_stepping_method +
408 "', is not recognized. Valid options are: 'forward_euler', "
409 "'rk_third_order', and 'rk_fourth_order'.");
411 if (database.get(
"time.scan_path_for_duration",
false))
413 ASSERT_THROW(database.get<
double>(
"time_stepping.duration") >= 0.0,
414 "Time stepping duration must be non-negative.");
417 ASSERT_THROW(database.get<
double>(
"time_stepping.time_step") >= 0.0,
418 "Time step must be non-negative.");
424 boost::optional<boost::property_tree::ptree &> experiment_optional_database =
425 database.get_child_optional(
"experiment");
426 if (experiment_optional_database)
428 bool experiment_active =
429 database.get(
"experiment.read_in_experimental_data",
false);
430 if (experiment_active)
432 ASSERT_THROW(database.get_child(
"experiment").count(
"file") != 0,
433 "If reading experimental data, a file must be given.");
435 ASSERT_THROW(database.get_child(
"experiment").count(
"last_frame") != 0,
436 "If reading experimental data, a last frame index "
439 std::string experiment_format =
440 database.get<std::string>(
"experiment.format");
441 ASSERT_THROW(boost::iequals(experiment_format,
"point_cloud") ||
442 boost::iequals(experiment_format,
"ray"),
443 "Experiment format must be 'point_cloud' or 'ray'.");
445 unsigned int first_frame_index =
446 database.get<
unsigned int>(
"experiment.first_frame", 0);
447 unsigned int last_frame_index =
448 database.get<
unsigned int>(
"experiment.last_frame");
450 "When reading experimental data, the last frame index "
451 "cannot be lower than the first frame index.");
453 unsigned int first_camera_id =
454 database.get<
unsigned int>(
"experiment.first_camera_id");
455 unsigned int last_camera_id =
456 database.get<
unsigned int>(
"experiment.last_camera_id");
458 "When reading experimental data, the last camera id cannot "
459 "be lower than the first camera id.");
462 database.get_child(
"experiment").count(
"log_filename") != 0,
463 "If reading experimental data, a log filename must be given.");
471 boost::optional<double> convergence_tolerance =
472 database.get_optional<
double>(
"data_assimilation.convergence_tolerance");
473 if (convergence_tolerance)
476 convergence_tolerance.get() >= 0.0,
477 "The data assimilation convergene tolerance must be non-negative.");
480 std::string localization_cutoff_function_str =
481 database.get(
"data_assimilation.localization_cutoff_function",
"none");
483 if (!(boost::iequals(localization_cutoff_function_str,
"gaspari_cohn") ||
484 boost::iequals(localization_cutoff_function_str,
"step_function") ||
485 boost::iequals(localization_cutoff_function_str,
"none")))
487 ASSERT_THROW(
false,
"Unknown localization cutoff function. Valid options "
488 "are 'gaspari_cohn', 'step_function', and 'none'.");
492 boost::optional<std::string> mesh_unit =
493 database.get_optional<std::string>(
"units.mesh");
494 if (mesh_unit && (!(boost::iequals(mesh_unit.get(),
"millimeter") ||
495 boost::iequals(mesh_unit.get(),
"centimeter") ||
496 boost::iequals(mesh_unit.get(),
"inch") ||
497 boost::iequals(mesh_unit.get(),
"meter"))))
499 ASSERT_THROW(
false,
"Unknown unit associated with the mesh. Valid options "
500 "are `millimeter`, `centimeter`, `inch`, and `meter`");
503 boost::optional<std::string> heat_source_power_unit =
504 database.get_optional<std::string>(
"units.heat_source.power");
505 if (heat_source_power_unit &&
506 (!(boost::iequals(heat_source_power_unit.get(),
"milliwatt") ||
507 boost::iequals(heat_source_power_unit.get(),
"watt"))))
509 ASSERT_THROW(
false,
"Unknown unit associated with the power of the heat "
510 "source. Valid options are `milliwatt`, and `watt`");
513 boost::optional<std::string> heat_source_velocity_unit =
514 database.get_optional<std::string>(
"units.heat_source.velocity");
515 if (heat_source_velocity_unit &&
516 (!(boost::iequals(heat_source_velocity_unit.get(),
"millimeter/second") ||
517 boost::iequals(heat_source_velocity_unit.get(),
"centimeter/second") ||
518 boost::iequals(heat_source_velocity_unit.get(),
"meter/second"))))
520 ASSERT_THROW(
false,
"Unknown unit associated with the velocity of the heat "
521 "source. Valid options are `millimeter/second`, "
522 "`centimeter/second`, and `meter/second`");
525 boost::optional<std::string> heat_source_dimension_unit =
526 database.get_optional<std::string>(
"units.heat_source.dimension");
527 if (heat_source_dimension_unit &&
528 (!(boost::iequals(heat_source_dimension_unit.get(),
"millimeter") ||
529 boost::iequals(heat_source_dimension_unit.get(),
"centimeter") ||
530 boost::iequals(heat_source_dimension_unit.get(),
"inch") ||
531 boost::iequals(heat_source_dimension_unit.get(),
"meter"))))
535 "Unknown unit associated with the dimension of the heat source. Valid "
536 "options are `millimeter`, `centimeter`, `inch`, and `meter`");
539 boost::optional<std::string> heat_source_scan_path_unit =
540 database.get_optional<std::string>(
"units.heat_source.scan_path");
541 if (heat_source_scan_path_unit &&
542 (!(boost::iequals(heat_source_scan_path_unit.get(),
"millimeter") ||
543 boost::iequals(heat_source_scan_path_unit.get(),
"centimeter") ||
544 boost::iequals(heat_source_scan_path_unit.get(),
"inch") ||
545 boost::iequals(heat_source_scan_path_unit.get(),
"meter"))))
548 "Unknown unit associated with the scan path. Valid options "
549 "are `millimeter`, `centimeter`, `inch`, and `meter`");
void validate_input_database(boost::property_tree::ptree &database)
static std::array< std::string, 3 > const material_state_names
void ASSERT_THROW(bool cond, std::string const &message)