/* SPDX-FileCopyrightText: Copyright (c) 2016 - 2025, the adamantine authors. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ #ifndef POST_PROCESSOR_HH #define POST_PROCESSOR_HH #include #include #include #include #include #include #include #include namespace adamantine { /** * Helper class to output the strain given the displacement. */ template class StrainPostProcessor : public dealii::DataPostprocessorTensor { public: StrainPostProcessor(); void evaluate_vector_field( const dealii::DataPostprocessorInputs::Vector &displacement_data, std::vector> &strain) const override; }; /** * This class outputs the results using the vtu format. */ template class PostProcessor { public: using kokkos_host = dealii::MemorySpace::Host::kokkos_space; using kokkos_default = dealii::MemorySpace::Default::kokkos_space; /** * Constructor takes the DoFHandler of the thermal or the mechanical * simulation. */ PostProcessor(MPI_Comm const &communicator, boost::property_tree::ptree const &database, dealii::DoFHandler &dof_handler, int ensemble_member_index = -1); /** * Constructor takes the DoFHandlers of the thermal and the mechanical * simulations. */ PostProcessor(MPI_Comm const &communicator, boost::property_tree::ptree const &database, dealii::DoFHandler &thermal_dof_handler, dealii::DoFHandler &mechanical_dof_handler, int ensemble_member_index = -1); /** * Write the different vtu and pvtu files for a thermal problem. */ template void write_thermal_output( unsigned int time_step, double time, dealii::LA::distributed::Vector const &temperature, Kokkos::View state, std::unordered_map const &dofs_map, dealii::DoFHandler const &material_dof_handler); /** * Write the different vtu and pvtu files for a mechanical problem. */ template void write_mechanical_output( unsigned int time_step, double time, dealii::LA::distributed::Vector const &displacement, std::vector>> const &stress_tensor, Kokkos::View state, std::unordered_map const &dofs_map, dealii::DoFHandler const &material_dof_handler); /** * Write the different vtu and pvtu files for themo-mechanical problems. */ template void write_output(unsigned int time_step, double time, dealii::LA::distributed::Vector const &temperature, dealii::LA::distributed::Vector const &displacement, std::vector>> const &stress_tensor, Kokkos::View state, std::unordered_map const &dofs_map, dealii::DoFHandler const &material_dof_handler); /** * Write the pvd file for Paraview. */ void write_pvd() const; private: /** * Compute the von Mises stress on each cell. */ dealii::Vector get_von_mises_stress( std::vector>> const &stress_tensor); /** * Fill _data_out with thermal data. */ void thermal_dataout(dealii::LA::distributed::Vector const &temperature); /** * Fill _data_out with mechanical data. */ void mechanical_dataout( dealii::LA::distributed::Vector const &displacement, StrainPostProcessor const &strain, std::vector>> const &stress_tensor); /** * Fill _data_out with material data. */ template void material_dataout(Kokkos::View state, std::unordered_map const &dofs_map, dealii::DoFHandler const &material_dof_handler); /** * Fill _data_out with subdomain data. */ void subdomain_dataout(); /** * Write pvtu file. */ void write_pvtu(unsigned int time_step, double time); /** * MPI communicator. */ MPI_Comm _communicator; /** * Flag is true if we output the results of the thermal simulation. */ bool _thermal_output; /** * Flag is true if we output the results of the mechanical simulation. */ bool _mechanical_output; /** * Prefix of the different output files. */ std::string _filename_prefix; /** * Output directory name. */ std::string _output_dir; /** * Vector of pair of time and pvtu file. */ std::vector> _times_filenames; /** * DataOut associated with the post-processing. */ dealii::DataOut _data_out; /** * DoFHandler associated with the thermal simulation. */ dealii::DoFHandler *_thermal_dof_handler = nullptr; /** * DoFHandler associated with the mechanical simulation. */ dealii::DoFHandler *_mechanical_dof_handler = nullptr; /** * Additional levels of refinement for the output. */ unsigned int _additional_output_refinement; }; template StrainPostProcessor::StrainPostProcessor() : dealii::DataPostprocessorTensor("strain", dealii::update_gradients) { } template void StrainPostProcessor::evaluate_vector_field( const dealii::DataPostprocessorInputs::Vector &displacement_data, std::vector> &strain) const { for (unsigned int i = 0; i < displacement_data.solution_gradients.size(); ++i) { for (unsigned int j = 0; j < dim; ++j) { for (unsigned int k = 0; k < dim; ++k) { // strain = (\nabla u + (\nabla u)^T)/2 strain[i][dealii::Tensor<2, dim>::component_to_unrolled_index( dealii::TableIndices<2>(j, k))] = (displacement_data.solution_gradients[i][j][k] + displacement_data.solution_gradients[i][k][j]) / 2.; } } } } template template void PostProcessor::write_thermal_output( unsigned int time_step, double time, dealii::LA::distributed::Vector const &temperature, Kokkos::View state, std::unordered_map const &dofs_map, dealii::DoFHandler const &material_dof_handler) { ASSERT(_thermal_dof_handler != nullptr, "Internal Error"); _data_out.clear(); thermal_dataout(temperature); material_dataout(state, dofs_map, material_dof_handler); subdomain_dataout(); write_pvtu(time_step, time); } template template void PostProcessor::write_mechanical_output( unsigned int time_step, double time, dealii::LA::distributed::Vector const &displacement, std::vector>> const &stress_tensor, Kokkos::View state, std::unordered_map const &dofs_map, dealii::DoFHandler const &material_dof_handler) { ASSERT(_mechanical_dof_handler != nullptr, "Internal Error"); _data_out.clear(); // We need the StrainPostProcessor to live until write_pvtu is done StrainPostProcessor strain; mechanical_dataout(displacement, strain, stress_tensor); material_dataout(state, dofs_map, material_dof_handler); subdomain_dataout(); write_pvtu(time_step, time); } template template void PostProcessor::write_output( unsigned int time_step, double time, dealii::LA::distributed::Vector const &temperature, dealii::LA::distributed::Vector const &displacement, std::vector>> const &stress_tensor, Kokkos::View state, std::unordered_map const &dofs_map, dealii::DoFHandler const &material_dof_handler) { ASSERT(_thermal_dof_handler != nullptr, "Internal Error"); ASSERT(_mechanical_dof_handler != nullptr, "Internal Error"); _data_out.clear(); thermal_dataout(temperature); // We need the StrainPostProcessor to live until write_pvtu is done StrainPostProcessor strain; mechanical_dataout(displacement, strain, stress_tensor); material_dataout(state, dofs_map, material_dof_handler); subdomain_dataout(); write_pvtu(time_step, time); } template template void PostProcessor::material_dataout( Kokkos::View state, std::unordered_map const &dofs_map, dealii::DoFHandler const &material_dof_handler) { unsigned int const n_active_cells = material_dof_handler.get_triangulation().n_active_cells(); dealii::Vector powder(n_active_cells); dealii::Vector liquid(n_active_cells); dealii::Vector solid(n_active_cells); unsigned int constexpr powder_index = static_cast(SolidLiquidPowder::State::powder); unsigned int constexpr liquid_index = static_cast(SolidLiquidPowder::State::liquid); unsigned int constexpr solid_index = static_cast(SolidLiquidPowder::State::solid); auto mp_cell = material_dof_handler.begin_active(); auto mp_end_cell = material_dof_handler.end(); std::vector mp_dof_indices(1); for (unsigned int i = 0; mp_cell != mp_end_cell; ++i, ++mp_cell) if (mp_cell->is_locally_owned()) { mp_cell->get_dof_indices(mp_dof_indices); dealii::types::global_dof_index const mp_dof_index = dofs_map.at(mp_dof_indices[0]); solid[i] = state(solid_index, mp_dof_index); liquid[i] = liquid_index < state.extent(0) ? state(liquid_index, mp_dof_index) : 0.; powder[i] = powder_index < state.extent(0) ? state(powder_index, mp_dof_index) : 0; } _data_out.add_data_vector(powder, "powder"); _data_out.add_data_vector(liquid, "liquid"); _data_out.add_data_vector(solid, "solid"); } } // namespace adamantine #endif