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 for (
auto const &child_pair : boundary_database)
92 bool thermal_bc =
false;
93 bool mechanical_bc =
false;
95 std::string boundary_type_str =
"invalid";
96 if (child_pair.first ==
"type")
98 boundary_type_str = child_pair.second.data();
103 boundary_database.get<std::string>(child_pair.first +
".type");
106 while ((pos_str = boundary_type_str.find(delimiter)) != std::string::npos)
108 std::string boundary = boundary_type_str.substr(0, pos_str);
109 parse_boundary_type(boundary, line_boundary_type, thermal_bc,
111 boundary_type_str.erase(0, pos_str + delimiter.length());
113 parse_boundary_type(boundary_type_str, line_boundary_type, thermal_bc,
116 if (use_thermal_physics)
118 ASSERT_THROW(thermal_bc,
"Missing thermal boundary condition.");
120 if (use_mechanical_physics)
122 ASSERT_THROW(mechanical_bc,
"Missing mechanical boundary condition.");
127 if (use_thermal_physics)
130 unsigned int const fe_degree =
131 database.get<
unsigned int>(
"discretization.thermal.fe_degree");
133 "fe_degree should be between 1 and 5.");
136 boost::optional<std::string> quadrature_type_optional =
137 database.get_optional<std::string>(
"discretization.thermal.quadrature");
139 if (quadrature_type_optional)
141 std::string quadrature_type = quadrature_type_optional.get();
142 if (!((boost::iequals(quadrature_type,
"gauss") ||
143 (boost::iequals(quadrature_type,
"lobatto")))))
151 unsigned int dim = database.get<
unsigned int>(
"geometry.dim");
152 ASSERT_THROW((dim == 2) || (dim == 3),
"dim should be 2 or 3");
154 bool use_powder = database.get(
"geometry.use_powder",
false);
158 double powder_layer = database.get<
double>(
"geometry.powder_layer");
159 ASSERT_THROW(powder_layer >= 0.0,
"powder_layer must be non-negative.");
162 bool material_deposition =
163 database.get(
"geometry.material_deposition",
false);
165 if (material_deposition)
168 database.get<std::string>(
"geometry.material_deposition_method");
171 (method ==
"file" || method ==
"scan_paths"),
172 "Method type for material deposition, '" + method +
173 "', is not recognized. Valid options are: 'file' and 'scan_paths'");
175 if (method ==
"file")
177 ASSERT_THROW(database.count(
"geometry.material_deposition_file") != 0,
178 "If the material deposition method is 'file', "
179 "'material_deposition_file' must be given.");
183 ASSERT_THROW(database.get_child(
"geometry").count(
"deposition_length") !=
185 "If the material deposition method is 'scan_path', "
186 "'deposition_length' must be given.");
187 ASSERT_THROW(database.get_child(
"geometry").count(
"deposition_height") !=
189 "If the material deposition method is 'scan_path', "
190 "'deposition_height' must be given.");
193 ASSERT_THROW(database.get_child(
"geometry").count(
"deposition_width") !=
195 "If the material deposition method is 'scan_path', "
196 "'deposition_width' must be given.");
199 database.get_child(
"geometry").count(
"deposition_lead_time") != 0,
200 "If the material deposition method is 'scan_path', "
201 "'deposition_lead_time' must be given.");
205 bool import_mesh = database.get<
bool>(
"geometry.import_mesh");
208 ASSERT_THROW(database.get_child(
"geometry").count(
"mesh_file") != 0,
209 "If the the mesh is imported, 'mesh_file' must be given.");
210 ASSERT_THROW(database.get_child(
"geometry").count(
"mesh_format") != 0,
211 "If the the mesh is imported, 'mesh_format' must be given.");
215 ASSERT_THROW(database.get_child(
"geometry").count(
"length") != 0,
216 "If the the mesh is not imported, 'length' must be given.");
217 ASSERT_THROW(database.get_child(
"geometry").count(
"height") != 0,
218 "If the the mesh is not imported, 'height' must be given.");
221 ASSERT_THROW(database.get_child(
"geometry").count(
"width") != 0,
222 "If the the mesh is not imported, 'width' must be given.");
227 unsigned int n_materials =
228 database.get<
unsigned int>(
"materials.n_materials");
230 std::string property_format =
231 database.get<std::string>(
"materials.property_format");
233 (property_format ==
"polynomial"),
234 "property_format should be table or polynomial.");
236 for (dealii::types::material_id
id = 0;
id < n_materials; ++id)
239 .count(
"material_" + std::to_string(
id)) != 0,
240 "Number of material subtrees does not match the set number of "
243 bool has_a_valid_state =
false;
244 for (
unsigned int state_index = 0;
247 if (database.get_child(
"materials")
248 .get_child(
"material_" + std::to_string(
id))
251 has_a_valid_state =
true;
254 .get_child(
"material_" + std::to_string(
id))
256 .count(
"density") != 0,
257 "Each state needs a user-specified density.");
259 .get_child(
"material_" + std::to_string(
id))
261 .count(
"specific_heat") != 0,
262 "Each state needs a user-specified specific heat.");
264 .get_child(
"material_" + std::to_string(
id))
266 .count(
"thermal_conductivity_x") != 0,
267 "Each state needs a user-specified specific thermal "
270 .get_child(
"material_" + std::to_string(
id))
272 .count(
"thermal_conductivity_z") != 0,
273 "Each state needs a user-specified specific thermal "
279 .get_child(
"material_" + std::to_string(
id))
281 .count(
"thermal_conductivity_y") != 0,
282 "Each state needs a user-specified specific thermal "
289 .get_child(
"material_" + std::to_string(
id))
291 .count(
"convection_heat_transfer_coef") != 0,
292 "Convective BCs require a user-specified convection "
293 "heat transfer coefficient.");
299 .get_child(
"material_" + std::to_string(
id))
301 .count(
"emissivity") != 0,
302 "Radiative BCs require a user-specified emissivity.");
312 has_a_valid_state ==
true,
313 "Material without any valid state (solid, powder, or liquid).");
318 database.get_child(
"materials")
319 .get_child(
"material_" + std::to_string(
id))
320 .count(
"convection_temperature_infty") != 0,
321 "Convective BCs require setting 'convection_temperature_infty'.");
327 database.get_child(
"materials")
328 .get_child(
"material_" + std::to_string(
id))
329 .count(
"radiation_temperature_infty") != 0,
330 "Radiative BCs require setting 'radiation_temperature_infty'.");
335 boost::optional<std::string> memory_space_optional =
336 database.get_optional<std::string>(
"memory_space");
337 if (memory_space_optional)
339 std::string memory_space = memory_space_optional.get();
341 (memory_space ==
"device" || memory_space ==
"host"),
342 "Method type for memory space, '" + memory_space +
343 "', is not recognized. Valid options are: 'host' and 'device'");
347 ASSERT_THROW(database.get_child(
"post_processor").count(
"filename_prefix") !=
349 "The filename prefix for the postprocessor must be specified.");
353 "A refinement section of the input file must exist.");
356 unsigned int n_beams = database.get<
unsigned int>(
"sources.n_beams");
357 for (
unsigned int beam_index = 0; beam_index < n_beams; ++beam_index)
359 std::string beam_type = database.get<std::string>(
360 "sources.beam_" + std::to_string(beam_index) +
".type");
362 boost::iequals(beam_type,
"electron_beam") ||
363 boost::iequals(beam_type,
"cube"),
364 "Beam type, '" + beam_type +
365 "', is not recognized. Valid options are: 'goldak', "
366 "'electron_beam', and 'cube'.");
368 .get_child(
"beam_" + std::to_string(beam_index))
369 .count(
"scan_path_file") != 0,
370 "A scan path file for each beam must be given.");
372 std::string file_format =
373 database.get<std::string>(
"sources.beam_" + std::to_string(beam_index) +
374 ".scan_path_file_format");
376 boost::iequals(file_format,
"event_series"),
377 "Scan path file format, '" + file_format +
378 "', is not recognized. Valid options are: 'segment' and "
381 std::to_string(beam_index) +
".depth") >=
383 "Heat source depth must be non-negative.");
385 double absorption_efficiency =
386 database.get<
double>(
"sources.beam_" + std::to_string(beam_index) +
387 ".absorption_efficiency");
388 ASSERT_THROW(absorption_efficiency >= 0.0 && absorption_efficiency <= 1.0,
389 "Heat source absorption efficiency must be between 0 and 1.");
393 std::string time_stepping_method =
394 database.get<std::string>(
"time_stepping.method");
395 ASSERT_THROW(boost::iequals(time_stepping_method,
"forward_euler") ||
396 boost::iequals(time_stepping_method,
"rk_third_order") ||
397 boost::iequals(time_stepping_method,
"rk_fourth_order"),
398 "Time stepping method, '" + time_stepping_method +
399 "', is not recognized. Valid options are: 'forward_euler', "
400 "'rk_third_order', and 'rk_fourth_order'.");
402 if (database.get(
"time.scan_path_for_duration",
false))
404 ASSERT_THROW(database.get<
double>(
"time_stepping.duration") >= 0.0,
405 "Time stepping duration must be non-negative.");
408 ASSERT_THROW(database.get<
double>(
"time_stepping.time_step") >= 0.0,
409 "Time step must be non-negative.");
415 boost::optional<boost::property_tree::ptree &> experiment_optional_database =
416 database.get_child_optional(
"experiment");
417 if (experiment_optional_database)
419 bool experiment_active =
420 database.get(
"experiment.read_in_experimental_data",
false);
421 if (experiment_active)
423 ASSERT_THROW(database.get_child(
"experiment").count(
"file") != 0,
424 "If reading experimental data, a file must be given.");
426 ASSERT_THROW(database.get_child(
"experiment").count(
"last_frame") != 0,
427 "If reading experimental data, a last frame index "
430 std::string experiment_format =
431 database.get<std::string>(
"experiment.format");
432 ASSERT_THROW(boost::iequals(experiment_format,
"point_cloud") ||
433 boost::iequals(experiment_format,
"ray"),
434 "Experiment format must be 'point_cloud' or 'ray'.");
436 unsigned int first_frame_index =
437 database.get<
unsigned int>(
"experiment.first_frame", 0);
438 unsigned int last_frame_index =
439 database.get<
unsigned int>(
"experiment.last_frame");
441 "When reading experimental data, the last frame index "
442 "cannot be lower than the first frame index.");
444 unsigned int first_camera_id =
445 database.get<
unsigned int>(
"experiment.first_camera_id");
446 unsigned int last_camera_id =
447 database.get<
unsigned int>(
"experiment.last_camera_id");
449 "When reading experimental data, the last camera id cannot "
450 "be lower than the first camera id.");
453 database.get_child(
"experiment").count(
"log_filename") != 0,
454 "If reading experimental data, a log filename must be given.");
462 boost::optional<double> convergence_tolerance =
463 database.get_optional<
double>(
"data_assimilation.convergence_tolerance");
464 if (convergence_tolerance)
467 convergence_tolerance.get() >= 0.0,
468 "The data assimilation convergene tolerance must be non-negative.");
471 std::string localization_cutoff_function_str =
472 database.get(
"data_assimilation.localization_cutoff_function",
"none");
474 if (!(boost::iequals(localization_cutoff_function_str,
"gaspari_cohn") ||
475 boost::iequals(localization_cutoff_function_str,
"step_function") ||
476 boost::iequals(localization_cutoff_function_str,
"none")))
478 ASSERT_THROW(
false,
"Unknown localization cutoff function. Valid options "
479 "are 'gaspari_cohn', 'step_function', and 'none'.");
483 boost::optional<std::string> mesh_unit =
484 database.get_optional<std::string>(
"units.mesh");
485 if (mesh_unit && (!(boost::iequals(mesh_unit.get(),
"millimeter") ||
486 boost::iequals(mesh_unit.get(),
"centimeter") ||
487 boost::iequals(mesh_unit.get(),
"inch") ||
488 boost::iequals(mesh_unit.get(),
"meter"))))
490 ASSERT_THROW(
false,
"Unknown unit associated with the mesh. Valid options "
491 "are `millimeter`, `centimeter`, `inch`, and `meter`");
494 boost::optional<std::string> heat_source_power_unit =
495 database.get_optional<std::string>(
"units.heat_source.power");
496 if (heat_source_power_unit &&
497 (!(boost::iequals(heat_source_power_unit.get(),
"milliwatt") ||
498 boost::iequals(heat_source_power_unit.get(),
"watt"))))
500 ASSERT_THROW(
false,
"Unknown unit associated with the power of the heat "
501 "source. Valid options are `milliwatt`, and `watt`");
504 boost::optional<std::string> heat_source_velocity_unit =
505 database.get_optional<std::string>(
"units.heat_source.velocity");
506 if (heat_source_velocity_unit &&
507 (!(boost::iequals(heat_source_velocity_unit.get(),
"millimeter/second") ||
508 boost::iequals(heat_source_velocity_unit.get(),
"centimeter/second") ||
509 boost::iequals(heat_source_velocity_unit.get(),
"meter/second"))))
511 ASSERT_THROW(
false,
"Unknown unit associated with the velocity of the heat "
512 "source. Valid options are `millimeter/second`, "
513 "`centimeter/second`, and `meter/second`");
516 boost::optional<std::string> heat_source_dimension_unit =
517 database.get_optional<std::string>(
"units.heat_source.dimension");
518 if (heat_source_dimension_unit &&
519 (!(boost::iequals(heat_source_dimension_unit.get(),
"millimeter") ||
520 boost::iequals(heat_source_dimension_unit.get(),
"centimeter") ||
521 boost::iequals(heat_source_dimension_unit.get(),
"inch") ||
522 boost::iequals(heat_source_dimension_unit.get(),
"meter"))))
526 "Unknown unit associated with the dimension of the heat source. Valid "
527 "options are `millimeter`, `centimeter`, `inch`, and `meter`");
530 boost::optional<std::string> heat_source_scan_path_unit =
531 database.get_optional<std::string>(
"units.heat_source.scan_path");
532 if (heat_source_scan_path_unit &&
533 (!(boost::iequals(heat_source_scan_path_unit.get(),
"millimeter") ||
534 boost::iequals(heat_source_scan_path_unit.get(),
"centimeter") ||
535 boost::iequals(heat_source_scan_path_unit.get(),
"inch") ||
536 boost::iequals(heat_source_scan_path_unit.get(),
"meter"))))
539 "Unknown unit associated with the scan path. Valid options "
540 "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)