27 #include <deal.II/arborx/bvh.h>
28 #include <deal.II/base/index_set.h>
29 #include <deal.II/base/mpi.h>
30 #include <deal.II/base/symmetric_tensor.h>
31 #include <deal.II/base/types.h>
32 #include <deal.II/distributed/cell_data_transfer.templates.h>
33 #include <deal.II/distributed/solution_transfer.h>
34 #include <deal.II/grid/filtered_iterator.h>
35 #include <deal.II/grid/grid_refinement.h>
36 #include <deal.II/lac/trilinos_sparse_matrix.h>
37 #include <deal.II/lac/vector_operation.h>
38 #include <deal.II/numerics/error_estimator.h>
40 #include <boost/algorithm/string.hpp>
41 #include <boost/archive/text_iarchive.hpp>
42 #include <boost/archive/text_oarchive.hpp>
43 #include <boost/property_tree/ptree.hpp>
49 #include <type_traits>
50 #include <unordered_map>
52 #ifdef ADAMANTINE_WITH_CALIPER
53 #include <caliper/cali.h>
59 template <
int dim,
int n_materials,
int p_order,
typename MaterialStates,
60 typename MemorySpaceType,
62 std::is_same<MemorySpaceType, dealii::MemorySpace::Host>::value,
70 dealii::LinearAlgebra::distributed::Vector<double, MemorySpaceType>
73 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>
const
75 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
78 MemorySpaceType>
const &material_properties,
79 std::vector<adamantine::Timer> &timers)
81 #ifdef ADAMANTINE_WITH_CALIPER
82 CALI_CXX_MARK_FUNCTION;
87 thermal_physics->get_affine_constraints().distribute(temperature);
88 if (mechanical_physics)
90 mechanical_physics->get_affine_constraints().distribute(displacement);
91 post_processor.template write_output<
typename Kokkos::View<
92 double **,
typename MemorySpaceType::kokkos_space>::array_layout>(
93 n_time_step, time, temperature, displacement,
94 mechanical_physics->get_stress_tensor(),
95 material_properties.get_state(), material_properties.get_dofs_map(),
96 material_properties.get_dof_handler());
100 post_processor.template write_thermal_output<
typename Kokkos::View<
101 double **,
typename MemorySpaceType::kokkos_space>::array_layout>(
102 n_time_step, time, temperature, material_properties.get_state(),
103 material_properties.get_dofs_map(),
104 material_properties.get_dof_handler());
109 mechanical_physics->get_affine_constraints().distribute(displacement);
110 post_processor.template write_mechanical_output<
typename Kokkos::View<
111 double **,
typename MemorySpaceType::kokkos_space>::array_layout>(
112 n_time_step, time, displacement,
113 mechanical_physics->get_stress_tensor(),
114 material_properties.get_state(), material_properties.get_dofs_map(),
115 material_properties.get_dof_handler());
120 template <
int dim,
int n_materials,
int p_order,
typename MaterialStates,
121 typename MemorySpaceType,
122 std::enable_if_t<std::is_same<MemorySpaceType,
123 dealii::MemorySpace::Default>::value,
131 dealii::LinearAlgebra::distributed::Vector<double, MemorySpaceType>
134 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>
const
136 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
139 MemorySpaceType>
const &material_properties,
140 std::vector<adamantine::Timer> &timers)
142 #ifdef ADAMANTINE_WITH_CALIPER
143 CALI_CXX_MARK_FUNCTION;
146 auto state = material_properties.get_state();
147 auto state_host = Kokkos::create_mirror_view_and_copy(
148 dealii::MemorySpace::Host::kokkos_space{}, state);
151 dealii::LinearAlgebra::distributed::Vector<double,
152 dealii::MemorySpace::Host>
153 temperature_host(temperature.get_partitioner());
154 temperature_host.import(temperature, dealii::VectorOperation::insert);
155 thermal_physics->get_affine_constraints().distribute(temperature_host);
156 if (mechanical_physics)
158 mechanical_physics->get_affine_constraints().distribute(displacement);
159 post_processor.template write_output<
typename Kokkos::View<
160 double **,
typename MemorySpaceType::kokkos_space>::array_layout>(
161 n_time_step, time, temperature_host, displacement,
162 mechanical_physics->get_stress_tensor(), state_host,
163 material_properties.get_dofs_map(),
164 material_properties.get_dof_handler());
168 post_processor.template write_thermal_output<
typename Kokkos::View<
169 double **,
typename MemorySpaceType::kokkos_space>::array_layout>(
170 n_time_step, time, temperature_host, state_host,
171 material_properties.get_dofs_map(),
172 material_properties.get_dof_handler());
177 mechanical_physics->get_affine_constraints().distribute(displacement);
178 post_processor.template write_mechanical_output<
typename Kokkos::View<
179 double **,
typename MemorySpaceType::kokkos_space>::array_layout>(
180 n_time_step, time, displacement,
181 mechanical_physics->get_stress_tensor(), state_host,
182 material_properties.get_dofs_map(),
183 material_properties.get_dof_handler());
190 std::vector<adamantine::Timer> &timers)
208 communicator,
"Evolve One Time Step: evaluate_thermal_physics"));
210 communicator,
"Evolve One Time Step: evaluate_material_properties"));
214 template <
int dim,
int n_materials,
int p_order,
int fe_degree,
215 typename MaterialStates,
typename MemorySpaceType,
216 typename QuadratureType>
217 std::unique_ptr<adamantine::ThermalPhysicsInterface<dim, MemorySpaceType>>
219 MPI_Comm
const &communicator, boost::property_tree::ptree
const &database,
222 MemorySpaceType> &material_properties)
225 dim, n_materials, p_order, fe_degree, MaterialStates, MemorySpaceType,
226 QuadratureType>>(communicator, database, geometry, boundary,
227 material_properties);
230 template <
int dim,
int n_materials,
int p_order,
int fe_degree,
231 typename MaterialStates,
typename MemorySpaceType>
232 std::unique_ptr<adamantine::ThermalPhysicsInterface<dim, MemorySpaceType>>
234 std::string
const &quadrature_type, MPI_Comm
const &communicator,
235 boost::property_tree::ptree
const &database,
238 MemorySpaceType> &material_properties)
240 if (quadrature_type.compare(
"gauss") == 0)
241 return initialize<dim, n_materials, p_order, fe_degree, MaterialStates,
242 MemorySpaceType, dealii::QGauss<1>>(
243 communicator, database, geometry, boundary, material_properties);
247 "quadrature should be Gauss or Lobatto.");
248 return initialize<dim, n_materials, p_order, fe_degree, MaterialStates,
249 MemorySpaceType, dealii::QGaussLobatto<1>>(
250 communicator, database, geometry, boundary, material_properties);
254 template <
int dim,
int n_materials,
int p_order,
typename MaterialStates,
255 typename MemorySpaceType>
256 std::unique_ptr<adamantine::ThermalPhysicsInterface<dim, MemorySpaceType>>
258 unsigned int fe_degree, std::string
const &quadrature_type,
259 MPI_Comm
const &communicator, boost::property_tree::ptree
const &database,
262 MemorySpaceType> &material_properties)
269 MemorySpaceType>(quadrature_type, communicator,
270 database, geometry, boundary,
271 material_properties);
276 MemorySpaceType>(quadrature_type, communicator,
277 database, geometry, boundary,
278 material_properties);
283 MemorySpaceType>(quadrature_type, communicator,
284 database, geometry, boundary,
285 material_properties);
290 MemorySpaceType>(quadrature_type, communicator,
291 database, geometry, boundary,
292 material_properties);
297 "fe_degree should be between 1 and 5.");
299 MemorySpaceType>(quadrature_type, communicator,
300 database, geometry, boundary,
301 material_properties);
306 template <
int dim,
int n_materials,
int p_order,
typename MaterialStates,
307 typename MemorySpaceType>
312 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>
315 MemorySpaceType> &material_properties,
316 dealii::DoFHandler<dim> &dof_handler,
317 dealii::LA::distributed::Vector<double, MemorySpaceType> &solution)
319 #ifdef ADAMANTINE_WITH_CALIPER
320 CALI_CXX_MARK_FUNCTION;
323 dealii::parallel::distributed::Triangulation<dim> &triangulation =
324 dynamic_cast<dealii::parallel::distributed::Triangulation<dim> &
>(
325 const_cast<dealii::Triangulation<dim> &
>(
326 dof_handler.get_triangulation()));
331 thermal_physics->set_state_to_material_properties();
334 dealii::parallel::distributed::SolutionTransfer<
335 dim, dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>>
336 solution_transfer(dof_handler);
339 unsigned int const direction_data_size = 2;
340 unsigned int const phase_history_data_size = 1;
341 unsigned int constexpr n_material_states = MaterialStates::n_material_states;
342 std::vector<std::vector<double>> data_to_transfer;
343 std::vector<double> dummy_cell_data(n_material_states + direction_data_size +
344 phase_history_data_size,
345 std::numeric_limits<double>::infinity());
346 auto state_host = Kokkos::create_mirror_view_and_copy(
347 Kokkos::HostSpace{}, material_properties.get_state());
348 unsigned int cell_id = 0;
349 unsigned int activated_cell_id = 0;
350 for (
auto const &cell : dof_handler.active_cell_iterators())
352 if (cell->is_locally_owned())
354 std::vector<double> cell_data(n_material_states + direction_data_size +
355 phase_history_data_size);
356 for (
unsigned int i = 0; i < n_material_states; ++i)
357 cell_data[i] = state_host(i, cell_id);
358 if (cell->active_fe_index() == 0)
360 cell_data[n_material_states] =
361 thermal_physics->get_deposition_cos(activated_cell_id);
362 cell_data[n_material_states + 1] =
363 thermal_physics->get_deposition_sin(activated_cell_id);
365 if (thermal_physics->get_has_melted(activated_cell_id))
366 cell_data[n_material_states + direction_data_size] = 1.0;
368 cell_data[n_material_states + direction_data_size] = 0.0;
374 cell_data[n_material_states] = std::numeric_limits<double>::infinity();
375 cell_data[n_material_states + 1] =
376 std::numeric_limits<double>::infinity();
377 cell_data[n_material_states + direction_data_size] =
378 std::numeric_limits<double>::infinity();
380 data_to_transfer.push_back(cell_data);
385 data_to_transfer.push_back(dummy_cell_data);
391 triangulation.prepare_coarsening_and_refinement();
393 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
395 if constexpr (std::is_same_v<MemorySpaceType, dealii::MemorySpace::Host>)
398 thermal_physics->get_affine_constraints().distribute(solution);
401 solution.update_ghost_values();
402 solution_transfer.prepare_for_coarsening_and_refinement(solution);
406 solution_host.reinit(solution.get_partitioner());
407 solution_host.import(solution, dealii::VectorOperation::insert);
409 thermal_physics->get_affine_constraints().distribute(solution_host);
412 solution_host.update_ghost_values();
413 solution_transfer.prepare_for_coarsening_and_refinement(solution_host);
416 dealii::parallel::distributed::CellDataTransfer<
417 dim, dim, std::vector<std::vector<double>>>
418 cell_data_trans(triangulation);
419 cell_data_trans.prepare_for_coarsening_and_refinement(data_to_transfer);
421 if (mechanical_physics)
423 mechanical_physics->prepare_transfer_mpi();
426 #ifdef ADAMANTINE_WITH_CALIPER
427 CALI_MARK_BEGIN(
"refine triangulation");
430 triangulation.execute_coarsening_and_refinement();
431 #ifdef ADAMANTINE_WITH_CALIPER
432 CALI_MARK_END(
"refine triangulation");
436 thermal_physics->setup_dofs();
437 thermal_physics->initialize_dof_vector(0., solution);
440 material_properties.reinit_dofs();
443 if constexpr (std::is_same_v<MemorySpaceType, dealii::MemorySpace::Host>)
445 solution_transfer.interpolate(solution);
449 solution_host.reinit(solution.get_partitioner());
450 solution_transfer.interpolate(solution_host);
451 solution.import(solution_host, dealii::VectorOperation::insert);
455 std::vector<std::vector<double>> transferred_data(
456 triangulation.n_active_cells(),
457 std::vector<double>(n_material_states + direction_data_size +
458 phase_history_data_size));
459 cell_data_trans.unpack(transferred_data);
460 auto state = material_properties.get_state();
461 state_host = Kokkos::create_mirror_view(state);
462 unsigned int total_cell_id = 0;
464 std::vector<double> transferred_cos;
465 std::vector<double> transferred_sin;
466 std::vector<bool> has_melted;
467 for (
auto const &cell : dof_handler.active_cell_iterators())
469 if (cell->is_locally_owned())
471 for (
unsigned int i = 0; i < n_material_states; ++i)
473 state_host(i, cell_id) = transferred_data[total_cell_id][i];
475 if (cell->active_fe_index() == 0)
477 transferred_cos.push_back(
478 transferred_data[total_cell_id][n_material_states]);
479 transferred_sin.push_back(
480 transferred_data[total_cell_id][n_material_states + 1]);
483 if (transferred_data[total_cell_id]
484 [n_material_states + direction_data_size] > 0.5)
485 has_melted.push_back(
true);
487 has_melted.push_back(
false);
495 thermal_physics->set_material_deposition_orientation(transferred_cos,
499 thermal_physics->set_has_melted_vector(has_melted);
502 Kokkos::deep_copy(state, state_host);
505 thermal_physics->get_state_from_material_properties();
510 for (
auto const &cell : dof_handler.active_cell_iterators())
512 if (cell->is_locally_owned())
514 double material_ratio = 0.;
515 for (
unsigned int i = 0; i < n_material_states; ++i)
517 material_ratio += state_host(i, cell_id);
519 ASSERT(std::abs(material_ratio - 1.) < 1e-14,
"Material is lost.");
525 if (mechanical_physics)
527 mechanical_physics->complete_transfer_mpi();
532 std::vector<
typename dealii::parallel::distributed::Triangulation<
533 dim>::active_cell_iterator>
535 dealii::parallel::distributed::Triangulation<dim> &triangulation,
536 double const time,
double const next_refinement_time,
537 unsigned int const n_time_steps,
545 std::vector<dealii::BoundingBox<dim>> cell_bounding_boxes;
546 for (
auto const &cell : triangulation.active_cell_iterators() |
547 dealii::IteratorFilters::LocallyOwnedCell())
549 cell_bounding_boxes.push_back(cell->bounding_box());
551 dealii::ArborXWrappers::BVH bvh(cell_bounding_boxes);
553 double const bounding_box_scaling = 2.0;
554 std::vector<dealii::BoundingBox<dim>> heat_source_bounding_boxes;
555 for (
unsigned int i = 0; i < n_time_steps; ++i)
557 double const current_time = time +
static_cast<double>(i) /
558 static_cast<double>(n_time_steps) *
559 (next_refinement_time - time);
562 for (
auto &beam : heat_sources)
564 heat_source_bounding_boxes.push_back(
565 beam->get_bounding_box(current_time, bounding_box_scaling));
571 dealii::ArborXWrappers::BoundingBoxIntersectPredicate bb_intersect(
572 heat_source_bounding_boxes);
573 auto [indices, offset] = bvh.query(bb_intersect);
577 std::unordered_set<int> indices_to_refine;
578 indices_to_refine.insert(indices.begin(), indices.end());
580 std::vector<
typename dealii::parallel::distributed::Triangulation<
581 dim>::active_cell_iterator>
584 for (
auto const &cell : triangulation.active_cell_iterators() |
585 dealii::IteratorFilters::LocallyOwnedCell())
587 if (indices_to_refine.count(cell_index))
589 cells_to_refine.push_back(cell);
594 return cells_to_refine;
597 template <
int dim,
int n_materials,
int p_order,
int fe_degree,
598 typename MaterialStates,
typename MemorySpaceType>
603 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>
606 MemorySpaceType> &material_properties,
607 dealii::LA::distributed::Vector<double, MemorySpaceType> &solution,
610 double const time,
double const next_refinement_time,
611 unsigned int const time_steps_refinement,
612 boost::property_tree::ptree
const &refinement_database)
614 #ifdef ADAMANTINE_WITH_CALIPER
615 CALI_CXX_MARK_FUNCTION;
617 dealii::DoFHandler<dim> &dof_handler = thermal_physics->get_dof_handler();
618 dealii::parallel::distributed::Triangulation<dim> &triangulation =
619 dynamic_cast<dealii::parallel::distributed::Triangulation<dim> &
>(
620 const_cast<dealii::Triangulation<dim> &
>(
621 dof_handler.get_triangulation()));
624 unsigned int const n_refinements =
625 refinement_database.get(
"n_refinements", 2);
627 for (
unsigned int i = 0; i < n_refinements; ++i)
630 auto cells_to_refine =
632 time_steps_refinement, heat_sources);
635 const bool coarsen_after_beam =
636 refinement_database.get<
bool>(
"coarsen_after_beam",
false);
639 if (coarsen_after_beam)
641 for (
auto cell : dealii::filter_iterators(
642 triangulation.active_cell_iterators(),
643 dealii::IteratorFilters::LocallyOwnedCell()))
645 if (cell->level() > 0)
646 cell->set_coarsen_flag();
651 for (
auto &cell : cells_to_refine)
653 if (coarsen_after_beam)
654 cell->clear_coarsen_flag();
656 if (cell->level() <
static_cast<int>(n_refinements))
657 cell->set_refine_flag();
662 material_properties, dof_handler, solution);
666 thermal_physics->compute_inverse_mass_matrix();
669 template <
int dim,
int n_materials,
int p_order,
typename MaterialStates,
670 typename MemorySpaceType>
675 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>
678 MemorySpaceType> &material_properties,
679 dealii::LA::distributed::Vector<double, MemorySpaceType> &solution,
682 double const time,
double const next_refinement_time,
683 unsigned int const time_steps_refinement,
684 boost::property_tree::ptree
const &refinement_database)
686 if (!thermal_physics)
689 switch (thermal_physics->get_fe_degree())
693 refine_mesh<dim, n_materials, p_order, 1, MaterialStates>(
694 thermal_physics, mechanical_physics, material_properties, solution,
695 heat_sources, time, next_refinement_time, time_steps_refinement,
696 refinement_database);
701 refine_mesh<dim, n_materials, p_order, 2, MaterialStates>(
702 thermal_physics, mechanical_physics, material_properties, solution,
703 heat_sources, time, next_refinement_time, time_steps_refinement,
704 refinement_database);
709 refine_mesh<dim, n_materials, p_order, 3, MaterialStates>(
710 thermal_physics, mechanical_physics, material_properties, solution,
711 heat_sources, time, next_refinement_time, time_steps_refinement,
712 refinement_database);
717 refine_mesh<dim, n_materials, p_order, 4, MaterialStates>(
718 thermal_physics, mechanical_physics, material_properties, solution,
719 heat_sources, time, next_refinement_time, time_steps_refinement,
720 refinement_database);
725 refine_mesh<dim, n_materials, p_order, 5, MaterialStates>(
726 thermal_physics, mechanical_physics, material_properties, solution,
727 heat_sources, time, next_refinement_time, time_steps_refinement,
728 refinement_database);
738 template <
int dim,
int n_materials,
int p_order,
typename MaterialStates,
739 typename MemorySpaceType>
740 std::pair<dealii::LinearAlgebra::distributed::Vector<double,
741 dealii::MemorySpace::Host>,
742 dealii::LinearAlgebra::distributed::Vector<double,
743 dealii::MemorySpace::Host>>
744 run(MPI_Comm
const &communicator, boost::property_tree::ptree
const &database,
745 std::vector<adamantine::Timer> &timers)
747 #ifdef ADAMANTINE_WITH_CALIPER
748 CALI_CXX_MARK_FUNCTION;
751 boost::optional<boost::property_tree::ptree const &> units_optional_database =
752 database.get_child_optional(
"units");
755 boost::property_tree::ptree geometry_database =
756 database.get_child(
"geometry");
758 units_optional_database);
761 boost::property_tree::ptree material_database =
762 database.get_child(
"materials");
769 boost::property_tree::ptree physics_database = database.get_child(
"physics");
770 bool const use_thermal_physics = physics_database.get<
bool>(
"thermal");
771 bool const use_mechanical_physics = physics_database.get<
bool>(
"mechanical");
774 boost::property_tree::ptree discretization_database =
775 database.get_child(
"discretization");
778 boost::property_tree::ptree post_processor_database =
779 database.get_child(
"post_processor");
783 bool const verbose_output = database.get(
"verbose_output",
false);
786 boost::property_tree::ptree boundary_database =
787 database.get_child(
"boundary");
792 std::unique_ptr<adamantine::ThermalPhysicsInterface<dim, MemorySpaceType>>
794 std::vector<std::shared_ptr<adamantine::HeatSource<dim>>> heat_sources;
795 if (use_thermal_physics)
798 unsigned int const fe_degree =
799 discretization_database.get<
unsigned int>(
"thermal.fe_degree");
801 std::string quadrature_type =
802 discretization_database.get(
"thermal.quadrature",
"gauss");
803 thermal_physics = initialize_thermal_physics<dim>(
804 fe_degree, quadrature_type, communicator, database, geometry, boundary,
805 material_properties);
806 heat_sources = thermal_physics->get_heat_sources();
807 post_processor_database.put(
"thermal_output",
true);
811 double const initial_temperature =
812 material_database.get(
"initial_temperature", 300.);
816 std::vector<double> material_reference_temps;
818 unsigned int const n_materials_runtime =
819 material_database.get<
unsigned int>(
"n_materials");
820 for (
unsigned int i = 0; i < n_materials_runtime; ++i)
825 double const reference_temperature = material_database.get<
double>(
826 "material_" + std::to_string(i) +
".solidus");
827 material_reference_temps.push_back(reference_temperature);
829 material_reference_temps.push_back(initial_temperature);
833 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>
835 if (use_mechanical_physics)
838 unsigned int const fe_degree =
839 discretization_database.
get<
unsigned int>(
"mechanical.fe_degree");
841 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>(
842 communicator, fe_degree, geometry, boundary, material_properties,
843 material_reference_temps);
844 post_processor_database.put(
"mechanical_output",
true);
848 std::unique_ptr<adamantine::PostProcessor<dim>> post_processor;
849 bool thermal_output = post_processor_database.get(
"thermal_output",
false);
850 bool mechanical_output =
851 post_processor_database.get(
"mechanical_output",
false);
852 if ((thermal_output) && (mechanical_output))
854 post_processor = std::make_unique<adamantine::PostProcessor<dim>>(
855 communicator, post_processor_database,
856 thermal_physics->get_dof_handler(),
857 mechanical_physics->get_dof_handler());
861 post_processor = std::make_unique<adamantine::PostProcessor<dim>>(
862 communicator, post_processor_database,
863 thermal_output ? thermal_physics->get_dof_handler()
864 : mechanical_physics->get_dof_handler());
868 boost::optional<boost::property_tree::ptree const &>
869 checkpoint_optional_database = database.get_child_optional(
"checkpoint");
870 boost::optional<boost::property_tree::ptree const &>
871 restart_optional_database = database.get_child_optional(
"restart");
873 unsigned int time_steps_checkpoint = std::numeric_limits<unsigned int>::max();
874 std::string checkpoint_filename;
875 bool checkpoint_overwrite =
true;
876 if (checkpoint_optional_database)
878 auto checkpoint_database = checkpoint_optional_database.get();
880 time_steps_checkpoint =
881 checkpoint_database.get<
unsigned int>(
"time_steps_between_checkpoint");
883 checkpoint_filename =
884 checkpoint_database.get<std::string>(
"filename_prefix");
886 checkpoint_overwrite = checkpoint_database.get<
bool>(
"overwrite_files");
889 bool restart =
false;
890 std::string restart_filename;
891 if (restart_optional_database)
894 auto restart_database = restart_optional_database.get();
896 restart_filename = restart_database.get<std::string>(
"filename_prefix");
899 dealii::LA::distributed::Vector<double, MemorySpaceType> temperature;
900 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
902 if (use_thermal_physics)
904 if (restart ==
false)
906 thermal_physics->setup();
907 thermal_physics->initialize_dof_vector(initial_temperature, temperature);
911 #ifdef ADAMANTINE_WITH_CALIPER
912 CALI_MARK_BEGIN(
"restart from file");
914 thermal_physics->load_checkpoint(restart_filename, temperature);
915 #ifdef ADAMANTINE_WITH_CALIPER
916 CALI_MARK_END(
"restart from file");
921 if (use_mechanical_physics)
926 "Mechanical simulation cannot be restarted from a file");
927 if (use_thermal_physics)
930 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
931 temperature_host(temperature.get_partitioner());
932 temperature_host.import(temperature, dealii::VectorOperation::insert);
933 mechanical_physics->setup_dofs(thermal_physics->get_dof_handler(),
935 thermal_physics->get_has_melted_vector());
940 mechanical_physics->setup_dofs();
942 displacement = mechanical_physics->solve();
945 unsigned int progress = 0;
946 unsigned int n_time_step = 0;
948 double activation_time_end = -1.;
949 unsigned int const rank =
950 dealii::Utilities::MPI::this_mpi_process(communicator);
955 std::cout <<
"Restarting from file" << std::endl;
957 std::ifstream file{restart_filename +
"_time.txt"};
958 boost::archive::text_iarchive ia{file};
963 double const activation_time =
964 geometry_database.get<
double>(
"deposition_time", 0.);
967 output_pvtu(*post_processor, n_time_step, time, thermal_physics, temperature,
968 mechanical_physics, displacement, material_properties, timers);
972 auto [material_deposition_boxes, deposition_times, deposition_cos,
974 adamantine::create_material_deposition_boxes<dim>(geometry_database,
977 boost::property_tree::ptree time_stepping_database =
978 database.get_child(
"time_stepping");
980 double time_step = time_stepping_database.get<
double>(
"time_step");
982 bool const scan_path_for_duration =
983 time_stepping_database.get(
"scan_path_for_duration",
false);
985 double const duration = scan_path_for_duration
986 ? std::numeric_limits<double>::max()
987 : time_stepping_database.get<
double>(
"duration");
990 boost::property_tree::ptree refinement_database =
991 database.get_child(
"refinement");
993 unsigned int const time_steps_refinement =
994 refinement_database.get(
"time_steps_between_refinement", 10);
996 unsigned int const time_steps_output =
997 post_processor_database.get(
"time_steps_between_output", 1);
999 double const new_material_temperature =
1000 database.get(
"materials.new_material_temperature", 300.);
1003 boost::optional<boost::property_tree::ptree const &>
1004 microstructure_optional_database =
1005 database.get_child_optional(
"microstructure");
1006 bool const compute_microstructure =
1007 microstructure_optional_database ? true :
false;
1008 std::unique_ptr<adamantine::Microstructure<dim>> microstructure;
1009 if (compute_microstructure)
1011 auto microstructure_database = microstructure_optional_database.get();
1013 std::string microstructure_filename =
1014 microstructure_database.get<std::string>(
"filename_prefix");
1015 microstructure = std::make_unique<adamantine::Microstructure<dim>>(
1016 communicator, microstructure_filename);
1019 #ifdef ADAMANTINE_WITH_CALIPER
1020 CALI_CXX_MARK_LOOP_BEGIN(main_loop_id,
"main_loop");
1022 while (time < duration)
1024 #ifdef ADAMANTINE_WITH_CALIPER
1025 CALI_CXX_MARK_LOOP_ITERATION(main_loop_id, n_time_step - 1);
1027 if ((time + time_step) > duration)
1028 time_step = duration - time;
1032 if (((n_time_step == 1) || ((n_time_step % time_steps_refinement) == 0)) &&
1033 use_thermal_physics)
1036 double next_refinement_time = time + time_steps_refinement * time_step;
1037 refine_mesh(thermal_physics, mechanical_physics, material_properties,
1038 temperature, heat_sources, time, next_refinement_time,
1039 time_steps_refinement, refinement_database);
1041 if ((rank == 0) && (verbose_output ==
true))
1043 std::cout <<
"n_time_step: " << n_time_step <<
" time: " << time
1044 <<
" n_dofs after mesh refinement: "
1045 << thermal_physics->get_dof_handler().n_dofs() << std::endl;
1054 if (time > activation_time_end)
1058 if (scan_path_for_duration)
1061 bool need_updated_scan_path =
false;
1062 for (
auto &source : heat_sources)
1064 if (time > source->get_scan_path().get_segment_list().back().end_time)
1066 need_updated_scan_path =
true;
1071 if (need_updated_scan_path)
1075 bool scan_path_end =
true;
1076 for (
auto &source : heat_sources)
1078 if (!source->get_scan_path().is_finished())
1080 scan_path_end =
false;
1083 source->get_scan_path().read_file();
1094 std::tie(material_deposition_boxes, deposition_times, deposition_cos,
1096 adamantine::create_material_deposition_boxes<dim>(
1097 geometry_database, heat_sources);
1101 double const eps = time_step / 1e10;
1103 auto activation_start =
1104 std::lower_bound(deposition_times.begin(), deposition_times.end(),
1106 deposition_times.begin();
1107 activation_time_end =
1108 std::min(time + std::max(activation_time, time_step), duration) - eps;
1109 auto activation_end =
1110 std::lower_bound(deposition_times.begin(), deposition_times.end(),
1111 activation_time_end) -
1112 deposition_times.begin();
1113 if (activation_start < activation_end)
1115 if (use_thermal_physics)
1117 #ifdef ADAMANTINE_WITH_CALIPER
1118 CALI_MARK_BEGIN(
"add material");
1127 thermal_physics->get_dof_handler(), material_deposition_boxes);
1132 std::vector<bool> has_melted(deposition_cos.size(),
false);
1134 thermal_physics->add_material_start(
1135 elements_to_activate, deposition_cos, deposition_sin, has_melted,
1136 activation_start, activation_end, temperature);
1138 if (use_mechanical_physics)
1140 mechanical_physics->prepare_transfer_mpi();
1143 #ifdef ADAMANTINE_WITH_CALIPER
1144 CALI_MARK_BEGIN(
"refine triangulation");
1146 dealii::parallel::distributed::Triangulation<dim> &triangulation =
1147 dynamic_cast<dealii::parallel::distributed::Triangulation<dim> &
>(
1148 const_cast<dealii::Triangulation<dim> &
>(
1149 thermal_physics->get_dof_handler().get_triangulation()));
1150 triangulation.execute_coarsening_and_refinement();
1151 #ifdef ADAMANTINE_WITH_CALIPER
1152 CALI_MARK_END(
"refine triangulation");
1155 thermal_physics->add_material_end(new_material_temperature,
1158 if (use_mechanical_physics)
1160 mechanical_physics->complete_transfer_mpi();
1163 #ifdef ADAMANTINE_WITH_CALIPER
1164 CALI_MARK_END(
"add material");
1169 if ((rank == 0) && (verbose_output ==
true) &&
1170 (activation_end - activation_start > 0) && use_thermal_physics)
1172 std::cout <<
"n_time_step: " << n_time_step <<
" time: " << time
1173 <<
" n_dofs after cell activation: "
1174 << thermal_physics->get_dof_handler().n_dofs() << std::endl;
1184 if (use_thermal_physics && use_mechanical_physics)
1186 thermal_physics->mark_has_melted(material_reference_temps[0],
1193 if (use_thermal_physics)
1195 if (compute_microstructure)
1197 #ifdef ADAMANTINE_WITH_CALIPER
1198 CALI_MARK_BEGIN(
"compute microstructure");
1200 if constexpr (std::is_same_v<MemorySpaceType,
1201 dealii::MemorySpace::Host>)
1203 microstructure->set_old_temperature(temperature);
1207 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
1208 temperature_host(temperature.get_partitioner());
1209 temperature_host.import_elements(temperature,
1210 dealii::VectorOperation::insert);
1211 microstructure->set_old_temperature(temperature_host);
1213 #ifdef ADAMANTINE_WITH_CALIPER
1214 CALI_MARK_END(
"compute microstructure");
1218 time = thermal_physics->evolve_one_time_step(time, time_step, temperature,
1221 if (compute_microstructure)
1223 #ifdef ADAMANTINE_WITH_CALIPER
1224 CALI_MARK_BEGIN(
"compute microstructure");
1226 if constexpr (std::is_same_v<MemorySpaceType,
1227 dealii::MemorySpace::Host>)
1229 microstructure->compute_G_and_R(material_properties,
1230 thermal_physics->get_dof_handler(),
1231 temperature, time_step);
1235 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
1236 temperature_host(temperature.get_partitioner());
1237 temperature_host.import_elements(temperature,
1238 dealii::VectorOperation::insert);
1239 microstructure->compute_G_and_R(material_properties,
1240 thermal_physics->get_dof_handler(),
1241 temperature_host, time_step);
1243 #ifdef ADAMANTINE_WITH_CALIPER
1244 CALI_MARK_END(
"compute microstructure");
1250 if (use_mechanical_physics)
1254 if (n_time_step % time_steps_output == 0)
1256 if (use_thermal_physics)
1259 thermal_physics->set_state_to_material_properties();
1260 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
1261 temperature_host(temperature.get_partitioner());
1262 temperature_host.import(temperature, dealii::VectorOperation::insert);
1263 mechanical_physics->setup_dofs(
1264 thermal_physics->get_dof_handler(), temperature_host,
1265 thermal_physics->get_has_melted_vector());
1269 mechanical_physics->setup_dofs();
1271 displacement = mechanical_physics->solve();
1277 if (n_time_step % time_steps_checkpoint == 0)
1279 #ifdef ADAMANTINE_WITH_CALIPER
1280 CALI_MARK_BEGIN(
"save checkpoint");
1284 std::cout <<
"Checkpoint reached" << std::endl;
1287 std::string output_dir =
1288 post_processor_database.get<std::string>(
"output_dir",
"");
1289 std::string filename_prefix =
1290 checkpoint_overwrite
1291 ? checkpoint_filename
1292 : checkpoint_filename +
'_' + std::to_string(n_time_step);
1293 thermal_physics->save_checkpoint(filename_prefix, temperature);
1294 std::ofstream file{output_dir + filename_prefix +
"_time.txt"};
1295 boost::archive::text_oarchive oa{file};
1298 #ifdef ADAMANTINE_WITH_CALIPER
1299 CALI_MARK_END(
"save checkpoint");
1306 double adim_time = time / (duration / 10.);
1307 double int_part = 0;
1308 std::modf(adim_time, &int_part);
1309 if (int_part > progress)
1311 std::cout << int_part * 10 <<
'%' <<
" completed" << std::endl;
1312 progress =
static_cast<unsigned int>(int_part);
1317 if (n_time_step % time_steps_output == 0)
1319 if (use_thermal_physics)
1321 thermal_physics->set_state_to_material_properties();
1323 output_pvtu(*post_processor, n_time_step, time, thermal_physics,
1324 temperature, mechanical_physics, displacement,
1325 material_properties, timers);
1330 #ifdef ADAMANTINE_WITH_CALIPER
1331 CALI_CXX_MARK_LOOP_END(main_loop_id);
1334 post_processor->write_pvd();
1337 if constexpr (std::is_same_v<MemorySpaceType, dealii::MemorySpace::Host>)
1339 if (use_thermal_physics)
1341 thermal_physics->get_affine_constraints().distribute(temperature);
1343 if (use_mechanical_physics)
1345 mechanical_physics->get_affine_constraints().distribute(displacement);
1347 return std::make_pair(temperature, displacement);
1351 dealii::LinearAlgebra::distributed::Vector<double,
1352 dealii::MemorySpace::Host>
1353 temperature_host(temperature.get_partitioner());
1354 temperature_host.import(temperature, dealii::VectorOperation::insert);
1355 if (use_thermal_physics)
1357 thermal_physics->get_affine_constraints().distribute(temperature_host);
1359 if (use_mechanical_physics)
1361 mechanical_physics->get_affine_constraints().distribute(displacement);
1363 return std::make_pair(temperature_host, displacement);
1368 unsigned int global_ensemble_size,
1369 MPI_Comm &local_communicator,
1370 unsigned int &local_ensemble_size,
1371 unsigned int &first_local_member,
int &my_color)
1373 unsigned int const global_rank =
1374 dealii::Utilities::MPI::this_mpi_process(global_communicator);
1375 unsigned int const global_n_procs =
1376 dealii::Utilities::MPI::n_mpi_processes(global_communicator);
1378 double const avg_n_procs_per_member =
1379 static_cast<double>(global_n_procs) /
1380 static_cast<double>(global_ensemble_size);
1381 if (avg_n_procs_per_member > 1)
1383 local_ensemble_size = 1;
1387 avg_n_procs_per_member == std::floor(avg_n_procs_per_member),
1388 "Number of MPI ranks should be less than the number of ensemble "
1389 "members or a multiple of this number.");
1392 global_rank /
static_cast<int>(std::floor(avg_n_procs_per_member));
1394 first_local_member = my_color;
1398 my_color = global_rank;
1400 unsigned int const members_per_proc = global_ensemble_size / global_n_procs;
1401 unsigned int const leftover_members =
1402 global_ensemble_size - global_n_procs * members_per_proc;
1405 local_ensemble_size = members_per_proc;
1406 if (global_rank == 0)
1408 local_ensemble_size += leftover_members;
1409 first_local_member = 0;
1413 first_local_member = global_rank * local_ensemble_size + leftover_members;
1417 MPI_Comm_split(global_communicator, my_color, 0, &local_communicator);
1420 template <
int dim,
int n_materials,
int p_order,
typename MaterialStates,
1421 typename MemorySpaceType>
1422 std::vector<dealii::LA::distributed::BlockVector<double>>
1424 boost::property_tree::ptree
const &database,
1425 std::vector<adamantine::Timer> &timers)
1427 #ifdef ADAMANTINE_WITH_CALIPER
1428 CALI_CXX_MARK_FUNCTION;
1433 boost::property_tree::ptree geometry_database =
1434 database.get_child(
"geometry");
1435 boost::property_tree::ptree boundary_database =
1436 database.get_child(
"boundary");
1437 boost::property_tree::ptree discretization_database =
1438 database.get_child(
"discretization");
1439 boost::property_tree::ptree time_stepping_database =
1440 database.get_child(
"time_stepping");
1441 boost::property_tree::ptree post_processor_database =
1442 database.get_child(
"post_processor");
1443 boost::property_tree::ptree refinement_database =
1444 database.get_child(
"refinement");
1445 boost::property_tree::ptree material_database =
1446 database.get_child(
"materials");
1449 boost::optional<boost::property_tree::ptree const &> units_optional_database =
1450 database.get_child_optional(
"units");
1451 boost::optional<const boost::property_tree::ptree &>
1452 experiment_optional_database = database.get_child_optional(
"experiment");
1453 boost::optional<const boost::property_tree::ptree &>
1454 data_assimilation_optional_database =
1455 database.get_child_optional(
"data_assimilation");
1459 bool const verbose_output = database.get(
"verbose_output",
false);
1463 unsigned int const fe_degree =
1464 discretization_database.get<
unsigned int>(
"thermal.fe_degree");
1466 std::string quadrature_type =
1467 discretization_database.get(
"thermal.quadrature",
"gauss");
1468 std::transform(quadrature_type.begin(), quadrature_type.end(),
1469 quadrature_type.begin(),
1470 [](
unsigned char c) { return std::tolower(c); });
1474 unsigned int const global_ensemble_size =
1475 database.get(
"ensemble.ensemble_size", 5);
1477 MPI_Comm local_communicator;
1478 unsigned int local_ensemble_size = std::numeric_limits<unsigned int>::max();
1479 unsigned int first_local_member = std::numeric_limits<unsigned int>::max();
1482 local_communicator, local_ensemble_size,
1483 first_local_member, my_color);
1491 std::vector<boost::property_tree::ptree> database_ensemble =
1493 database, local_communicator, first_local_member, local_ensemble_size,
1494 global_ensemble_size);
1496 std::vector<std::unique_ptr<
1498 thermal_physics_ensemble(local_ensemble_size);
1500 std::vector<std::vector<std::shared_ptr<adamantine::HeatSource<dim>>>>
1501 heat_sources_ensemble(local_ensemble_size);
1503 std::vector<std::unique_ptr<adamantine::Geometry<dim>>> geometry_ensemble;
1505 std::vector<std::unique_ptr<adamantine::Boundary>> boundary_ensemble;
1508 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>>
1509 material_properties_ensemble;
1511 std::vector<std::unique_ptr<adamantine::PostProcessor<dim>>>
1512 post_processor_ensemble;
1515 std::vector<dealii::LA::distributed::BlockVector<double>>
1516 solution_augmented_ensemble(local_ensemble_size);
1519 int constexpr base_state = 0;
1520 int constexpr augmented_state = 1;
1523 boost::property_tree::ptree data_assimilation_database;
1524 bool assimilate_data =
false;
1525 std::vector<adamantine::AugmentedStateParameters> augmented_state_parameters;
1527 if (data_assimilation_optional_database)
1530 data_assimilation_database = data_assimilation_optional_database.get();
1533 if (data_assimilation_database.get(
"assimilate_data",
false))
1535 assimilate_data =
true;
1538 if (data_assimilation_database.get(
"augment_with_beam_0_absorption",
1541 augmented_state_parameters.push_back(
1545 if (data_assimilation_database.get(
"augment_with_beam_0_max_power",
1548 augmented_state_parameters.push_back(
1554 local_communicator, my_color,
1555 data_assimilation_database);
1558 boost::optional<boost::property_tree::ptree const &>
1559 checkpoint_optional_database = database.get_child_optional(
"checkpoint");
1560 boost::optional<boost::property_tree::ptree const &>
1561 restart_optional_database = database.get_child_optional(
"restart");
1563 unsigned int const global_rank =
1564 dealii::Utilities::MPI::this_mpi_process(global_communicator);
1565 unsigned int time_steps_checkpoint = std::numeric_limits<unsigned int>::max();
1566 std::string checkpoint_filename;
1567 bool checkpoint_overwrite =
true;
1568 if (checkpoint_optional_database)
1570 auto checkpoint_database = checkpoint_optional_database.get();
1572 time_steps_checkpoint =
1573 checkpoint_database.get<
unsigned int>(
"time_steps_between_checkpoint");
1575 checkpoint_filename =
1576 checkpoint_database.get<std::string>(
"filename_prefix");
1578 checkpoint_overwrite = checkpoint_database.get<
bool>(
"overwrite_files");
1581 bool restart =
false;
1582 std::string restart_filename;
1583 if (restart_optional_database)
1586 auto restart_database = restart_optional_database.get();
1588 restart_filename = restart_database.get<std::string>(
"filename_prefix");
1590 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
1593 solution_augmented_ensemble[member].reinit(2);
1596 if (database.get<
unsigned int>(
"sources.n_beams") > 0)
1600 if (assimilate_data)
1602 solution_augmented_ensemble[member]
1603 .block(augmented_state)
1604 .reinit(augmented_state_parameters.size());
1606 for (
unsigned int index = 0; index < augmented_state_parameters.size();
1612 if (augmented_state_parameters.at(index) ==
1615 solution_augmented_ensemble[member].block(augmented_state)[index] =
1616 database_ensemble[member].get<
double>(
1617 "sources.beam_0.absorption_efficiency");
1619 else if (augmented_state_parameters.at(index) ==
1622 solution_augmented_ensemble[member].block(augmented_state)[index] =
1623 database_ensemble[member].get<
double>(
1624 "sources.beam_0.max_power");
1630 solution_augmented_ensemble[member].collect_sizes();
1633 local_communicator, geometry_database, units_optional_database));
1635 boundary_ensemble.push_back(std::make_unique<adamantine::Boundary>(
1637 geometry_ensemble.back()->get_triangulation().get_boundary_ids()));
1639 material_properties_ensemble.push_back(
1641 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>(
1642 local_communicator, geometry_ensemble.back()->get_triangulation(),
1643 material_database));
1645 thermal_physics_ensemble[member] = initialize_thermal_physics<dim>(
1646 fe_degree, quadrature_type, local_communicator,
1647 database_ensemble[member], *geometry_ensemble[member],
1648 *boundary_ensemble[member], *material_properties_ensemble[member]);
1649 heat_sources_ensemble[member] =
1650 thermal_physics_ensemble[member]->get_heat_sources();
1652 if (restart ==
false)
1654 thermal_physics_ensemble[member]->setup();
1655 thermal_physics_ensemble[member]->initialize_dof_vector(
1656 database_ensemble[member].get(
"materials.initial_temperature", 300.),
1657 solution_augmented_ensemble[member].block(base_state));
1661 #ifdef ADAMANTINE_WITH_CALIPER
1662 CALI_MARK_BEGIN(
"restart from file");
1664 thermal_physics_ensemble[member]->load_checkpoint(
1665 restart_filename +
'_' + std::to_string(member),
1666 solution_augmented_ensemble[member].block(base_state));
1667 #ifdef ADAMANTINE_WITH_CALIPER
1668 CALI_MARK_END(
"restart from file");
1671 solution_augmented_ensemble[member].collect_sizes();
1674 post_processor_database.put(
"thermal_output",
true);
1675 post_processor_ensemble.push_back(
1677 local_communicator, post_processor_database,
1678 thermal_physics_ensemble[member]->get_dof_handler(),
1679 first_local_member + member));
1683 boost::property_tree::ptree post_processor_expt_database;
1685 std::string expt_file_prefix =
1686 post_processor_database.get<std::string>(
"filename_prefix") +
".expt";
1687 post_processor_expt_database.put(
"filename_prefix", expt_file_prefix);
1688 post_processor_expt_database.put(
"thermal_output",
true);
1689 std::unique_ptr<adamantine::PostProcessor<dim>> post_processor_expt;
1691 bool const output_experiment_on_mesh =
1692 experiment_optional_database
1693 ? experiment_optional_database->get(
"output_experiment_on_mesh",
true)
1698 if (output_experiment_on_mesh && (my_color == 0))
1700 post_processor_expt = std::make_unique<adamantine::PostProcessor<dim>>(
1701 local_communicator, post_processor_expt_database,
1702 thermal_physics_ensemble[0]->get_dof_handler());
1706 unsigned int progress = 0;
1707 unsigned int n_time_step = 0;
1709 double activation_time_end = -1.;
1710 double da_time = -1.;
1711 if (restart ==
true)
1713 if (global_rank == 0)
1715 std::cout <<
"Restarting from file" << std::endl;
1717 std::ifstream file{restart_filename +
"_time.txt"};
1718 boost::archive::text_iarchive ia{file};
1724 double const activation_time =
1725 geometry_database.get<
double>(
"deposition_time", 0.);
1728 std::vector<std::vector<double>> frame_time_stamps;
1729 std::unique_ptr<adamantine::ExperimentalData<dim>> experimental_data;
1730 unsigned int experimental_frame_index =
1731 std::numeric_limits<unsigned int>::max();
1733 if (experiment_optional_database)
1735 auto experiment_database = experiment_optional_database.get();
1738 bool const read_in_experimental_data =
1739 experiment_database.get(
"read_in_experimental_data",
false);
1741 if (read_in_experimental_data)
1743 if (global_rank == 0)
1744 std::cout <<
"Reading the experimental log file..." << std::endl;
1750 "Experimental data parsing is activated, but "
1751 "the log shows zero cameras.");
1753 "Experimental data parsing is activated, but "
1754 "the log shows zero data frames.");
1756 if (global_rank == 0)
1757 std::cout <<
"Done. Log entries found for " << frame_time_stamps.size()
1758 <<
" camera(s), with " << frame_time_stamps[0].size()
1759 <<
" frame(s)." << std::endl;
1762 std::string experiment_format =
1763 experiment_database.get<std::string>(
"format");
1765 if (boost::iequals(experiment_format,
"point_cloud"))
1767 experimental_data = std::make_unique<adamantine::PointCloud<dim>>(
1772 if constexpr (dim == 3)
1776 experiment_database,
1777 thermal_physics_ensemble[0]->get_dof_handler()));
1784 bool found_frame =
false;
1785 while (!found_frame)
1787 if (frame_time_stamps[0][experimental_frame_index + 1] < time)
1789 experimental_frame_index++;
1802 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>
1804 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
1806 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
1808 output_pvtu(*post_processor_ensemble[member], n_time_step, time,
1809 thermal_physics_ensemble[member],
1810 solution_augmented_ensemble[member].block(base_state),
1811 mechanical_physics, displacement,
1812 *material_properties_ensemble[member], timers);
1820 unsigned int const time_steps_refinement =
1821 refinement_database.get(
"time_steps_between_refinement", 10);
1823 double time_step = time_stepping_database.get<
double>(
"time_step");
1824 double const da_time_half_window = 1.01 * time_step;
1826 bool const scan_path_for_duration =
1827 time_stepping_database.get(
"scan_path_for_duration",
false);
1829 double const duration = scan_path_for_duration
1830 ? std::numeric_limits<double>::max()
1831 : time_stepping_database.get<
double>(
"duration");
1833 unsigned int const time_steps_output =
1834 post_processor_database.get(
"time_steps_between_output", 1);
1836 bool const output_on_da =
1837 post_processor_database.get(
"output_on_data_assimilation",
true);
1844 auto [material_deposition_boxes, deposition_times, deposition_cos,
1846 adamantine::create_material_deposition_boxes<dim>(
1847 geometry_database, heat_sources_ensemble[0]);
1854 auto bounding_heat_sources = adamantine::get_bounding_heat_sources<dim>(
1855 database_ensemble, global_communicator);
1858 if (global_rank == 0)
1859 std::cout <<
"Starting the main time stepping loop..." << std::endl;
1861 #ifdef ADAMANTINE_WITH_CALIPER
1862 CALI_CXX_MARK_LOOP_BEGIN(main_loop_id,
"main_loop");
1864 while (time < duration)
1866 #ifdef ADAMANTINE_WITH_CALIPER
1867 CALI_CXX_MARK_LOOP_ITERATION(main_loop_id, n_time_step - 1);
1869 if ((time + time_step) > duration)
1870 time_step = duration - time;
1875 if ((n_time_step == 1) || ((n_time_step % time_steps_refinement) == 0))
1878 double const next_refinement_time =
1879 time + time_steps_refinement * time_step;
1881 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
1885 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>
1887 refine_mesh(thermal_physics_ensemble[member], dummy,
1888 *material_properties_ensemble[member],
1889 solution_augmented_ensemble[member].block(base_state),
1890 bounding_heat_sources, time, next_refinement_time,
1891 time_steps_refinement, refinement_database);
1892 solution_augmented_ensemble[member].collect_sizes();
1896 if ((global_rank == 0) && (verbose_output ==
true))
1898 std::cout <<
"n_time_step: " << n_time_step <<
" time: " << time
1900 << thermal_physics_ensemble[0]->get_dof_handler().n_dofs()
1909 if (time > activation_time_end)
1913 if (scan_path_for_duration)
1916 bool need_updated_scan_path =
false;
1918 for (
auto &source : heat_sources_ensemble[0])
1921 source->get_scan_path().get_segment_list().back().end_time)
1923 need_updated_scan_path =
true;
1929 if (need_updated_scan_path)
1937 bool scan_path_end =
true;
1938 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
1940 for (
auto &source : heat_sources_ensemble[member])
1942 if (!source->get_scan_path().is_finished())
1944 scan_path_end =
false;
1947 source->get_scan_path().read_file();
1959 std::tie(material_deposition_boxes, deposition_times, deposition_cos,
1961 adamantine::create_material_deposition_boxes<dim>(
1962 geometry_database, heat_sources_ensemble[0]);
1966 double const eps = time_step / 1e10;
1967 auto activation_start =
1968 std::lower_bound(deposition_times.begin(), deposition_times.end(),
1970 deposition_times.begin();
1971 activation_time_end =
1972 std::min(time + std::max(activation_time, time_step), duration) - eps;
1973 auto activation_end =
1974 std::lower_bound(deposition_times.begin(), deposition_times.end(),
1975 activation_time_end) -
1976 deposition_times.begin();
1977 if (activation_start < activation_end)
1979 #ifdef ADAMANTINE_WITH_CALIPER
1980 CALI_MARK_BEGIN(
"add material");
1982 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
1991 thermal_physics_ensemble[member]->get_dof_handler(),
1992 material_deposition_boxes);
1996 std::vector<bool> has_melted(deposition_cos.size(),
false);
1998 thermal_physics_ensemble[member]->add_material_start(
1999 elements_to_activate, deposition_cos, deposition_sin, has_melted,
2000 activation_start, activation_end,
2001 solution_augmented_ensemble[member].block(base_state));
2003 #ifdef ADAMANTINE_WITH_CALIPER
2004 CALI_MARK_BEGIN(
"refine triangulation");
2006 dealii::DoFHandler<dim> &dof_handler =
2007 thermal_physics_ensemble[member]->get_dof_handler();
2008 dealii::parallel::distributed::Triangulation<dim> &triangulation =
2009 dynamic_cast<dealii::parallel::distributed::Triangulation<dim> &
>(
2010 const_cast<dealii::Triangulation<dim> &
>(
2011 dof_handler.get_triangulation()));
2013 triangulation.execute_coarsening_and_refinement();
2014 #ifdef ADAMANTINE_WITH_CALIPER
2015 CALI_MARK_END(
"refine triangulation");
2018 thermal_physics_ensemble[member]->add_material_end(
2019 database_ensemble[member].get(
2020 "materials.new_material_temperature", 300.),
2021 solution_augmented_ensemble[member].block(base_state));
2023 solution_augmented_ensemble[member].collect_sizes();
2025 #ifdef ADAMANTINE_WITH_CALIPER
2026 CALI_MARK_END(
"add material");
2030 if ((global_rank == 0) && (verbose_output ==
true) &&
2031 (activation_end - activation_start > 0))
2033 std::cout <<
"n_time_step: " << n_time_step <<
" time: " << time
2034 <<
" n_dofs after cell activation: "
2035 << thermal_physics_ensemble[0]->get_dof_handler().n_dofs()
2042 double const old_time = time;
2045 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2047 time = thermal_physics_ensemble[member]->evolve_one_time_step(
2048 old_time, time_step,
2049 solution_augmented_ensemble[member].block(base_state), timers);
2054 if (assimilate_data)
2056 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2058 thermal_physics_ensemble[member]->get_affine_constraints().distribute(
2059 solution_augmented_ensemble[member].block(base_state));
2064 double frame_time = std::numeric_limits<double>::max();
2065 if ((experimental_frame_index + 1) < frame_time_stamps[0].size())
2067 if (time > da_time + da_time_half_window)
2069 da_time = frame_time_stamps[0][experimental_frame_index + 1];
2071 if (frame_time_stamps[0][experimental_frame_index + 1] <= time)
2073 experimental_frame_index = experimental_data->read_next_frame();
2074 frame_time = frame_time_stamps[0][experimental_frame_index];
2078 if (frame_time <= time)
2081 frame_time > old_time || n_time_step == 1,
2082 "Unexpectedly missed a data assimilation frame.");
2083 if (global_rank == 0)
2084 std::cout <<
"Performing data assimilation at time " << time <<
"..."
2088 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2090 std::cout <<
"Rank: " << global_rank
2091 <<
" | Old parameters for member "
2092 << first_local_member + member <<
": ";
2093 for (
auto param : solution_augmented_ensemble[member].block(1))
2094 std::cout << param <<
" ";
2096 std::cout << std::endl;
2100 #ifdef ADAMANTINE_WITH_CALIPER
2101 CALI_MARK_BEGIN(
"da_experimental_data");
2103 auto points_values = experimental_data->get_points_values();
2104 auto const &thermal_dof_handler =
2105 thermal_physics_ensemble[0]->get_dof_handler();
2107 points_values, thermal_dof_handler);
2108 std::cout <<
"Rank: " << global_rank
2109 <<
" | Number expt sites mapped to DOFs: "
2110 << expt_to_dof_mapping.first.size() << std::endl;
2111 #ifdef ADAMANTINE_WITH_CALIPER
2112 CALI_MARK_END(
"da_experimental_data");
2116 if (post_processor_expt)
2118 dealii::LA::distributed::Vector<double, MemorySpaceType>
2120 temperature_expt.reinit(
2121 solution_augmented_ensemble[0].block(base_state));
2122 temperature_expt.add(1.0e10);
2124 global_communicator, points_values, expt_to_dof_mapping,
2125 temperature_expt, verbose_output);
2127 thermal_physics_ensemble[0]->get_affine_constraints().distribute(
2130 ->template write_thermal_output<
typename Kokkos::View<
2132 typename MemorySpaceType::kokkos_space>::array_layout>(
2133 n_time_step, time, temperature_expt,
2134 material_properties_ensemble[0]->get_state(),
2135 material_properties_ensemble[0]->get_dofs_map(),
2136 material_properties_ensemble[0]->get_dof_handler());
2141 if (expt_to_dof_mapping.first.size() > 0)
2151 #ifdef ADAMANTINE_WITH_CALIPER
2152 CALI_MARK_BEGIN(
"da_dof_mapping");
2155 #ifdef ADAMANTINE_WITH_CALIPER
2156 CALI_MARK_END(
"da_dof_mapping");
2161 #ifdef ADAMANTINE_WITH_CALIPER
2162 CALI_MARK_BEGIN(
"da_covariance_sparsity");
2165 thermal_dof_handler,
2166 solution_augmented_ensemble[0].block(augmented_state).size());
2167 #ifdef ADAMANTINE_WITH_CALIPER
2168 CALI_MARK_END(
"da_covariance_sparsity");
2172 unsigned int experimental_data_size = points_values.values.size();
2177 #ifdef ADAMANTINE_WITH_CALIPER
2178 CALI_MARK_BEGIN(
"da_obs_covariance");
2180 double variance_entries = experiment_optional_database.get().get(
2181 "estimated_uncertainty", 0.0);
2182 variance_entries = variance_entries * variance_entries;
2184 dealii::SparsityPattern pattern(experimental_data_size,
2185 experimental_data_size, 1);
2186 for (
unsigned int i = 0; i < experimental_data_size; ++i)
2192 dealii::SparseMatrix<double> R(pattern);
2193 for (
unsigned int i = 0; i < experimental_data_size; ++i)
2195 R.add(i, i, variance_entries);
2197 #ifdef ADAMANTINE_WITH_CALIPER
2198 CALI_MARK_END(
"da_obs_covariance");
2204 #ifdef ADAMANTINE_WITH_CALIPER
2205 CALI_MARK_BEGIN(
"da_update_ensemble");
2208 points_values.values, R);
2209 #ifdef ADAMANTINE_WITH_CALIPER
2210 CALI_MARK_END(
"da_update_ensemble");
2215 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2217 for (
unsigned int index = 0;
2218 index < augmented_state_parameters.size(); ++index)
2223 if (augmented_state_parameters.at(index) ==
2226 database_ensemble[member].put(
2227 "sources.beam_0.absorption_efficiency",
2228 solution_augmented_ensemble[member].block(
2229 augmented_state)[index]);
2231 else if (augmented_state_parameters.at(index) ==
2234 database_ensemble[member].put(
2235 "sources.beam_0.max_power",
2236 solution_augmented_ensemble[member].block(
2237 augmented_state)[index]);
2242 if (global_rank == 0)
2243 std::cout <<
"Done." << std::endl;
2246 if (solution_augmented_ensemble[0].block(1).size() > 0)
2248 for (
unsigned int member = 0; member < local_ensemble_size;
2251 std::cout <<
"Rank: " << global_rank
2252 <<
" | New parameters for member "
2253 << first_local_member + member <<
": ";
2254 for (
auto param : solution_augmented_ensemble[member].block(1))
2255 std::cout << param <<
" ";
2257 std::cout << std::endl;
2263 if (global_rank == 0)
2265 <<
"WARNING: NO EXPERIMENTAL DATA POINTS MAPPED ONTO THE "
2266 "SIMULATION MESH. SKIPPING DATA ASSIMILATION OPERATION."
2272 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2274 thermal_physics_ensemble[member]->update_physics_parameters(
2275 database_ensemble[member].get_child(
"sources"));
2280 if (n_time_step % time_steps_checkpoint == 0)
2282 #ifdef ADAMANTINE_WITH_CALIPER
2283 CALI_MARK_BEGIN(
"save checkpoint");
2285 if (global_rank == 0)
2287 std::cout <<
"Checkpoint reached" << std::endl;
2290 std::string output_dir =
2291 post_processor_database.get<std::string>(
"output_dir",
"");
2292 std::string filename_prefix =
2293 checkpoint_overwrite
2294 ? checkpoint_filename
2295 : checkpoint_filename +
'_' + std::to_string(n_time_step);
2296 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2298 thermal_physics_ensemble[member]->save_checkpoint(
2299 filename_prefix +
'_' + std::to_string(first_local_member + member),
2300 solution_augmented_ensemble[member].block(base_state));
2302 std::ofstream file{output_dir + filename_prefix +
"_time.txt"};
2303 boost::archive::text_oarchive oa{file};
2306 #ifdef ADAMANTINE_WITH_CALIPER
2307 CALI_MARK_END(
"save checkpoint");
2312 if (global_rank == 0)
2314 double adim_time = time / (duration / 10.);
2315 double int_part = 0;
2316 std::modf(adim_time, &int_part);
2317 if (int_part > progress)
2319 std::cout << int_part * 10 <<
'%' <<
" completed" << std::endl;
2325 if ((n_time_step % time_steps_output == 0) ||
2326 (output_on_da && time > (da_time - da_time_half_window) &&
2327 time < (da_time + da_time_half_window)))
2329 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2331 thermal_physics_ensemble[member]->set_state_to_material_properties();
2332 output_pvtu(*post_processor_ensemble[member], n_time_step, time,
2333 thermal_physics_ensemble[member],
2334 solution_augmented_ensemble[member].block(base_state),
2335 mechanical_physics, displacement,
2336 *material_properties_ensemble[member], timers);
2343 #ifdef ADAMANTINE_WITH_CALIPER
2344 CALI_CXX_MARK_LOOP_END(main_loop_id);
2347 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2349 post_processor_ensemble[member]->write_pvd();
2353 if constexpr (std::is_same_v<MemorySpaceType, dealii::MemorySpace::Host>)
2355 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2357 thermal_physics_ensemble[member]->get_affine_constraints().distribute(
2358 solution_augmented_ensemble[member].block(base_state));
2360 return solution_augmented_ensemble;
2366 std::vector<dealii::LA::distributed::BlockVector<double>>
2367 solution_augmented_ensemble_host(local_ensemble_size);
2369 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2371 solution_augmented_ensemble[member].reinit(2);
2373 solution_augmented_ensemble_host[member].block(0).reinit(
2374 solution_augmented_ensemble[member].block(0).get_partitioner());
2376 solution_augmented_ensemble_host[member].block(0).import(
2377 solution_augmented_ensemble[member].block(0),
2378 dealii::VectorOperation::insert);
2379 thermal_physics_ensemble[member]->get_affine_constraints().distribute(
2380 solution_augmented_ensemble_host[member].block(0));
2382 solution_augmented_ensemble_host[member].block(1).reinit(
2383 solution_augmented_ensemble[member].block(0).get_partitioner());
2385 solution_augmented_ensemble_host[member].block(1).import(
2386 solution_augmented_ensemble[member].block(1),
2387 dealii::VectorOperation::insert);
2390 return solution_augmented_ensemble_host;
std::vector< dealii::LA::distributed::BlockVector< double > > run_ensemble(MPI_Comm const &global_communicator, boost::property_tree::ptree const &database, std::vector< adamantine::Timer > &timers)
std::vector< typename dealii::parallel::distributed::Triangulation< dim >::active_cell_iterator > compute_cells_to_refine(dealii::parallel::distributed::Triangulation< dim > &triangulation, double const time, double const next_refinement_time, unsigned int const n_time_steps, std::vector< std::shared_ptr< adamantine::HeatSource< dim >>> const &heat_sources)
void refine_and_transfer(std::unique_ptr< adamantine::ThermalPhysicsInterface< dim, MemorySpaceType >> &thermal_physics, std::unique_ptr< adamantine::MechanicalPhysics< dim, n_materials, p_order, MaterialStates, MemorySpaceType >> &mechanical_physics, adamantine::MaterialProperty< dim, n_materials, p_order, MaterialStates, MemorySpaceType > &material_properties, dealii::DoFHandler< dim > &dof_handler, dealii::LA::distributed::Vector< double, MemorySpaceType > &solution)
void split_global_communicator(MPI_Comm global_communicator, unsigned int global_ensemble_size, MPI_Comm &local_communicator, unsigned int &local_ensemble_size, unsigned int &first_local_member, int &my_color)
std::unique_ptr< adamantine::ThermalPhysicsInterface< dim, MemorySpaceType > > initialize_thermal_physics(unsigned int fe_degree, std::string const &quadrature_type, MPI_Comm const &communicator, boost::property_tree::ptree const &database, adamantine::Geometry< dim > &geometry, adamantine::Boundary const &boundary, adamantine::MaterialProperty< dim, n_materials, p_order, MaterialStates, MemorySpaceType > &material_properties)
std::unique_ptr< adamantine::ThermalPhysicsInterface< dim, MemorySpaceType > > initialize(MPI_Comm const &communicator, boost::property_tree::ptree const &database, adamantine::Geometry< dim > &geometry, adamantine::Boundary const &boundary, adamantine::MaterialProperty< dim, n_materials, p_order, MaterialStates, MemorySpaceType > &material_properties)
void output_pvtu(adamantine::PostProcessor< dim > &post_processor, unsigned int n_time_step, double time, std::unique_ptr< adamantine::ThermalPhysicsInterface< dim, MemorySpaceType >> const &thermal_physics, dealii::LinearAlgebra::distributed::Vector< double, MemorySpaceType > &temperature, std::unique_ptr< adamantine::MechanicalPhysics< dim, n_materials, p_order, MaterialStates, MemorySpaceType >> const &mechanical_physics, dealii::LA::distributed::Vector< double, dealii::MemorySpace::Host > &displacement, adamantine::MaterialProperty< dim, n_materials, p_order, MaterialStates, MemorySpaceType > const &material_properties, std::vector< adamantine::Timer > &timers)
void refine_mesh(std::unique_ptr< adamantine::ThermalPhysicsInterface< dim, MemorySpaceType >> &thermal_physics, std::unique_ptr< adamantine::MechanicalPhysics< dim, n_materials, p_order, MaterialStates, MemorySpaceType >> &mechanical_physics, adamantine::MaterialProperty< dim, n_materials, p_order, MaterialStates, MemorySpaceType > &material_properties, dealii::LA::distributed::Vector< double, MemorySpaceType > &solution, std::vector< std::shared_ptr< adamantine::HeatSource< dim >>> const &heat_sources, double const time, double const next_refinement_time, unsigned int const time_steps_refinement, boost::property_tree::ptree const &refinement_database)
void initialize_timers(MPI_Comm const &communicator, std::vector< adamantine::Timer > &timers)
std::pair< dealii::LinearAlgebra::distributed::Vector< double, dealii::MemorySpace::Host >, dealii::LinearAlgebra::distributed::Vector< double, dealii::MemorySpace::Host > > run(MPI_Comm const &communicator, boost::property_tree::ptree const &database, std::vector< adamantine::Timer > &timers)
std::unique_ptr< adamantine::ThermalPhysicsInterface< dim, MemorySpaceType > > initialize_quadrature(std::string const &quadrature_type, MPI_Comm const &communicator, boost::property_tree::ptree const &database, adamantine::Geometry< dim > &geometry, adamantine::Boundary const &boundary, adamantine::MaterialProperty< dim, n_materials, p_order, MaterialStates, MemorySpaceType > &material_properties)
void update_dof_mapping(std::pair< std::vector< int >, std::vector< int >> const &expt_to_dof_mapping)
void update_covariance_sparsity_pattern(dealii::DoFHandler< dim > const &dof_handler, const unsigned int parameter_size)
void update_ensemble(std::vector< dealii::LA::distributed::BlockVector< double >> &augmented_state_ensemble, std::vector< double > const &expt_data, dealii::SparseMatrix< double > const &R)
dealii::parallel::distributed::Triangulation< dim > & get_triangulation()
double get(dealii::types::material_id material_id, Property prop) const
std::pair< std::vector< int >, std::vector< int > > get_expt_to_dof_mapping(PointsValues< dim > const &points_values, dealii::DoFHandler< dim > const &dof_handler)
std::vector< boost::property_tree::ptree > create_database_ensemble(boost::property_tree::ptree const &database, MPI_Comm local_communicator, unsigned int first_local_member, unsigned int local_ensemble_size, unsigned int global_ensemble_size)
void ASSERT_THROW(bool cond, std::string const &message)
std::vector< std::vector< typename dealii::DoFHandler< dim >::active_cell_iterator > > get_elements_to_activate(dealii::DoFHandler< dim > const &dof_handler, std::vector< dealii::BoundingBox< dim >> const &material_deposition_boxes)
void set_with_experimental_data(MPI_Comm const &communicator, PointsValues< dim > const &points_values, std::pair< std::vector< int >, std::vector< int >> &expt_to_dof_mapping, dealii::LinearAlgebra::distributed::Vector< double > &temperature, bool verbose_output)
std::vector< std::vector< double > > read_frame_timestamps(boost::property_tree::ptree const &experiment_database)
#define ASSERT(condition, message)