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 #if DEAL_II_VERSION_GTE(9, 7, 0) && defined(DEAL_II_TRILINOS_WITH_TPETRA)
37 #include <deal.II/lac/trilinos_tpetra_sparse_matrix.h>
39 #include <deal.II/lac/trilinos_sparse_matrix.h>
41 #include <deal.II/lac/vector_operation.h>
42 #include <deal.II/numerics/error_estimator.h>
44 #include <boost/algorithm/string.hpp>
45 #include <boost/archive/text_iarchive.hpp>
46 #include <boost/archive/text_oarchive.hpp>
47 #include <boost/property_tree/ptree.hpp>
53 #include <type_traits>
54 #include <unordered_map>
56 #ifdef ADAMANTINE_WITH_CALIPER
57 #include <caliper/cali.h>
63 template <
int dim,
int n_materials,
int p_order,
typename MaterialStates,
64 typename MemorySpaceType,
66 std::is_same<MemorySpaceType, dealii::MemorySpace::Host>::value,
74 dealii::LinearAlgebra::distributed::Vector<double, MemorySpaceType>
77 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>
const
79 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
82 MemorySpaceType>
const &material_properties,
83 std::vector<adamantine::Timer> &timers)
85 #ifdef ADAMANTINE_WITH_CALIPER
86 CALI_CXX_MARK_FUNCTION;
91 thermal_physics->get_affine_constraints().distribute(temperature);
92 if (mechanical_physics)
94 mechanical_physics->get_affine_constraints().distribute(displacement);
95 post_processor.template write_output<
typename Kokkos::View<
96 double **,
typename MemorySpaceType::kokkos_space>::array_layout>(
97 n_time_step, time, temperature, displacement,
98 mechanical_physics->get_stress_tensor(),
99 material_properties.get_state(), material_properties.get_dofs_map(),
100 material_properties.get_dof_handler());
104 post_processor.template write_thermal_output<
typename Kokkos::View<
105 double **,
typename MemorySpaceType::kokkos_space>::array_layout>(
106 n_time_step, time, temperature, material_properties.get_state(),
107 material_properties.get_dofs_map(),
108 material_properties.get_dof_handler());
113 mechanical_physics->get_affine_constraints().distribute(displacement);
114 post_processor.template write_mechanical_output<
typename Kokkos::View<
115 double **,
typename MemorySpaceType::kokkos_space>::array_layout>(
116 n_time_step, time, displacement,
117 mechanical_physics->get_stress_tensor(),
118 material_properties.get_state(), material_properties.get_dofs_map(),
119 material_properties.get_dof_handler());
124 template <
int dim,
int n_materials,
int p_order,
typename MaterialStates,
125 typename MemorySpaceType,
126 std::enable_if_t<std::is_same<MemorySpaceType,
127 dealii::MemorySpace::Default>::value,
135 dealii::LinearAlgebra::distributed::Vector<double, MemorySpaceType>
138 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>
const
140 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
143 MemorySpaceType>
const &material_properties,
144 std::vector<adamantine::Timer> &timers)
146 #ifdef ADAMANTINE_WITH_CALIPER
147 CALI_CXX_MARK_FUNCTION;
150 auto state = material_properties.get_state();
151 auto state_host = Kokkos::create_mirror_view_and_copy(
152 dealii::MemorySpace::Host::kokkos_space{}, state);
155 dealii::LinearAlgebra::distributed::Vector<double,
156 dealii::MemorySpace::Host>
157 temperature_host(temperature.get_partitioner());
158 temperature_host.import_elements(temperature,
159 dealii::VectorOperation::insert);
160 thermal_physics->get_affine_constraints().distribute(temperature_host);
161 if (mechanical_physics)
163 mechanical_physics->get_affine_constraints().distribute(displacement);
164 post_processor.template write_output<
typename Kokkos::View<
165 double **,
typename MemorySpaceType::kokkos_space>::array_layout>(
166 n_time_step, time, temperature_host, displacement,
167 mechanical_physics->get_stress_tensor(), state_host,
168 material_properties.get_dofs_map(),
169 material_properties.get_dof_handler());
173 post_processor.template write_thermal_output<
typename Kokkos::View<
174 double **,
typename MemorySpaceType::kokkos_space>::array_layout>(
175 n_time_step, time, temperature_host, state_host,
176 material_properties.get_dofs_map(),
177 material_properties.get_dof_handler());
182 mechanical_physics->get_affine_constraints().distribute(displacement);
183 post_processor.template write_mechanical_output<
typename Kokkos::View<
184 double **,
typename MemorySpaceType::kokkos_space>::array_layout>(
185 n_time_step, time, displacement,
186 mechanical_physics->get_stress_tensor(), state_host,
187 material_properties.get_dofs_map(),
188 material_properties.get_dof_handler());
195 std::vector<adamantine::Timer> &timers)
213 communicator,
"Evolve One Time Step: evaluate_thermal_physics"));
215 communicator,
"Evolve One Time Step: evaluate_material_properties"));
219 template <
int dim,
int n_materials,
int p_order,
int fe_degree,
220 typename MaterialStates,
typename MemorySpaceType,
221 typename QuadratureType>
222 std::unique_ptr<adamantine::ThermalPhysicsInterface<dim, MemorySpaceType>>
224 MPI_Comm
const &communicator, boost::property_tree::ptree
const &database,
227 MemorySpaceType> &material_properties)
230 dim, n_materials, p_order, fe_degree, MaterialStates, MemorySpaceType,
231 QuadratureType>>(communicator, database, geometry, boundary,
232 material_properties);
235 template <
int dim,
int n_materials,
int p_order,
int fe_degree,
236 typename MaterialStates,
typename MemorySpaceType>
237 std::unique_ptr<adamantine::ThermalPhysicsInterface<dim, MemorySpaceType>>
239 std::string
const &quadrature_type, MPI_Comm
const &communicator,
240 boost::property_tree::ptree
const &database,
243 MemorySpaceType> &material_properties)
245 if (quadrature_type.compare(
"gauss") == 0)
246 return initialize<dim, n_materials, p_order, fe_degree, MaterialStates,
247 MemorySpaceType, dealii::QGauss<1>>(
248 communicator, database, geometry, boundary, material_properties);
252 "quadrature should be Gauss or Lobatto.");
253 return initialize<dim, n_materials, p_order, fe_degree, MaterialStates,
254 MemorySpaceType, dealii::QGaussLobatto<1>>(
255 communicator, database, geometry, boundary, material_properties);
259 template <
int dim,
int n_materials,
int p_order,
typename MaterialStates,
260 typename MemorySpaceType>
261 std::unique_ptr<adamantine::ThermalPhysicsInterface<dim, MemorySpaceType>>
263 unsigned int fe_degree, std::string
const &quadrature_type,
264 MPI_Comm
const &communicator, boost::property_tree::ptree
const &database,
267 MemorySpaceType> &material_properties)
274 MemorySpaceType>(quadrature_type, communicator,
275 database, geometry, boundary,
276 material_properties);
281 MemorySpaceType>(quadrature_type, communicator,
282 database, geometry, boundary,
283 material_properties);
288 MemorySpaceType>(quadrature_type, communicator,
289 database, geometry, boundary,
290 material_properties);
295 MemorySpaceType>(quadrature_type, communicator,
296 database, geometry, boundary,
297 material_properties);
302 "fe_degree should be between 1 and 5.");
304 MemorySpaceType>(quadrature_type, communicator,
305 database, geometry, boundary,
306 material_properties);
311 template <
int dim,
int n_materials,
int p_order,
typename MaterialStates,
312 typename MemorySpaceType>
317 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>
320 MemorySpaceType> &material_properties,
321 dealii::DoFHandler<dim> &dof_handler,
322 dealii::LA::distributed::Vector<double, MemorySpaceType> &solution)
324 #ifdef ADAMANTINE_WITH_CALIPER
325 CALI_CXX_MARK_FUNCTION;
328 dealii::parallel::distributed::Triangulation<dim> &triangulation =
329 dynamic_cast<dealii::parallel::distributed::Triangulation<dim> &
>(
330 const_cast<dealii::Triangulation<dim> &
>(
331 dof_handler.get_triangulation()));
336 thermal_physics->set_state_to_material_properties();
339 #if DEAL_II_VERSION_GTE(9, 7, 0)
340 dealii::SolutionTransfer<
342 dealii::parallel::distributed::SolutionTransfer<
344 dim, dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>>
345 solution_transfer(dof_handler);
348 unsigned int const direction_data_size = 2;
349 unsigned int const phase_history_data_size = 1;
350 unsigned int constexpr n_material_states = MaterialStates::n_material_states;
351 std::vector<std::vector<double>> data_to_transfer;
352 std::vector<double> dummy_cell_data(n_material_states + direction_data_size +
353 phase_history_data_size,
354 std::numeric_limits<double>::infinity());
355 auto state_host = Kokkos::create_mirror_view_and_copy(
356 Kokkos::HostSpace{}, material_properties.get_state());
357 unsigned int cell_id = 0;
358 unsigned int activated_cell_id = 0;
359 for (
auto const &cell : dof_handler.active_cell_iterators())
361 if (cell->is_locally_owned())
363 std::vector<double> cell_data(n_material_states + direction_data_size +
364 phase_history_data_size);
365 for (
unsigned int i = 0; i < n_material_states; ++i)
366 cell_data[i] = state_host(i, cell_id);
367 if (cell->active_fe_index() == 0)
369 cell_data[n_material_states] =
370 thermal_physics->get_deposition_cos(activated_cell_id);
371 cell_data[n_material_states + 1] =
372 thermal_physics->get_deposition_sin(activated_cell_id);
374 if (thermal_physics->get_has_melted(activated_cell_id))
375 cell_data[n_material_states + direction_data_size] = 1.0;
377 cell_data[n_material_states + direction_data_size] = 0.0;
383 cell_data[n_material_states] = std::numeric_limits<double>::infinity();
384 cell_data[n_material_states + 1] =
385 std::numeric_limits<double>::infinity();
386 cell_data[n_material_states + direction_data_size] =
387 std::numeric_limits<double>::infinity();
389 data_to_transfer.push_back(cell_data);
394 data_to_transfer.push_back(dummy_cell_data);
400 triangulation.prepare_coarsening_and_refinement();
402 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
404 if constexpr (std::is_same_v<MemorySpaceType, dealii::MemorySpace::Host>)
407 thermal_physics->get_affine_constraints().distribute(solution);
410 solution.update_ghost_values();
411 solution_transfer.prepare_for_coarsening_and_refinement(solution);
415 solution_host.reinit(solution.get_partitioner());
416 solution_host.import_elements(solution, dealii::VectorOperation::insert);
418 thermal_physics->get_affine_constraints().distribute(solution_host);
421 solution_host.update_ghost_values();
422 solution_transfer.prepare_for_coarsening_and_refinement(solution_host);
425 dealii::parallel::distributed::CellDataTransfer<
426 dim, dim, std::vector<std::vector<double>>>
427 cell_data_trans(triangulation);
428 cell_data_trans.prepare_for_coarsening_and_refinement(data_to_transfer);
430 if (mechanical_physics)
432 mechanical_physics->prepare_transfer_mpi();
435 #ifdef ADAMANTINE_WITH_CALIPER
436 CALI_MARK_BEGIN(
"refine triangulation");
439 triangulation.execute_coarsening_and_refinement();
440 #ifdef ADAMANTINE_WITH_CALIPER
441 CALI_MARK_END(
"refine triangulation");
445 thermal_physics->setup_dofs();
446 thermal_physics->initialize_dof_vector(0., solution);
449 material_properties.reinit_dofs();
452 if constexpr (std::is_same_v<MemorySpaceType, dealii::MemorySpace::Host>)
454 solution_transfer.interpolate(solution);
458 solution_host.reinit(solution.get_partitioner());
459 solution_transfer.interpolate(solution_host);
460 solution.import_elements(solution_host, dealii::VectorOperation::insert);
464 std::vector<std::vector<double>> transferred_data(
465 triangulation.n_active_cells(),
466 std::vector<double>(n_material_states + direction_data_size +
467 phase_history_data_size));
468 cell_data_trans.unpack(transferred_data);
469 auto state = material_properties.get_state();
470 state_host = Kokkos::create_mirror_view(state);
471 unsigned int total_cell_id = 0;
473 std::vector<double> transferred_cos;
474 std::vector<double> transferred_sin;
475 std::vector<bool> has_melted;
476 for (
auto const &cell : dof_handler.active_cell_iterators())
478 if (cell->is_locally_owned())
480 for (
unsigned int i = 0; i < n_material_states; ++i)
482 state_host(i, cell_id) = transferred_data[total_cell_id][i];
484 if (cell->active_fe_index() == 0)
486 transferred_cos.push_back(
487 transferred_data[total_cell_id][n_material_states]);
488 transferred_sin.push_back(
489 transferred_data[total_cell_id][n_material_states + 1]);
492 if (transferred_data[total_cell_id]
493 [n_material_states + direction_data_size] > 0.5)
494 has_melted.push_back(
true);
496 has_melted.push_back(
false);
504 thermal_physics->set_material_deposition_orientation(transferred_cos,
508 thermal_physics->set_has_melted_vector(has_melted);
511 Kokkos::deep_copy(state, state_host);
514 thermal_physics->get_state_from_material_properties();
519 for (
auto const &cell : dof_handler.active_cell_iterators())
521 if (cell->is_locally_owned())
523 double material_ratio = 0.;
524 for (
unsigned int i = 0; i < n_material_states; ++i)
526 material_ratio += state_host(i, cell_id);
528 ASSERT(std::abs(material_ratio - 1.) < 1e-14,
"Material is lost.");
534 if (mechanical_physics)
536 mechanical_physics->complete_transfer_mpi();
541 std::vector<
typename dealii::parallel::distributed::Triangulation<
542 dim>::active_cell_iterator>
544 dealii::parallel::distributed::Triangulation<dim> &triangulation,
545 double const time,
double const next_refinement_time,
546 unsigned int const n_time_steps,
554 std::vector<dealii::BoundingBox<dim>> cell_bounding_boxes;
555 cell_bounding_boxes.reserve(triangulation.n_locally_owned_active_cells());
556 for (
auto const &cell : triangulation.active_cell_iterators() |
557 dealii::IteratorFilters::LocallyOwnedCell())
559 cell_bounding_boxes.push_back(cell->bounding_box());
561 dealii::ArborXWrappers::BVH bvh(cell_bounding_boxes);
563 double const bounding_box_scaling = 2.0;
564 std::vector<dealii::BoundingBox<dim>> heat_source_bounding_boxes;
565 heat_source_bounding_boxes.reserve(n_time_steps * heat_sources.size());
566 for (
unsigned int i = 0; i < n_time_steps; ++i)
568 double const current_time = time +
static_cast<double>(i) /
569 static_cast<double>(n_time_steps) *
570 (next_refinement_time - time);
573 for (
auto &beam : heat_sources)
575 heat_source_bounding_boxes.push_back(
576 beam->get_bounding_box(current_time, bounding_box_scaling));
582 dealii::ArborXWrappers::BoundingBoxIntersectPredicate bb_intersect(
583 heat_source_bounding_boxes);
584 auto [indices, offset] = bvh.query(bb_intersect);
588 std::unordered_set<int> indices_to_refine;
589 indices_to_refine.insert(indices.begin(), indices.end());
591 std::vector<
typename dealii::parallel::distributed::Triangulation<
592 dim>::active_cell_iterator>
595 for (
auto const &cell : triangulation.active_cell_iterators() |
596 dealii::IteratorFilters::LocallyOwnedCell())
598 if (indices_to_refine.count(cell_index))
600 cells_to_refine.push_back(cell);
605 return cells_to_refine;
608 template <
int dim,
int n_materials,
int p_order,
int fe_degree,
609 typename MaterialStates,
typename MemorySpaceType>
614 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>
617 MemorySpaceType> &material_properties,
618 dealii::LA::distributed::Vector<double, MemorySpaceType> &solution,
621 double const time,
double const next_refinement_time,
622 unsigned int const time_steps_refinement,
623 boost::property_tree::ptree
const &refinement_database)
625 #ifdef ADAMANTINE_WITH_CALIPER
626 CALI_CXX_MARK_FUNCTION;
628 dealii::DoFHandler<dim> &dof_handler = thermal_physics->get_dof_handler();
629 dealii::parallel::distributed::Triangulation<dim> &triangulation =
630 dynamic_cast<dealii::parallel::distributed::Triangulation<dim> &
>(
631 const_cast<dealii::Triangulation<dim> &
>(
632 dof_handler.get_triangulation()));
635 unsigned int const n_refinements =
636 refinement_database.get(
"n_refinements", 2);
638 for (
unsigned int i = 0; i < n_refinements; ++i)
641 auto cells_to_refine =
643 time_steps_refinement, heat_sources);
646 const bool coarsen_after_beam =
647 refinement_database.get<
bool>(
"coarsen_after_beam",
false);
650 if (coarsen_after_beam)
652 for (
auto cell : dealii::filter_iterators(
653 triangulation.active_cell_iterators(),
654 dealii::IteratorFilters::LocallyOwnedCell()))
656 if (cell->level() > 0)
657 cell->set_coarsen_flag();
662 for (
auto &cell : cells_to_refine)
664 if (coarsen_after_beam)
665 cell->clear_coarsen_flag();
667 if (cell->level() <
static_cast<int>(n_refinements))
668 cell->set_refine_flag();
673 material_properties, dof_handler, solution);
677 thermal_physics->compute_inverse_mass_matrix();
680 template <
int dim,
int n_materials,
int p_order,
typename MaterialStates,
681 typename MemorySpaceType>
686 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>
689 MemorySpaceType> &material_properties,
690 dealii::LA::distributed::Vector<double, MemorySpaceType> &solution,
693 double const time,
double const next_refinement_time,
694 unsigned int const time_steps_refinement,
695 boost::property_tree::ptree
const &refinement_database)
697 if (!thermal_physics)
700 switch (thermal_physics->get_fe_degree())
704 refine_mesh<dim, n_materials, p_order, 1, MaterialStates>(
705 thermal_physics, mechanical_physics, material_properties, solution,
706 heat_sources, time, next_refinement_time, time_steps_refinement,
707 refinement_database);
712 refine_mesh<dim, n_materials, p_order, 2, MaterialStates>(
713 thermal_physics, mechanical_physics, material_properties, solution,
714 heat_sources, time, next_refinement_time, time_steps_refinement,
715 refinement_database);
720 refine_mesh<dim, n_materials, p_order, 3, MaterialStates>(
721 thermal_physics, mechanical_physics, material_properties, solution,
722 heat_sources, time, next_refinement_time, time_steps_refinement,
723 refinement_database);
728 refine_mesh<dim, n_materials, p_order, 4, MaterialStates>(
729 thermal_physics, mechanical_physics, material_properties, solution,
730 heat_sources, time, next_refinement_time, time_steps_refinement,
731 refinement_database);
736 refine_mesh<dim, n_materials, p_order, 5, MaterialStates>(
737 thermal_physics, mechanical_physics, material_properties, solution,
738 heat_sources, time, next_refinement_time, time_steps_refinement,
739 refinement_database);
749 template <
int dim,
int n_materials,
int p_order,
typename MaterialStates,
750 typename MemorySpaceType>
751 std::pair<dealii::LinearAlgebra::distributed::Vector<double,
752 dealii::MemorySpace::Host>,
753 dealii::LinearAlgebra::distributed::Vector<double,
754 dealii::MemorySpace::Host>>
755 run(MPI_Comm
const &communicator, boost::property_tree::ptree
const &database,
756 std::vector<adamantine::Timer> &timers)
758 #ifdef ADAMANTINE_WITH_CALIPER
759 CALI_CXX_MARK_FUNCTION;
762 boost::optional<boost::property_tree::ptree const &> units_optional_database =
763 database.get_child_optional(
"units");
766 boost::property_tree::ptree geometry_database =
767 database.get_child(
"geometry");
769 units_optional_database);
772 boost::property_tree::ptree material_database =
773 database.get_child(
"materials");
780 boost::property_tree::ptree physics_database = database.get_child(
"physics");
781 bool const use_thermal_physics = physics_database.get<
bool>(
"thermal");
782 bool const use_mechanical_physics = physics_database.get<
bool>(
"mechanical");
785 boost::property_tree::ptree discretization_database =
786 database.get_child(
"discretization");
789 boost::property_tree::ptree post_processor_database =
790 database.get_child(
"post_processor");
794 bool const verbose_output = database.get(
"verbose_output",
false);
797 boost::property_tree::ptree boundary_database =
798 database.get_child(
"boundary");
803 std::unique_ptr<adamantine::ThermalPhysicsInterface<dim, MemorySpaceType>>
805 std::vector<std::shared_ptr<adamantine::HeatSource<dim>>> heat_sources;
806 if (use_thermal_physics)
809 unsigned int const fe_degree =
810 discretization_database.get<
unsigned int>(
"thermal.fe_degree");
812 std::string quadrature_type =
813 discretization_database.get(
"thermal.quadrature",
"gauss");
814 thermal_physics = initialize_thermal_physics<dim>(
815 fe_degree, quadrature_type, communicator, database, geometry, boundary,
816 material_properties);
817 heat_sources = thermal_physics->get_heat_sources();
818 post_processor_database.put(
"thermal_output",
true);
822 double const initial_temperature =
823 material_database.get(
"initial_temperature", 300.);
827 std::vector<double> material_reference_temps;
829 unsigned int const n_materials_runtime =
830 material_database.get<
unsigned int>(
"n_materials");
831 for (
unsigned int i = 0; i < n_materials_runtime; ++i)
836 double const reference_temperature = material_database.get<
double>(
837 "material_" + std::to_string(i) +
".solidus");
838 material_reference_temps.push_back(reference_temperature);
840 material_reference_temps.push_back(initial_temperature);
844 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>
846 if (use_mechanical_physics)
849 unsigned int const fe_degree =
850 discretization_database.
get<
unsigned int>(
"mechanical.fe_degree");
852 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>(
853 communicator, fe_degree, geometry, boundary, material_properties,
854 material_reference_temps);
855 post_processor_database.put(
"mechanical_output",
true);
859 std::unique_ptr<adamantine::PostProcessor<dim>> post_processor;
860 bool thermal_output = post_processor_database.get(
"thermal_output",
false);
861 bool mechanical_output =
862 post_processor_database.get(
"mechanical_output",
false);
863 if ((thermal_output) && (mechanical_output))
865 post_processor = std::make_unique<adamantine::PostProcessor<dim>>(
866 communicator, post_processor_database,
867 thermal_physics->get_dof_handler(),
868 mechanical_physics->get_dof_handler());
872 post_processor = std::make_unique<adamantine::PostProcessor<dim>>(
873 communicator, post_processor_database,
874 thermal_output ? thermal_physics->get_dof_handler()
875 : mechanical_physics->get_dof_handler());
879 boost::optional<boost::property_tree::ptree const &>
880 checkpoint_optional_database = database.get_child_optional(
"checkpoint");
881 boost::optional<boost::property_tree::ptree const &>
882 restart_optional_database = database.get_child_optional(
"restart");
884 unsigned int time_steps_checkpoint = std::numeric_limits<unsigned int>::max();
885 std::string checkpoint_filename;
886 bool checkpoint_overwrite =
true;
887 if (checkpoint_optional_database)
889 auto checkpoint_database = checkpoint_optional_database.get();
891 time_steps_checkpoint =
892 checkpoint_database.get<
unsigned int>(
"time_steps_between_checkpoint");
894 checkpoint_filename =
895 checkpoint_database.get<std::string>(
"filename_prefix");
897 checkpoint_overwrite = checkpoint_database.get<
bool>(
"overwrite_files");
900 bool restart =
false;
901 std::string restart_filename;
902 if (restart_optional_database)
905 auto restart_database = restart_optional_database.get();
907 restart_filename = restart_database.get<std::string>(
"filename_prefix");
910 dealii::LA::distributed::Vector<double, MemorySpaceType> temperature;
911 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
913 if (use_thermal_physics)
915 if (restart ==
false)
917 thermal_physics->setup();
918 thermal_physics->initialize_dof_vector(initial_temperature, temperature);
922 #ifdef ADAMANTINE_WITH_CALIPER
923 CALI_MARK_BEGIN(
"restart from file");
925 thermal_physics->load_checkpoint(restart_filename, temperature);
926 #ifdef ADAMANTINE_WITH_CALIPER
927 CALI_MARK_END(
"restart from file");
932 if (use_mechanical_physics)
937 "Mechanical simulation cannot be restarted from a file");
938 if (use_thermal_physics)
941 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
942 temperature_host(temperature.get_partitioner());
943 temperature_host.import_elements(temperature,
944 dealii::VectorOperation::insert);
945 mechanical_physics->setup_dofs(thermal_physics->get_dof_handler(),
947 thermal_physics->get_has_melted_vector());
952 mechanical_physics->setup_dofs();
954 displacement = mechanical_physics->solve();
957 unsigned int progress = 0;
958 unsigned int n_time_step = 0;
960 double activation_time_end = -1.;
961 unsigned int const rank =
962 dealii::Utilities::MPI::this_mpi_process(communicator);
967 std::cout <<
"Restarting from file" << std::endl;
969 std::ifstream file{restart_filename +
"_time.txt"};
970 boost::archive::text_iarchive ia{file};
975 double const activation_time =
976 geometry_database.get<
double>(
"deposition_time", 0.);
979 output_pvtu(*post_processor, n_time_step, time, thermal_physics, temperature,
980 mechanical_physics, displacement, material_properties, timers);
984 auto [material_deposition_boxes, deposition_times, deposition_cos,
986 adamantine::create_material_deposition_boxes<dim>(geometry_database,
989 boost::property_tree::ptree time_stepping_database =
990 database.get_child(
"time_stepping");
992 double time_step = time_stepping_database.get<
double>(
"time_step");
994 unsigned int const mechanical_time_step_factor =
995 time_stepping_database.get<
unsigned int>(
"mechanical_time_step_factor",
998 bool const scan_path_for_duration =
999 time_stepping_database.get(
"scan_path_for_duration",
false);
1001 double const duration = scan_path_for_duration
1002 ? std::numeric_limits<double>::max()
1003 : time_stepping_database.get<
double>(
"duration");
1006 boost::property_tree::ptree refinement_database =
1007 database.get_child(
"refinement");
1009 unsigned int const time_steps_refinement =
1010 refinement_database.get(
"time_steps_between_refinement", 10);
1012 unsigned int const time_steps_output =
1013 post_processor_database.get(
"time_steps_between_output", 1);
1015 double const new_material_temperature =
1016 database.get(
"materials.new_material_temperature", 300.);
1019 boost::optional<boost::property_tree::ptree const &>
1020 microstructure_optional_database =
1021 database.get_child_optional(
"microstructure");
1022 bool const compute_microstructure =
1023 microstructure_optional_database ? true :
false;
1024 std::unique_ptr<adamantine::Microstructure<dim>> microstructure;
1025 if (compute_microstructure)
1027 auto microstructure_database = microstructure_optional_database.get();
1029 std::string microstructure_filename =
1030 microstructure_database.get<std::string>(
"filename_prefix");
1031 microstructure = std::make_unique<adamantine::Microstructure<dim>>(
1032 communicator, microstructure_filename);
1035 bool rebuild_mechanical_matrix =
true;
1037 #ifdef ADAMANTINE_WITH_CALIPER
1038 CALI_CXX_MARK_LOOP_BEGIN(main_loop_id,
"main_loop");
1040 while (time < duration)
1042 #ifdef ADAMANTINE_WITH_CALIPER
1043 CALI_CXX_MARK_LOOP_ITERATION(main_loop_id, n_time_step - 1);
1045 if ((time + time_step) > duration)
1046 time_step = duration - time;
1050 if (((n_time_step == 1) || ((n_time_step % time_steps_refinement) == 0)) &&
1051 use_thermal_physics)
1054 double next_refinement_time = time + time_steps_refinement * time_step;
1055 refine_mesh(thermal_physics, mechanical_physics, material_properties,
1056 temperature, heat_sources, time, next_refinement_time,
1057 time_steps_refinement, refinement_database);
1059 rebuild_mechanical_matrix =
true;
1060 if ((rank == 0) && (verbose_output ==
true))
1062 std::cout <<
"n_time_step: " << n_time_step <<
" time: " << time
1063 <<
" n_dofs after mesh refinement: "
1064 << thermal_physics->get_dof_handler().n_dofs() << std::endl;
1073 if (time > activation_time_end)
1077 if (scan_path_for_duration)
1080 bool need_updated_scan_path =
false;
1081 for (
auto &source : heat_sources)
1083 if (time > source->get_scan_path().get_segment_list().back().end_time)
1085 need_updated_scan_path =
true;
1090 if (need_updated_scan_path)
1094 bool scan_path_end =
true;
1095 for (
auto &source : heat_sources)
1097 if (!source->get_scan_path().is_finished())
1099 scan_path_end =
false;
1102 source->get_scan_path().read_file();
1113 std::tie(material_deposition_boxes, deposition_times, deposition_cos,
1115 adamantine::create_material_deposition_boxes<dim>(
1116 geometry_database, heat_sources);
1120 double const eps = time_step / 1e10;
1122 auto activation_start =
1123 std::lower_bound(deposition_times.begin(), deposition_times.end(),
1125 deposition_times.begin();
1126 activation_time_end =
1127 std::min(time + std::max(activation_time, time_step), duration) - eps;
1128 auto activation_end =
1129 std::lower_bound(deposition_times.begin(), deposition_times.end(),
1130 activation_time_end) -
1131 deposition_times.begin();
1132 if (activation_start < activation_end)
1134 if (use_thermal_physics)
1136 #ifdef ADAMANTINE_WITH_CALIPER
1137 CALI_MARK_BEGIN(
"add material");
1146 geometry, thermal_physics->get_dof_handler(),
1147 material_deposition_boxes);
1152 std::vector<bool> has_melted(deposition_cos.size(),
false);
1154 thermal_physics->add_material_start(
1155 elements_to_activate, deposition_cos, deposition_sin, has_melted,
1156 activation_start, activation_end, temperature);
1158 if (use_mechanical_physics)
1160 mechanical_physics->prepare_transfer_mpi();
1163 #ifdef ADAMANTINE_WITH_CALIPER
1164 CALI_MARK_BEGIN(
"refine triangulation");
1166 dealii::parallel::distributed::Triangulation<dim> &triangulation =
1167 dynamic_cast<dealii::parallel::distributed::Triangulation<dim> &
>(
1168 const_cast<dealii::Triangulation<dim> &
>(
1169 thermal_physics->get_dof_handler().get_triangulation()));
1170 triangulation.execute_coarsening_and_refinement();
1171 #ifdef ADAMANTINE_WITH_CALIPER
1172 CALI_MARK_END(
"refine triangulation");
1175 thermal_physics->add_material_end(new_material_temperature,
1178 if (use_mechanical_physics)
1180 mechanical_physics->complete_transfer_mpi();
1181 rebuild_mechanical_matrix =
true;
1184 #ifdef ADAMANTINE_WITH_CALIPER
1185 CALI_MARK_END(
"add material");
1190 if ((rank == 0) && (verbose_output ==
true) &&
1191 (activation_end - activation_start > 0) && use_thermal_physics)
1193 std::cout <<
"n_time_step: " << n_time_step <<
" time: " << time
1194 <<
" n_dofs after cell activation: "
1195 << thermal_physics->get_dof_handler().n_dofs() << std::endl;
1205 if (use_thermal_physics && use_mechanical_physics)
1207 thermal_physics->mark_has_melted(material_reference_temps[0],
1214 if (use_thermal_physics)
1216 if (compute_microstructure)
1218 #ifdef ADAMANTINE_WITH_CALIPER
1219 CALI_MARK_BEGIN(
"compute microstructure");
1221 if constexpr (std::is_same_v<MemorySpaceType,
1222 dealii::MemorySpace::Host>)
1224 microstructure->set_old_temperature(temperature);
1228 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
1229 temperature_host(temperature.get_partitioner());
1230 temperature_host.import_elements(temperature,
1231 dealii::VectorOperation::insert);
1232 microstructure->set_old_temperature(temperature_host);
1234 #ifdef ADAMANTINE_WITH_CALIPER
1235 CALI_MARK_END(
"compute microstructure");
1239 time = thermal_physics->evolve_one_time_step(time, time_step, temperature,
1242 if (compute_microstructure)
1244 #ifdef ADAMANTINE_WITH_CALIPER
1245 CALI_MARK_BEGIN(
"compute microstructure");
1247 if constexpr (std::is_same_v<MemorySpaceType,
1248 dealii::MemorySpace::Host>)
1250 microstructure->compute_G_and_R(material_properties,
1251 thermal_physics->get_dof_handler(),
1252 temperature, time_step);
1256 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
1257 temperature_host(temperature.get_partitioner());
1258 temperature_host.import_elements(temperature,
1259 dealii::VectorOperation::insert);
1260 microstructure->compute_G_and_R(material_properties,
1261 thermal_physics->get_dof_handler(),
1262 temperature_host, time_step);
1264 #ifdef ADAMANTINE_WITH_CALIPER
1265 CALI_MARK_END(
"compute microstructure");
1271 if (use_mechanical_physics)
1275 if ((n_time_step % mechanical_time_step_factor == 0) ||
1276 (n_time_step % time_steps_output == 0))
1278 if (use_thermal_physics)
1281 thermal_physics->set_state_to_material_properties();
1282 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
1283 temperature_host(temperature.get_partitioner());
1284 temperature_host.import_elements(temperature,
1285 dealii::VectorOperation::insert);
1286 if (rebuild_mechanical_matrix)
1288 mechanical_physics->setup_dofs(
1289 thermal_physics->get_dof_handler(), temperature_host,
1290 thermal_physics->get_has_melted_vector());
1291 rebuild_mechanical_matrix =
false;
1295 mechanical_physics->update_rhs(
1296 thermal_physics->get_dof_handler(), temperature_host,
1297 thermal_physics->get_has_melted_vector());
1302 if (rebuild_mechanical_matrix)
1304 mechanical_physics->setup_dofs();
1305 rebuild_mechanical_matrix =
false;
1309 mechanical_physics->update_rhs();
1312 displacement = mechanical_physics->solve();
1318 if (n_time_step % time_steps_checkpoint == 0)
1320 #ifdef ADAMANTINE_WITH_CALIPER
1321 CALI_MARK_BEGIN(
"save checkpoint");
1325 std::cout <<
"Checkpoint reached" << std::endl;
1328 std::string output_dir =
1329 post_processor_database.get<std::string>(
"output_dir",
"");
1330 std::string filename_prefix =
1331 checkpoint_overwrite
1332 ? checkpoint_filename
1333 : checkpoint_filename +
'_' + std::to_string(n_time_step);
1334 thermal_physics->save_checkpoint(filename_prefix, temperature);
1335 std::ofstream file{output_dir + filename_prefix +
"_time.txt"};
1336 boost::archive::text_oarchive oa{file};
1339 #ifdef ADAMANTINE_WITH_CALIPER
1340 CALI_MARK_END(
"save checkpoint");
1347 double adim_time = time / (duration / 10.);
1348 double int_part = 0;
1349 std::modf(adim_time, &int_part);
1350 if (int_part > progress)
1352 std::cout << int_part * 10 <<
'%' <<
" completed" << std::endl;
1353 progress =
static_cast<unsigned int>(int_part);
1358 if (n_time_step % time_steps_output == 0)
1360 if (use_thermal_physics)
1362 thermal_physics->set_state_to_material_properties();
1364 output_pvtu(*post_processor, n_time_step, time, thermal_physics,
1365 temperature, mechanical_physics, displacement,
1366 material_properties, timers);
1371 #ifdef ADAMANTINE_WITH_CALIPER
1372 CALI_CXX_MARK_LOOP_END(main_loop_id);
1375 post_processor->write_pvd();
1378 if constexpr (std::is_same_v<MemorySpaceType, dealii::MemorySpace::Host>)
1380 if (use_thermal_physics)
1382 thermal_physics->get_affine_constraints().distribute(temperature);
1384 if (use_mechanical_physics)
1386 mechanical_physics->get_affine_constraints().distribute(displacement);
1388 return std::make_pair(temperature, displacement);
1392 dealii::LinearAlgebra::distributed::Vector<double,
1393 dealii::MemorySpace::Host>
1394 temperature_host(temperature.get_partitioner());
1395 temperature_host.import_elements(temperature,
1396 dealii::VectorOperation::insert);
1397 if (use_thermal_physics)
1399 thermal_physics->get_affine_constraints().distribute(temperature_host);
1401 if (use_mechanical_physics)
1403 mechanical_physics->get_affine_constraints().distribute(displacement);
1405 return std::make_pair(temperature_host, displacement);
1410 unsigned int global_ensemble_size,
1411 MPI_Comm &local_communicator,
1412 unsigned int &local_ensemble_size,
1413 unsigned int &first_local_member,
int &my_color)
1415 unsigned int const global_rank =
1416 dealii::Utilities::MPI::this_mpi_process(global_communicator);
1417 unsigned int const global_n_procs =
1418 dealii::Utilities::MPI::n_mpi_processes(global_communicator);
1420 double const avg_n_procs_per_member =
1421 static_cast<double>(global_n_procs) /
1422 static_cast<double>(global_ensemble_size);
1423 if (avg_n_procs_per_member > 1)
1425 local_ensemble_size = 1;
1429 avg_n_procs_per_member == std::floor(avg_n_procs_per_member),
1430 "Number of MPI ranks should be less than the number of ensemble "
1431 "members or a multiple of this number.");
1434 global_rank /
static_cast<int>(std::floor(avg_n_procs_per_member));
1436 first_local_member = my_color;
1440 my_color = global_rank;
1442 unsigned int const members_per_proc = global_ensemble_size / global_n_procs;
1443 unsigned int const leftover_members =
1444 global_ensemble_size - global_n_procs * members_per_proc;
1447 local_ensemble_size = members_per_proc;
1448 if (global_rank == 0)
1450 local_ensemble_size += leftover_members;
1451 first_local_member = 0;
1455 first_local_member = global_rank * local_ensemble_size + leftover_members;
1459 MPI_Comm_split(global_communicator, my_color, 0, &local_communicator);
1462 template <
int dim,
int n_materials,
int p_order,
typename MaterialStates,
1463 typename MemorySpaceType>
1464 std::vector<dealii::LA::distributed::BlockVector<double>>
1466 boost::property_tree::ptree
const &database,
1467 std::vector<adamantine::Timer> &timers)
1469 #ifdef ADAMANTINE_WITH_CALIPER
1470 CALI_CXX_MARK_FUNCTION;
1475 boost::property_tree::ptree geometry_database =
1476 database.get_child(
"geometry");
1477 boost::property_tree::ptree boundary_database =
1478 database.get_child(
"boundary");
1479 boost::property_tree::ptree discretization_database =
1480 database.get_child(
"discretization");
1481 boost::property_tree::ptree time_stepping_database =
1482 database.get_child(
"time_stepping");
1483 boost::property_tree::ptree post_processor_database =
1484 database.get_child(
"post_processor");
1485 boost::property_tree::ptree refinement_database =
1486 database.get_child(
"refinement");
1487 boost::property_tree::ptree material_database =
1488 database.get_child(
"materials");
1491 boost::optional<boost::property_tree::ptree const &> units_optional_database =
1492 database.get_child_optional(
"units");
1493 boost::optional<const boost::property_tree::ptree &>
1494 experiment_optional_database = database.get_child_optional(
"experiment");
1495 boost::optional<const boost::property_tree::ptree &>
1496 data_assimilation_optional_database =
1497 database.get_child_optional(
"data_assimilation");
1501 bool const verbose_output = database.get(
"verbose_output",
false);
1505 unsigned int const fe_degree =
1506 discretization_database.get<
unsigned int>(
"thermal.fe_degree");
1508 std::string quadrature_type =
1509 discretization_database.get(
"thermal.quadrature",
"gauss");
1510 std::transform(quadrature_type.begin(), quadrature_type.end(),
1511 quadrature_type.begin(),
1512 [](
unsigned char c) { return std::tolower(c); });
1516 unsigned int const global_ensemble_size =
1517 database.get(
"ensemble.ensemble_size", 5);
1519 MPI_Comm local_communicator;
1520 unsigned int local_ensemble_size = std::numeric_limits<unsigned int>::max();
1521 unsigned int first_local_member = std::numeric_limits<unsigned int>::max();
1524 local_communicator, local_ensemble_size,
1525 first_local_member, my_color);
1533 std::vector<boost::property_tree::ptree> database_ensemble =
1535 database, local_communicator, first_local_member, local_ensemble_size,
1536 global_ensemble_size);
1538 std::vector<std::unique_ptr<
1540 thermal_physics_ensemble(local_ensemble_size);
1542 std::vector<std::vector<std::shared_ptr<adamantine::HeatSource<dim>>>>
1543 heat_sources_ensemble(local_ensemble_size);
1545 std::vector<std::unique_ptr<adamantine::Geometry<dim>>> geometry_ensemble;
1547 std::vector<std::unique_ptr<adamantine::Boundary>> boundary_ensemble;
1550 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>>
1551 material_properties_ensemble;
1553 std::vector<std::unique_ptr<adamantine::PostProcessor<dim>>>
1554 post_processor_ensemble;
1557 std::vector<dealii::LA::distributed::BlockVector<double>>
1558 solution_augmented_ensemble(local_ensemble_size);
1561 int constexpr base_state = 0;
1562 int constexpr augmented_state = 1;
1565 boost::property_tree::ptree data_assimilation_database;
1566 bool assimilate_data =
false;
1567 std::vector<adamantine::AugmentedStateParameters> augmented_state_parameters;
1569 if (data_assimilation_optional_database)
1572 data_assimilation_database = data_assimilation_optional_database.get();
1575 if (data_assimilation_database.get(
"assimilate_data",
false))
1577 assimilate_data =
true;
1580 if (data_assimilation_database.get(
"augment_with_beam_0_absorption",
1583 augmented_state_parameters.push_back(
1587 if (data_assimilation_database.get(
"augment_with_beam_0_max_power",
1590 augmented_state_parameters.push_back(
1596 local_communicator, my_color,
1597 data_assimilation_database);
1600 boost::optional<boost::property_tree::ptree const &>
1601 checkpoint_optional_database = database.get_child_optional(
"checkpoint");
1602 boost::optional<boost::property_tree::ptree const &>
1603 restart_optional_database = database.get_child_optional(
"restart");
1605 unsigned int const global_rank =
1606 dealii::Utilities::MPI::this_mpi_process(global_communicator);
1607 unsigned int time_steps_checkpoint = std::numeric_limits<unsigned int>::max();
1608 std::string checkpoint_filename;
1609 bool checkpoint_overwrite =
true;
1610 if (checkpoint_optional_database)
1612 auto checkpoint_database = checkpoint_optional_database.get();
1614 time_steps_checkpoint =
1615 checkpoint_database.get<
unsigned int>(
"time_steps_between_checkpoint");
1617 checkpoint_filename =
1618 checkpoint_database.get<std::string>(
"filename_prefix");
1620 checkpoint_overwrite = checkpoint_database.get<
bool>(
"overwrite_files");
1623 bool restart =
false;
1624 std::string restart_filename;
1625 if (restart_optional_database)
1628 auto restart_database = restart_optional_database.get();
1630 restart_filename = restart_database.get<std::string>(
"filename_prefix");
1632 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
1635 solution_augmented_ensemble[member].reinit(2);
1638 if (database.get<
unsigned int>(
"sources.n_beams") > 0)
1642 if (assimilate_data)
1644 solution_augmented_ensemble[member]
1645 .block(augmented_state)
1646 .reinit(augmented_state_parameters.size());
1648 for (
unsigned int index = 0; index < augmented_state_parameters.size();
1654 if (augmented_state_parameters.at(index) ==
1657 solution_augmented_ensemble[member].block(augmented_state)[index] =
1658 database_ensemble[member].get<
double>(
1659 "sources.beam_0.absorption_efficiency");
1661 else if (augmented_state_parameters.at(index) ==
1664 solution_augmented_ensemble[member].block(augmented_state)[index] =
1665 database_ensemble[member].get<
double>(
1666 "sources.beam_0.max_power");
1672 solution_augmented_ensemble[member].collect_sizes();
1675 local_communicator, geometry_database, units_optional_database));
1677 boundary_ensemble.push_back(std::make_unique<adamantine::Boundary>(
1679 geometry_ensemble.back()->get_triangulation().get_boundary_ids()));
1681 material_properties_ensemble.push_back(
1683 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>(
1684 local_communicator, geometry_ensemble.back()->get_triangulation(),
1685 material_database));
1687 thermal_physics_ensemble[member] = initialize_thermal_physics<dim>(
1688 fe_degree, quadrature_type, local_communicator,
1689 database_ensemble[member], *geometry_ensemble[member],
1690 *boundary_ensemble[member], *material_properties_ensemble[member]);
1691 heat_sources_ensemble[member] =
1692 thermal_physics_ensemble[member]->get_heat_sources();
1694 if (restart ==
false)
1696 thermal_physics_ensemble[member]->setup();
1697 thermal_physics_ensemble[member]->initialize_dof_vector(
1698 database_ensemble[member].get(
"materials.initial_temperature", 300.),
1699 solution_augmented_ensemble[member].block(base_state));
1703 #ifdef ADAMANTINE_WITH_CALIPER
1704 CALI_MARK_BEGIN(
"restart from file");
1706 thermal_physics_ensemble[member]->load_checkpoint(
1707 restart_filename +
'_' + std::to_string(member),
1708 solution_augmented_ensemble[member].block(base_state));
1709 #ifdef ADAMANTINE_WITH_CALIPER
1710 CALI_MARK_END(
"restart from file");
1713 solution_augmented_ensemble[member].collect_sizes();
1716 post_processor_database.put(
"thermal_output",
true);
1717 post_processor_ensemble.push_back(
1719 local_communicator, post_processor_database,
1720 thermal_physics_ensemble[member]->get_dof_handler(),
1721 first_local_member + member));
1725 boost::property_tree::ptree post_processor_expt_database;
1727 std::string expt_file_prefix =
1728 post_processor_database.get<std::string>(
"filename_prefix") +
".expt";
1729 post_processor_expt_database.put(
"filename_prefix", expt_file_prefix);
1730 post_processor_expt_database.put(
"thermal_output",
true);
1731 std::unique_ptr<adamantine::PostProcessor<dim>> post_processor_expt;
1733 bool const output_experiment_on_mesh =
1734 experiment_optional_database
1735 ? experiment_optional_database->get(
"output_experiment_on_mesh",
true)
1740 if (output_experiment_on_mesh && (my_color == 0))
1742 post_processor_expt = std::make_unique<adamantine::PostProcessor<dim>>(
1743 local_communicator, post_processor_expt_database,
1744 thermal_physics_ensemble[0]->get_dof_handler());
1748 unsigned int progress = 0;
1749 unsigned int n_time_step = 0;
1751 double activation_time_end = -1.;
1752 double da_time = -1.;
1753 if (restart ==
true)
1755 if (global_rank == 0)
1757 std::cout <<
"Restarting from file" << std::endl;
1759 std::ifstream file{restart_filename +
"_time.txt"};
1760 boost::archive::text_iarchive ia{file};
1766 double const activation_time =
1767 geometry_database.get<
double>(
"deposition_time", 0.);
1770 std::vector<std::vector<double>> frame_time_stamps;
1771 std::unique_ptr<adamantine::ExperimentalData<dim>> experimental_data;
1772 unsigned int experimental_frame_index =
1773 std::numeric_limits<unsigned int>::max();
1775 if (experiment_optional_database)
1777 auto experiment_database = experiment_optional_database.get();
1780 bool const read_in_experimental_data =
1781 experiment_database.get(
"read_in_experimental_data",
false);
1783 if (read_in_experimental_data)
1785 if (global_rank == 0)
1786 std::cout <<
"Reading the experimental log file..." << std::endl;
1792 "Experimental data parsing is activated, but "
1793 "the log shows zero cameras.");
1795 "Experimental data parsing is activated, but "
1796 "the log shows zero data frames.");
1798 if (global_rank == 0)
1799 std::cout <<
"Done. Log entries found for " << frame_time_stamps.size()
1800 <<
" camera(s), with " << frame_time_stamps[0].size()
1801 <<
" frame(s)." << std::endl;
1804 std::string experiment_format =
1805 experiment_database.get<std::string>(
"format");
1807 if (boost::iequals(experiment_format,
"point_cloud"))
1809 experimental_data = std::make_unique<adamantine::PointCloud<dim>>(
1814 if constexpr (dim == 3)
1818 experiment_database,
1819 thermal_physics_ensemble[0]->get_dof_handler()));
1826 bool found_frame =
false;
1827 while (!found_frame)
1829 if (frame_time_stamps[0][experimental_frame_index + 1] < time)
1831 experimental_frame_index++;
1844 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>
1846 dealii::LA::distributed::Vector<double, dealii::MemorySpace::Host>
1848 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
1850 output_pvtu(*post_processor_ensemble[member], n_time_step, time,
1851 thermal_physics_ensemble[member],
1852 solution_augmented_ensemble[member].block(base_state),
1853 mechanical_physics, displacement,
1854 *material_properties_ensemble[member], timers);
1862 unsigned int const time_steps_refinement =
1863 refinement_database.get(
"time_steps_between_refinement", 10);
1865 double time_step = time_stepping_database.get<
double>(
"time_step");
1866 double const da_time_half_window = 1.01 * time_step;
1868 bool const scan_path_for_duration =
1869 time_stepping_database.get(
"scan_path_for_duration",
false);
1871 double const duration = scan_path_for_duration
1872 ? std::numeric_limits<double>::max()
1873 : time_stepping_database.get<
double>(
"duration");
1875 unsigned int const time_steps_output =
1876 post_processor_database.get(
"time_steps_between_output", 1);
1878 bool const output_on_da =
1879 post_processor_database.get(
"output_on_data_assimilation",
true);
1886 auto [material_deposition_boxes, deposition_times, deposition_cos,
1888 adamantine::create_material_deposition_boxes<dim>(
1889 geometry_database, heat_sources_ensemble[0]);
1896 auto bounding_heat_sources = adamantine::get_bounding_heat_sources<dim>(
1897 database_ensemble, global_communicator);
1900 if (global_rank == 0)
1901 std::cout <<
"Starting the main time stepping loop..." << std::endl;
1903 #ifdef ADAMANTINE_WITH_CALIPER
1904 CALI_CXX_MARK_LOOP_BEGIN(main_loop_id,
"main_loop");
1906 while (time < duration)
1908 #ifdef ADAMANTINE_WITH_CALIPER
1909 CALI_CXX_MARK_LOOP_ITERATION(main_loop_id, n_time_step - 1);
1911 if ((time + time_step) > duration)
1912 time_step = duration - time;
1917 if ((n_time_step == 1) || ((n_time_step % time_steps_refinement) == 0))
1920 double const next_refinement_time =
1921 time + time_steps_refinement * time_step;
1923 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
1927 dim, n_materials, p_order, MaterialStates, MemorySpaceType>>
1929 refine_mesh(thermal_physics_ensemble[member], dummy,
1930 *material_properties_ensemble[member],
1931 solution_augmented_ensemble[member].block(base_state),
1932 bounding_heat_sources, time, next_refinement_time,
1933 time_steps_refinement, refinement_database);
1934 solution_augmented_ensemble[member].collect_sizes();
1938 if ((global_rank == 0) && (verbose_output ==
true))
1940 std::cout <<
"n_time_step: " << n_time_step <<
" time: " << time
1942 << thermal_physics_ensemble[0]->get_dof_handler().n_dofs()
1951 if (time > activation_time_end)
1955 if (scan_path_for_duration)
1958 bool need_updated_scan_path =
false;
1960 for (
auto &source : heat_sources_ensemble[0])
1963 source->get_scan_path().get_segment_list().back().end_time)
1965 need_updated_scan_path =
true;
1971 if (need_updated_scan_path)
1979 bool scan_path_end =
true;
1980 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
1982 for (
auto &source : heat_sources_ensemble[member])
1984 if (!source->get_scan_path().is_finished())
1986 scan_path_end =
false;
1989 source->get_scan_path().read_file();
2001 std::tie(material_deposition_boxes, deposition_times, deposition_cos,
2003 adamantine::create_material_deposition_boxes<dim>(
2004 geometry_database, heat_sources_ensemble[0]);
2008 double const eps = time_step / 1e10;
2009 auto activation_start =
2010 std::lower_bound(deposition_times.begin(), deposition_times.end(),
2012 deposition_times.begin();
2013 activation_time_end =
2014 std::min(time + std::max(activation_time, time_step), duration) - eps;
2015 auto activation_end =
2016 std::lower_bound(deposition_times.begin(), deposition_times.end(),
2017 activation_time_end) -
2018 deposition_times.begin();
2019 if (activation_start < activation_end)
2021 #ifdef ADAMANTINE_WITH_CALIPER
2022 CALI_MARK_BEGIN(
"add material");
2024 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2033 *geometry_ensemble[member],
2034 thermal_physics_ensemble[member]->get_dof_handler(),
2035 material_deposition_boxes);
2039 std::vector<bool> has_melted(deposition_cos.size(),
false);
2041 thermal_physics_ensemble[member]->add_material_start(
2042 elements_to_activate, deposition_cos, deposition_sin, has_melted,
2043 activation_start, activation_end,
2044 solution_augmented_ensemble[member].block(base_state));
2046 #ifdef ADAMANTINE_WITH_CALIPER
2047 CALI_MARK_BEGIN(
"refine triangulation");
2049 dealii::DoFHandler<dim> &dof_handler =
2050 thermal_physics_ensemble[member]->get_dof_handler();
2051 dealii::parallel::distributed::Triangulation<dim> &triangulation =
2052 dynamic_cast<dealii::parallel::distributed::Triangulation<dim> &
>(
2053 const_cast<dealii::Triangulation<dim> &
>(
2054 dof_handler.get_triangulation()));
2056 triangulation.execute_coarsening_and_refinement();
2057 #ifdef ADAMANTINE_WITH_CALIPER
2058 CALI_MARK_END(
"refine triangulation");
2061 thermal_physics_ensemble[member]->add_material_end(
2062 database_ensemble[member].get(
2063 "materials.new_material_temperature", 300.),
2064 solution_augmented_ensemble[member].block(base_state));
2066 solution_augmented_ensemble[member].collect_sizes();
2068 #ifdef ADAMANTINE_WITH_CALIPER
2069 CALI_MARK_END(
"add material");
2073 if ((global_rank == 0) && (verbose_output ==
true) &&
2074 (activation_end - activation_start > 0))
2076 std::cout <<
"n_time_step: " << n_time_step <<
" time: " << time
2077 <<
" n_dofs after cell activation: "
2078 << thermal_physics_ensemble[0]->get_dof_handler().n_dofs()
2085 double const old_time = time;
2088 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2090 time = thermal_physics_ensemble[member]->evolve_one_time_step(
2091 old_time, time_step,
2092 solution_augmented_ensemble[member].block(base_state), timers);
2097 if (assimilate_data)
2099 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2101 thermal_physics_ensemble[member]->get_affine_constraints().distribute(
2102 solution_augmented_ensemble[member].block(base_state));
2107 double frame_time = std::numeric_limits<double>::max();
2108 if ((experimental_frame_index + 1) < frame_time_stamps[0].size())
2110 if (time > da_time + da_time_half_window)
2112 da_time = frame_time_stamps[0][experimental_frame_index + 1];
2114 if (frame_time_stamps[0][experimental_frame_index + 1] <= time)
2116 experimental_frame_index = experimental_data->read_next_frame();
2117 frame_time = frame_time_stamps[0][experimental_frame_index];
2121 if (frame_time <= time)
2124 frame_time > old_time || n_time_step == 1,
2125 "Unexpectedly missed a data assimilation frame.");
2126 if (global_rank == 0)
2127 std::cout <<
"Performing data assimilation at time " << time <<
"..."
2131 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2133 std::cout <<
"Rank: " << global_rank
2134 <<
" | Old parameters for member "
2135 << first_local_member + member <<
": ";
2136 for (
auto param : solution_augmented_ensemble[member].block(1))
2137 std::cout << param <<
" ";
2139 std::cout << std::endl;
2143 #ifdef ADAMANTINE_WITH_CALIPER
2144 CALI_MARK_BEGIN(
"da_experimental_data");
2146 auto points_values = experimental_data->get_points_values();
2147 auto const &thermal_dof_handler =
2148 thermal_physics_ensemble[0]->get_dof_handler();
2150 points_values, thermal_dof_handler);
2151 std::cout <<
"Rank: " << global_rank
2152 <<
" | Number expt sites mapped to DOFs: "
2153 << expt_to_dof_mapping.first.size() << std::endl;
2154 #ifdef ADAMANTINE_WITH_CALIPER
2155 CALI_MARK_END(
"da_experimental_data");
2159 if (post_processor_expt)
2161 dealii::LA::distributed::Vector<double, MemorySpaceType>
2163 temperature_expt.reinit(
2164 solution_augmented_ensemble[0].block(base_state));
2165 temperature_expt.add(1.0e10);
2167 global_communicator, points_values, expt_to_dof_mapping,
2168 temperature_expt, verbose_output);
2170 thermal_physics_ensemble[0]->get_affine_constraints().distribute(
2173 ->template write_thermal_output<
typename Kokkos::View<
2175 typename MemorySpaceType::kokkos_space>::array_layout>(
2176 n_time_step, time, temperature_expt,
2177 material_properties_ensemble[0]->get_state(),
2178 material_properties_ensemble[0]->get_dofs_map(),
2179 material_properties_ensemble[0]->get_dof_handler());
2184 if (expt_to_dof_mapping.first.size() > 0)
2194 #ifdef ADAMANTINE_WITH_CALIPER
2195 CALI_MARK_BEGIN(
"da_dof_mapping");
2198 #ifdef ADAMANTINE_WITH_CALIPER
2199 CALI_MARK_END(
"da_dof_mapping");
2204 #ifdef ADAMANTINE_WITH_CALIPER
2205 CALI_MARK_BEGIN(
"da_covariance_sparsity");
2208 thermal_dof_handler,
2209 solution_augmented_ensemble[0].block(augmented_state).size());
2210 #ifdef ADAMANTINE_WITH_CALIPER
2211 CALI_MARK_END(
"da_covariance_sparsity");
2215 unsigned int experimental_data_size = points_values.values.size();
2220 #ifdef ADAMANTINE_WITH_CALIPER
2221 CALI_MARK_BEGIN(
"da_obs_covariance");
2223 double variance_entries = experiment_optional_database.get().get(
2224 "estimated_uncertainty", 0.0);
2225 variance_entries = variance_entries * variance_entries;
2227 dealii::SparsityPattern pattern(experimental_data_size,
2228 experimental_data_size, 1);
2229 for (
unsigned int i = 0; i < experimental_data_size; ++i)
2235 dealii::SparseMatrix<double> R(pattern);
2236 for (
unsigned int i = 0; i < experimental_data_size; ++i)
2238 R.add(i, i, variance_entries);
2240 #ifdef ADAMANTINE_WITH_CALIPER
2241 CALI_MARK_END(
"da_obs_covariance");
2247 #ifdef ADAMANTINE_WITH_CALIPER
2248 CALI_MARK_BEGIN(
"da_update_ensemble");
2251 points_values.values, R);
2252 #ifdef ADAMANTINE_WITH_CALIPER
2253 CALI_MARK_END(
"da_update_ensemble");
2258 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2260 for (
unsigned int index = 0;
2261 index < augmented_state_parameters.size(); ++index)
2266 if (augmented_state_parameters.at(index) ==
2269 database_ensemble[member].put(
2270 "sources.beam_0.absorption_efficiency",
2271 solution_augmented_ensemble[member].block(
2272 augmented_state)[index]);
2274 else if (augmented_state_parameters.at(index) ==
2277 database_ensemble[member].put(
2278 "sources.beam_0.max_power",
2279 solution_augmented_ensemble[member].block(
2280 augmented_state)[index]);
2285 if (global_rank == 0)
2286 std::cout <<
"Done." << std::endl;
2289 if (solution_augmented_ensemble[0].block(1).size() > 0)
2291 for (
unsigned int member = 0; member < local_ensemble_size;
2294 std::cout <<
"Rank: " << global_rank
2295 <<
" | New parameters for member "
2296 << first_local_member + member <<
": ";
2297 for (
auto param : solution_augmented_ensemble[member].block(1))
2298 std::cout << param <<
" ";
2300 std::cout << std::endl;
2306 if (global_rank == 0)
2308 <<
"WARNING: NO EXPERIMENTAL DATA POINTS MAPPED ONTO THE "
2309 "SIMULATION MESH. SKIPPING DATA ASSIMILATION OPERATION."
2315 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2317 thermal_physics_ensemble[member]->update_physics_parameters(
2318 database_ensemble[member].get_child(
"sources"));
2323 if (n_time_step % time_steps_checkpoint == 0)
2325 #ifdef ADAMANTINE_WITH_CALIPER
2326 CALI_MARK_BEGIN(
"save checkpoint");
2328 if (global_rank == 0)
2330 std::cout <<
"Checkpoint reached" << std::endl;
2333 std::string output_dir =
2334 post_processor_database.get<std::string>(
"output_dir",
"");
2335 std::string filename_prefix =
2336 checkpoint_overwrite
2337 ? checkpoint_filename
2338 : checkpoint_filename +
'_' + std::to_string(n_time_step);
2339 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2341 thermal_physics_ensemble[member]->save_checkpoint(
2342 filename_prefix +
'_' + std::to_string(first_local_member + member),
2343 solution_augmented_ensemble[member].block(base_state));
2345 std::ofstream file{output_dir + filename_prefix +
"_time.txt"};
2346 boost::archive::text_oarchive oa{file};
2349 #ifdef ADAMANTINE_WITH_CALIPER
2350 CALI_MARK_END(
"save checkpoint");
2355 if (global_rank == 0)
2357 double adim_time = time / (duration / 10.);
2358 double int_part = 0;
2359 std::modf(adim_time, &int_part);
2360 if (int_part > progress)
2362 std::cout << int_part * 10 <<
'%' <<
" completed" << std::endl;
2368 if ((n_time_step % time_steps_output == 0) ||
2369 (output_on_da && time > (da_time - da_time_half_window) &&
2370 time < (da_time + da_time_half_window)))
2372 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2374 thermal_physics_ensemble[member]->set_state_to_material_properties();
2375 output_pvtu(*post_processor_ensemble[member], n_time_step, time,
2376 thermal_physics_ensemble[member],
2377 solution_augmented_ensemble[member].block(base_state),
2378 mechanical_physics, displacement,
2379 *material_properties_ensemble[member], timers);
2386 #ifdef ADAMANTINE_WITH_CALIPER
2387 CALI_CXX_MARK_LOOP_END(main_loop_id);
2390 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2392 post_processor_ensemble[member]->write_pvd();
2396 if constexpr (std::is_same_v<MemorySpaceType, dealii::MemorySpace::Host>)
2398 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2400 thermal_physics_ensemble[member]->get_affine_constraints().distribute(
2401 solution_augmented_ensemble[member].block(base_state));
2403 return solution_augmented_ensemble;
2409 std::vector<dealii::LA::distributed::BlockVector<double>>
2410 solution_augmented_ensemble_host(local_ensemble_size);
2412 for (
unsigned int member = 0; member < local_ensemble_size; ++member)
2414 solution_augmented_ensemble[member].reinit(2);
2416 solution_augmented_ensemble_host[member].block(0).reinit(
2417 solution_augmented_ensemble[member].block(0).get_partitioner());
2419 solution_augmented_ensemble_host[member].block(0).import_elements(
2420 solution_augmented_ensemble[member].block(0),
2421 dealii::VectorOperation::insert);
2422 thermal_physics_ensemble[member]->get_affine_constraints().distribute(
2423 solution_augmented_ensemble_host[member].block(0));
2425 solution_augmented_ensemble_host[member].block(1).reinit(
2426 solution_augmented_ensemble[member].block(0).get_partitioner());
2428 solution_augmented_ensemble_host[member].block(1).import_elements(
2429 solution_augmented_ensemble[member].block(1),
2430 dealii::VectorOperation::insert);
2433 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)
std::vector< std::vector< typename dealii::DoFHandler< dim >::active_cell_iterator > > get_elements_to_activate([[maybe_unused]] Geometry< dim > const &geometry, dealii::DoFHandler< dim > const &dof_handler, std::vector< dealii::BoundingBox< dim >> const &material_deposition_boxes)
void ASSERT_THROW(bool cond, std::string const &message)
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)