Contents
Phase Field for Brittle Fracture
Introduction
TBA
Theory
TBA
Implementation
TBA
Results
TBA
Complete code
#include <deal.II/base/quadrature_lib.h> #include <deal.II/base/function.h> #include <deal.II/base/timer.h> #include <deal.II/lac/generic_linear_algebra.h> #include <deal.II/lac/vector.h> #include <deal.II/lac/full_matrix.h> #include <deal.II/lac/precondition.h> #include <deal.II/lac/petsc_precondition.h> #include <deal.II/lac/solver_cg.h> #include <deal.II/lac/affine_constraints.h> #include <deal.II/lac/dynamic_sparsity_pattern.h> #include <deal.II/grid/grid_generator.h> #include <deal.II/dofs/dof_handler.h> #include <deal.II/dofs/dof_tools.h> #include <deal.II/dofs/dof_accessor.h> #include <deal.II/grid/tria_accessor.h> #include <deal.II/fe/fe_values.h> #include <deal.II/fe/fe_system.h> #include <deal.II/fe/fe_q.h> #include <deal.II/grid/grid_refinement.h> #include <deal.II/numerics/vector_tools.h> #include <deal.II/numerics/matrix_tools.h> #include <deal.II/numerics/data_out.h> #include <deal.II/numerics/error_estimator.h> #include <deal.II/base/utilities.h> #include <deal.II/base/conditional_ostream.h> #include <deal.II/base/index_set.h> #include <deal.II/lac/sparsity_tools.h> #include <deal.II/distributed/tria.h> #include <deal.II/distributed/grid_refinement.h> #include <deal.II/distributed/solution_transfer.h> #include <deal.II/base/quadrature_point_data.h> #include <deal.II/base/tensor_function.h> #include <fstream> #include <iostream> #include <random> const unsigned int damage_type = 2; // 1 for quadratic // 2 for linear namespace elas { using namespace dealii; template<int dim> SymmetricTensor<4, dim> get_stress_strain_tensor(const double lambda, const double mu) { SymmetricTensor<4, dim> tmp; for (unsigned int i = 0; i < dim; ++i) for (unsigned int j = 0; j < dim; ++j) for (unsigned int k = 0; k < dim; ++k) for (unsigned int l = 0; l < dim; ++l) tmp[i][j][k][l] = (((i == k) && (j == l) ? mu : 0.0) + ((i == l) && (j == k) ? mu : 0.0) + ((i == j) && (k == l) ? lambda : 0.0)); return tmp; } template<int dim> inline SymmetricTensor<2, dim> get_strain(const FEValues<dim>& fe_values, const unsigned int shape_func, const unsigned int q_point) { SymmetricTensor<2,dim> tmp; for (unsigned int i = 0; i < dim; ++i) tmp[i][i] = fe_values.shape_grad_component(shape_func, q_point, i)[i]; for (unsigned int i = 0; i < dim; ++i) for (unsigned int j = i + 1; j < dim; ++j) tmp[i][j] = (fe_values.shape_grad_component(shape_func, q_point, i)[j] + fe_values.shape_grad_component(shape_func, q_point, j)[i]) / 2; return tmp; } template<int dim> inline SymmetricTensor<2, dim> get_strain(const std::vector<Tensor<1, dim>>& grad) { Assert(grad.size() == dim, ExcInternalError()); SymmetricTensor<2, dim> strain; for (unsigned int i = 0; i < dim; ++i) strain[i][i] = grad[i][i]; for (unsigned int i = 0; i < dim; ++i) for (unsigned int j = i + 1; j < dim; ++j) strain[i][j] = (grad[i][j] + grad[j][i]) / 2; return strain; } template <int dim> class Elasticity { public: Elasticity(); void run(); private: // Mesh generation and refinement void create_mesh(); void refine_mesh(const unsigned int load_step); // Elasticity problem functions void setup_constraints_elastic (const unsigned int load_step); // Posso creare funz che applica BC o mettere a fine assembly matrix void setup_elasticity(const unsigned int load_step); void assemble_elasticity(const unsigned int load_step, const bool flag_iter); void solve_linear_problem(const bool flag_iter); // Damage problem functions void setup_constraints_alpha(); void setup_system_alpha(); void assemble_system_alpha(PETScWrappers::MPI::Vector &present_solution_alpha, PETScWrappers::MPI::Vector &system_rhs_alpha); double gc(const float GC, const float beta, const float x1, const float x2, const Point<dim> &p); static PetscErrorCode FormFunction(SNES, Vec, Vec, void*); static PetscErrorCode FormJacobian(SNES, Vec, Mat, Mat, void*); // Save the results - Disp, stress, reaction, energies void output_results(const unsigned int load_step) const; void output_forces(const unsigned int load_step); void output_energies(const unsigned int load_step); // Parallel setup and print on screen MPI_Comm mpi_communicator; const unsigned int n_mpi_processes; const unsigned int this_mpi_process; parallel::distributed::Triangulation<dim> triangulation; // Objects for elasticity const FESystem<dim> fe_elastic; // FE System DoFHandler<dim> dof_handler_elastic; // DoF Handler IndexSet locally_owned_dofs_elastic; // IndexSet - Locally Owned IndexSet locally_relevant_dofs_elastic; // IndexSet - Locally relevant AffineConstraints<double> constraints_elastic; // Affine Constraint static const SymmetricTensor<4,dim> stress_strain_tensor; PETScWrappers::MPI::SparseMatrix system_matrix_elastic; // Elastcitiy Matrix PETScWrappers::MPI::Vector locally_relevant_solution_elastic; // MPI Split solution PETScWrappers::MPI::Vector completely_distributed_solution_elastic; // Full Solution PETScWrappers::MPI::Vector newton_update_solution_elastic; // Full Solution PETScWrappers::MPI::Vector system_rhs_elastic; // RHS PETScWrappers::MPI::Vector completely_distributed_solution_elastic_old; // This is for the refinement const QGauss<dim> quadrature_formula_elastic; // Quadrature formula // Objects for damage const FESystem<dim> fe_damage; // FE System DoFHandler<dim> dof_handler_damage; // DoF Handler IndexSet locally_owned_dofs_damage; // IndexSet - Locally Owned IndexSet locally_relevant_dofs_damage; // IndexSet - Locally relevant AffineConstraints<double> constraints_damage; // Affine Constraint PETScWrappers::MPI::SparseMatrix system_matrix_damage; // Elastcitiy Matrix PETScWrappers::MPI::Vector system_rhs_damage; // RHS PETScWrappers::MPI::Vector locally_relevant_solution_damage; // MPI Split solution PETScWrappers::MPI::Vector completely_distributed_solution_damage; // Full Solution PETScWrappers::MPI::Vector completely_distributed_solution_damage_old; // This is for the refinement PETScWrappers::MPI::Vector locally_damageLB; // MPI Split solution -> mi serve per interpolazione durante il raffittimento PETScWrappers::MPI::Vector completely_distributed_damageLB; // Full Solution LB -> uso nello SNES PETScWrappers::MPI::Vector completely_distributed_damageLB_old; // This is for the refinement -> storo la soluzione e la uso per interpolazione PETScWrappers::MPI::Vector completely_distributed_damageUB; // Full Solution UB -> ricreo e setto 1 ogni volta che setuppo const QGauss<dim> quadrature_formula_damage; // Quadrature formula // Domain dimensions double L = 1; double H = 0.05; double W = 0.05; const unsigned int nx = 25; const unsigned int ny = 2; const unsigned int nz = 2; // Material properties double E = 100; double nu = 0.3; // Damage parameters double Gc = .01; double ell = 0.02; double k_res = 1e-6; double c_w; double load_increment = 0.01; // Load increment applied double applied_load = 0; // Current applied_load += load_increment double num_load_steps = 15; // Total load increment ConditionalOStream pcout; TimerOutput computing_timer; }; // End of Elast class // Constructor template <int dim> Elasticity<dim>::Elasticity() : mpi_communicator(MPI_COMM_WORLD) , n_mpi_processes(Utilities::MPI::n_mpi_processes(mpi_communicator)) , this_mpi_process(Utilities::MPI::this_mpi_process(mpi_communicator)) , triangulation (mpi_communicator) , fe_elastic (FE_Q<dim> (1), dim) , dof_handler_elastic (triangulation) , quadrature_formula_elastic (fe_elastic.degree + 1) , fe_damage (FE_Q<dim> (1), 1) , dof_handler_damage (triangulation) , quadrature_formula_damage (fe_elastic.degree + 1) , c_w(damage_type == 1 ? 2.0 : 8.0 / 3.0) , pcout (std::cout, this_mpi_process == 0) , computing_timer (mpi_communicator, pcout, TimerOutput::never, TimerOutput::wall_times) {} // Evaluation of the elastic constant inline double lambda (const float E, const float nu) { return (E * nu) / ((1 + nu) * (1 - 2 * nu)); } inline double mu (const float E, const float nu) { return E / (2 * (1 + nu)); } // Evaluation of the damage functions inline double g_alpha (double &alpha) { return (1-alpha)*(1-alpha); } inline double g_prime_alpha (double &alpha) { return -2.+2.*alpha; } inline double g_second_alpha () { return 2.; } inline double w_alpha (double &alpha) { double tmp; if (damage_type == 1) tmp = alpha*alpha; else if (damage_type == 2) tmp = alpha; return tmp; } inline double w_prime_alpha (double &alpha) { double tmp; if (damage_type == 1) tmp = 2.*alpha; else if (damage_type == 2) tmp = 1.; return tmp; } inline double w_second_alpha () { double tmp; if (damage_type == 1) tmp = 2.; else if (damage_type == 2) tmp = 0.; return tmp; } template <int dim> double Elasticity<dim>::gc(const float GC, const float beta, const float x1, const float x2, const Point<dim> &p) { if (((p[0] - x1) > 1e-6) && ((p[0] - x2) < 1e-6)) return GC * beta; else return GC; } // ----------------------------- // ----------- MESH ------------ // ----------------------------- template <int dim> void Elasticity<dim>::create_mesh() { // Define the initial coarse subdivision const std::vector<unsigned int> repetitions = {nx,ny,nz}; // Create Mesh Point<dim> p1, p2; if constexpr (dim == 2) { p1 = Point<dim>(0, 0); p2 = Point<dim>(L, H); } else if constexpr (dim == 3) { p1 = Point<dim>(0, 0, 0); p2 = Point<dim>(L, H, W); } GridGenerator::subdivided_hyper_rectangle (triangulation, repetitions, p1, p2); // create coarse mesh // Set Fce IDs for (const auto &cell : triangulation.active_cell_iterators ()) { if (cell->is_locally_owned()) { if (cell->center()[0] >= (0.5*L-0.1) && cell->center()[0] <= (0.5*L+0.1)) cell->set_material_id(1); else cell->set_material_id(0); } for (const auto &face : cell->face_iterators ()) { if (face->at_boundary ()) { const auto center = face->center (); if (std::fabs (center(0) - 0) < 1e-12) face->set_boundary_id (0); else if (std::fabs (center(0) - L) < 1e-12) face->set_boundary_id (1); else if (std::fabs (center(1) - 0) < 1e-12) face->set_boundary_id (2); else if (std::fabs (center(1) - H) < 1e-12) face->set_boundary_id (3); // Controlla se siamo in 3D prima di accedere a center(2) if constexpr (dim == 3) { if (std::fabs(center(2) - 0) < 1e-12) face->set_boundary_id(4); else if (std::fabs(center(2) - W) < 1e-12) face->set_boundary_id(5); } } } } // Initialize dof handler and extact Owned/Relevant DoFs dof_handler_damage.distribute_dofs (fe_damage); dof_handler_elastic.distribute_dofs (fe_elastic); //Initialising damage vectors locally_owned_dofs_damage = dof_handler_damage.locally_owned_dofs (); locally_relevant_dofs_damage = DoFTools::extract_locally_relevant_dofs (dof_handler_damage); // Actual solution -> local; Old solution -> global locally_relevant_solution_damage.reinit(locally_owned_dofs_damage, locally_relevant_dofs_damage, mpi_communicator); locally_damageLB.reinit (locally_owned_dofs_damage, locally_relevant_dofs_damage, mpi_communicator); completely_distributed_solution_damage_old.reinit (locally_owned_dofs_damage, mpi_communicator); completely_distributed_damageLB_old.reinit (locally_owned_dofs_damage, mpi_communicator); completely_distributed_damageLB_old = 0; // Do the same for elasticity locally_owned_dofs_elastic = dof_handler_elastic.locally_owned_dofs (); locally_relevant_dofs_elastic = DoFTools::extract_locally_relevant_dofs (dof_handler_elastic); // Initialize the old solution for refinement purposes completely_distributed_solution_elastic_old.reinit (locally_owned_dofs_elastic, mpi_communicator); pcout << "No. of levels in triangulation: " << triangulation.n_global_levels () << std::endl; pcout << " Number of locally owned cells on the process: " << triangulation.n_locally_owned_active_cells () << std::endl; pcout << "Number of global cells:" << triangulation.n_global_active_cells () << std::endl; pcout << " Total Number of globally active cells: " << triangulation.n_global_active_cells () << std::endl << " Number of degrees of freedom for elasticity: " << dof_handler_elastic.n_dofs () << std::endl; } template<int dim> void Elasticity<dim>::refine_mesh(const unsigned int load_step) { Vector<float> estimated_error_per_cell (triangulation.n_locally_owned_active_cells ()); KellyErrorEstimator<dim>::estimate (dof_handler_damage, QGauss<dim-1> (fe_damage.degree + 1), std::map<types::boundary_id, const Function<dim> *>(), locally_relevant_solution_damage, estimated_error_per_cell); // Initialize SolutionTransfer object parallel::distributed::SolutionTransfer<dim, PETScWrappers::MPI::Vector> soltransDamage (dof_handler_damage); parallel::distributed::SolutionTransfer<dim, PETScWrappers::MPI::Vector> soltransDamageLB (dof_handler_damage); parallel::distributed::SolutionTransfer<dim, PETScWrappers::MPI::Vector> soltransElastic (dof_handler_elastic); parallel::distributed::GridRefinement::refine_and_coarsen_fixed_fraction ( triangulation, estimated_error_per_cell, 0.15, 0.05); if (triangulation.n_global_levels () >= 7) { for (const auto &cell : triangulation.active_cell_iterators_on_level (6)) if (cell->is_locally_owned ()) cell->clear_refine_flag (); } // Prepare the triangulation triangulation.prepare_coarsening_and_refinement (); // Prepare the SolutionTransfer object for coarsening and refinement // and give the solution vector that we intend to interpolate later, soltransDamage.prepare_for_coarsening_and_refinement (locally_relevant_solution_damage); soltransDamageLB.prepare_for_coarsening_and_refinement (locally_damageLB); soltransElastic.prepare_for_coarsening_and_refinement (locally_relevant_solution_elastic); // Do the refinement triangulation.execute_coarsening_and_refinement (); // redistribute dofs, dof_handler_damage.distribute_dofs (fe_damage); dof_handler_elastic.distribute_dofs (fe_elastic); // --- DAMAGE // Recreate locally_owned_dofs and locally_relevant_dofs index sets locally_owned_dofs_damage = dof_handler_damage.locally_owned_dofs (); locally_relevant_dofs_damage = DoFTools::extract_locally_relevant_dofs (dof_handler_damage); completely_distributed_solution_damage_old.reinit (locally_owned_dofs_damage, mpi_communicator); soltransDamage.interpolate (completely_distributed_solution_damage_old); completely_distributed_damageLB_old.reinit (locally_owned_dofs_damage, mpi_communicator); soltransDamageLB.interpolate (completely_distributed_damageLB_old); // Apply constraints on the interpolated solution to make sure it conforms with the new mesh setup_constraints_alpha (); constraints_damage.distribute (completely_distributed_solution_damage_old); constraints_damage.distribute (completely_distributed_damageLB_old); // Copy completely_distributed_solution_damage_old to locally_relevant_solution_damage locally_relevant_solution_damage.reinit (locally_owned_dofs_damage, locally_relevant_dofs_damage, mpi_communicator); locally_damageLB.reinit (locally_owned_dofs_damage, locally_relevant_dofs_damage, mpi_communicator); locally_relevant_solution_damage = completely_distributed_solution_damage_old; locally_damageLB = completely_distributed_damageLB_old; // --- ELASTICITY // Recreate locally_owned_dofs and locally_relevant_dofs index sets - ELASTICITY locally_owned_dofs_elastic = dof_handler_elastic.locally_owned_dofs (); locally_relevant_dofs_elastic = DoFTools::extract_locally_relevant_dofs (dof_handler_elastic); completely_distributed_solution_elastic_old.reinit (locally_owned_dofs_elastic, mpi_communicator); soltransElastic.interpolate (completely_distributed_solution_elastic_old); // Apply constraints on the interpolated solution to make sure it conforms with the new mesh setup_constraints_elastic(load_step); constraints_elastic.distribute (completely_distributed_solution_elastic_old); // Copy completely_distributed_solution_damage_old to locally_relevant_solution_damage locally_relevant_solution_elastic.reinit(locally_owned_dofs_elastic, locally_relevant_dofs_elastic, mpi_communicator); locally_relevant_solution_elastic = completely_distributed_solution_elastic_old; for (const auto &cell : triangulation.active_cell_iterators ()) { if (cell->is_locally_owned ()) { if (cell->center()[0] >= (0.5*L-0.1) && cell->center()[0] <= (0.5*L+0.1)) cell->set_material_id(1); else cell->set_material_id(0); } } } // ----------------------------- // -------- ELASTICITY --------- // ----------------------------- template <int dim> const SymmetricTensor<4,dim> Elasticity<dim>::stress_strain_tensor = get_stress_strain_tensor<dim>(/*lambda = */ (100*0.3)/((1+0.3)*(1-2*0.3)), /*mu = */ 100/(2.*(1+0.3))); template<int dim> void Elasticity<dim>::setup_constraints_elastic (const unsigned int load_step) { /* constraints_elastic.clear (); constraints_elastic.reinit (locally_relevant_dofs_elastic); DoFTools::make_hanging_node_constraints (dof_handler_elastic, constraints_elastic); for (const auto &cell : dof_handler_elastic.active_cell_iterators ()) if (cell->is_locally_owned ()) { for (const auto &face : cell->face_iterators ()) { if (face->at_boundary ()) { const auto center = face->center (); if (std::fabs (center (0) - 0.5*L) < 1e-12) // Face at L/2 { for (const auto vertex_number : cell->vertex_indices ()) { const auto vert = cell->vertex (vertex_number); const double y_bot = 0; if (std::fabs (vert (1) - 0) < 1e-12 && std::fabs (vert (0) - L/2) < 1e-12) { const unsigned int y_dof = cell->vertex_dof_index (vertex_number, 1); constraints_elastic.add_line (y_dof); constraints_elastic.set_inhomogeneity (y_dof, 0); const unsigned int x_dof = cell->vertex_dof_index (vertex_number, 0); constraints_elastic.add_line (x_dof); constraints_elastic.set_inhomogeneity (x_dof, 0); } } } } } } const FEValuesExtractors::Scalar u_x (0); const ComponentMask u_x_mask = fe_elastic.component_mask (u_x); applied_load = load_increment*load_step; const double u_x_values_right = 0.5*applied_load; const double u_x_values_left = -0.5*applied_load; VectorTools::interpolate_boundary_values (dof_handler_elastic, 0, Functions::ConstantFunction<dim> (u_x_values_left, dim), constraints_elastic, u_x_mask); VectorTools::interpolate_boundary_values (dof_handler_elastic, 1, Functions::ConstantFunction<dim> (u_x_values_right, dim), constraints_elastic, u_x_mask); constraints_elastic.close (); */ constraints_elastic.clear (); constraints_elastic.reinit (locally_relevant_dofs_elastic); DoFTools::make_hanging_node_constraints (dof_handler_elastic, constraints_elastic); /* for (const auto &cell : dof_handler_elastic.active_cell_iterators ()) if (cell->is_locally_owned ()) { for (const auto &face : cell->face_iterators ()) { if (face->at_boundary ()) { const auto center = face->center (); if (std::fabs (center (0) - Domain::x_min) < 1e-12) //face lies at x=x_min { for (const auto vertex_number : cell->vertex_indices ()) { const auto vert = cell->vertex (vertex_number); const double z_mid = 0.5 * (Domain::z_max + Domain::z_min); if (std::fabs (vert (2) - z_mid) < 1e-12 && std::fabs (vert (0) - Domain::x_min) < 1e-12) // vertex at x=x_min,z=z_mid; { const unsigned int z_dof = cell->vertex_dof_index (vertex_number, 2); constraints_elastic.add_line (z_dof); constraints_elastic.set_inhomogeneity (z_dof, 0); const unsigned int x_dof = cell->vertex_dof_index (vertex_number, 0); constraints_elastic.add_line (x_dof); constraints_elastic.set_inhomogeneity (x_dof, 0); } else if (std::fabs (vert (0) - Domain::x_min) < 1e-12) // vertex at x_min { const unsigned int x_dof = cell->vertex_dof_index (vertex_number, 0); constraints_elastic.add_line (x_dof); constraints_elastic.set_inhomogeneity (x_dof, 0); } } } } } } */ const FEValuesExtractors::Scalar u_x (0); const FEValuesExtractors::Scalar u_y (1); const ComponentMask u_x_mask = fe_elastic.component_mask (u_x); const ComponentMask u_y_mask = fe_elastic.component_mask (u_y); applied_load = load_increment*load_step; const double u_x_values_right = 0.5*applied_load; const double u_x_values_left = -0.5*applied_load; /* const double u_x_values_right = ux * load_step; const double u_y_values = uy * load_step; */ const double u_fix = 0.0; VectorTools::interpolate_boundary_values (dof_handler_elastic, 0, Functions::ConstantFunction<dim> (u_x_values_left, dim), constraints_elastic, u_x_mask); VectorTools::interpolate_boundary_values (dof_handler_elastic, 0, Functions::ConstantFunction<dim> (u_fix, dim), constraints_elastic, u_y_mask); VectorTools::interpolate_boundary_values (dof_handler_elastic, 1, Functions::ConstantFunction<dim> (u_x_values_right, dim), constraints_elastic, u_x_mask); constraints_elastic.close (); } template<int dim> void Elasticity<dim>::setup_elasticity(const unsigned int load_step) { TimerOutput::Scope ts(computing_timer, "setup_system_elastic"); // Initialize the dofs contained locally as well as those of the near cells locally_owned_dofs_elastic = dof_handler_elastic.locally_owned_dofs (); locally_relevant_dofs_elastic = DoFTools::extract_locally_relevant_dofs (dof_handler_elastic); locally_relevant_solution_elastic.reinit (locally_owned_dofs_elastic, locally_relevant_dofs_elastic, mpi_communicator); // Initialize the contraints objects for BC and Hanging Nodes during refinement system_rhs_elastic.reinit (locally_owned_dofs_elastic, mpi_communicator); completely_distributed_solution_elastic.reinit (locally_owned_dofs_elastic, mpi_communicator); newton_update_solution_elastic.reinit(locally_owned_dofs_elastic, mpi_communicator); setup_constraints_elastic (load_step); // Qui unizializzo gli hanging nodes constrains (e le BC volendo) // Sparsity pattern initialization (where matrix has nonzero entries) DynamicSparsityPattern dsp(locally_relevant_dofs_elastic); DoFTools::make_sparsity_pattern (dof_handler_elastic, dsp, constraints_elastic, false); SparsityTools::distribute_sparsity_pattern (dsp, dof_handler_elastic.locally_owned_dofs (), mpi_communicator, locally_relevant_dofs_elastic); // Elasticity Matrix system_matrix_elastic.reinit (locally_owned_dofs_elastic, locally_owned_dofs_elastic, dsp, mpi_communicator); } template<int dim> void Elasticity<dim>::assemble_elasticity(const unsigned int load_step, const bool flag_iter) { TimerOutput::Scope ts (computing_timer, "assembly_elastic"); // Clean the current matrices system_rhs_elastic = 0; system_matrix_elastic = 0; // Initialize the FEValues Objects FEValues<dim> fe_values_elastic (fe_elastic, quadrature_formula_elastic, update_values | update_gradients | update_quadrature_points | update_JxW_values); FEValues<dim> fe_values_damage (fe_damage, quadrature_formula_elastic, update_values | update_gradients | update_quadrature_points | update_JxW_values); // Number of DoFs and Gauss points per cell const unsigned int dofs_per_cell = fe_elastic.n_dofs_per_cell (); const unsigned int n_q_points = quadrature_formula_elastic.size (); // Local Matrices and Vector FullMatrix<double> cell_matrix_elastic (dofs_per_cell, dofs_per_cell); Vector<double> cell_rhs_elastic (dofs_per_cell); // Create vector to store the local dof indices std::vector<types::global_dof_index> local_dof_indices (dofs_per_cell); std::vector<double> damage_values (n_q_points); std::vector<SymmetricTensor<2, dim>> strain_values (n_q_points); // loop over the cells for (const auto &cell : dof_handler_elastic.active_cell_iterators ()) { if (cell->is_locally_owned ()) { // Reset the local matrix/rhs of the cell cell_matrix_elastic = 0; cell_rhs_elastic = 0; const typename DoFHandler<dim>::active_cell_iterator damage_cell = cell->as_dof_handler_iterator(dof_handler_damage); // const DoFHandler<dim>::active_cell_iterator damage_cell = Triangulation<dim>::active_cell_iterator (cell)->as_dof_handler_iterator (dof_handler_damage); fe_values_elastic.reinit (cell); fe_values_damage.reinit (damage_cell); const FEValuesExtractors::Vector displacements (/* first vector component = */0); fe_values_elastic[displacements].get_function_symmetric_gradients (locally_relevant_solution_elastic, strain_values); fe_values_damage.get_function_values(locally_relevant_solution_damage, damage_values); // loop over the gauss point of the cell for (const unsigned int q_point : fe_values_elastic.quadrature_point_indices ()) { // Estraggo i valori relevant sui punti di gauss const double d = damage_values[q_point]; for (const unsigned int i : fe_values_elastic.dof_indices ()) { const unsigned int component_i = fe_elastic.system_to_component_index (i).first; for (const unsigned int j : fe_values_elastic.dof_indices ()) { const unsigned int component_j = fe_elastic.system_to_component_index (j).first; cell_matrix_elastic (i, j) += (std::pow((1 - d), 2) + k_res) * ((fe_values_elastic.shape_grad (i, q_point)[component_i] * lambda (E, nu) * fe_values_elastic.shape_grad (j, q_point)[component_j]) + (fe_values_elastic.shape_grad (i, q_point)[component_j] * mu (E, nu) * fe_values_elastic.shape_grad (j, q_point)[component_i]) + ((component_i == component_j) ? (fe_values_elastic.shape_grad (i, q_point) * mu (E, nu) * fe_values_elastic.shape_grad (j, q_point)) : 0) ) * fe_values_elastic.JxW (q_point); // } cell_rhs_elastic (i) += fe_values_elastic.shape_value (i, q_point) * 0 * fe_values_elastic.JxW (q_point); } } cell->get_dof_indices (local_dof_indices); constraints_elastic.distribute_local_to_global (cell_matrix_elastic, cell_rhs_elastic, local_dof_indices, system_matrix_elastic, system_rhs_elastic); } } system_matrix_elastic.compress (VectorOperation::add); system_rhs_elastic.compress (VectorOperation::add); /* // Now set BC const FEValuesExtractors::Scalar u_x (0); const FEValuesExtractors::Scalar u_y (1); const FEValuesExtractors::Scalar u_z (2); const ComponentMask u_x_mask = fe_elastic.component_mask (u_x); const ComponentMask u_y_mask = fe_elastic.component_mask (u_y); const ComponentMask u_z_mask = fe_elastic.component_mask (u_z); applied_load = load_increment*load_step; const double u_x_values_right = 0.5*applied_load; const double u_x_values_left = -0.5*applied_load; std::map<types::global_dof_index, double> boundary_values; Point<dim> point_one, point_two; point_one(0) = 0.5*L; point_one(1) = 0.; point_one(2) = 0.; point_two(0) = 0.5*L; point_two(1) = H; point_two(2) = 0.; typename DoFHandler<dim>::active_cell_iterator cell = dof_handler_elastic.begin_active(), endc = dof_handler_elastic.end(); */ /* // Set up Punctual BC bool evaluation_point_found = false; for (; (cell!=endc) && !evaluation_point_found; ++cell) { if (cell->is_locally_owned()) { for (unsigned int vertex=0; vertex<GeometryInfo<dim>::vertices_per_cell; ++vertex) { if (cell->vertex(vertex).distance (point_one) < cell->diameter() * 1e-12) { // Block displacement on the mid point at y = 0 boundary_values[cell->vertex_dof_index(vertex,0)]=0.; boundary_values[cell->vertex_dof_index(vertex,1)]=0.; boundary_values[cell->vertex_dof_index(vertex,2)]=0.; evaluation_point_found = true; } if (cell->vertex(vertex).distance (point_two) < cell->diameter() * 1e-12) { // Block only ux, uz at midpoint at y = H boundary_values[cell->vertex_dof_index(vertex,0)]=0.; boundary_values[cell->vertex_dof_index(vertex,2)]=0.; evaluation_point_found = true; } } } } */ // Set the displacement on the left face /* if (flag_iter == true) { VectorTools::interpolate_boundary_values (dof_handler_elastic, 0, Functions::ConstantFunction<dim> (u_x_values_left, dim), boundary_values, u_x_mask); VectorTools::interpolate_boundary_values (dof_handler_elastic, 1, Functions::ConstantFunction<dim> (u_x_values_right, dim), boundary_values, u_x_mask); } else { VectorTools::interpolate_boundary_values (dof_handler_elastic, 0, Functions::ConstantFunction<dim> (0., dim), boundary_values, u_x_mask); VectorTools::interpolate_boundary_values (dof_handler_elastic, 1, Functions::ConstantFunction<dim> (0., dim), boundary_values, u_x_mask); } PETScWrappers::MPI::Vector tmp(locally_owned_dofs_elastic, mpi_communicator); MatrixTools::apply_boundary_values(boundary_values, system_matrix_elastic, tmp, system_rhs_elastic, false); if (flag_iter == true) completely_distributed_solution_elastic = tmp; else newton_update_solution_elastic = tmp; */ } template<int dim> void Elasticity<dim>::solve_linear_problem(const bool solve_step) { TimerOutput::Scope ts (computing_timer, "solve_linear_system_elastic"); // CG SolverControl solver_control (10000, 1e-12* system_rhs_elastic.l2_norm()); SolverCG<PETScWrappers::MPI::Vector> solver (solver_control); /* PETScWrappers::PreconditionBoomerAMG::AdditionalData data; PETScWrappers::PreconditionBoomerAMG preconditioner; preconditioner.initialize (system_matrix_elastic, data); */ PETScWrappers::PreconditionBlockJacobi preconditioner(system_matrix_elastic); solver.solve (system_matrix_elastic, completely_distributed_solution_elastic, system_rhs_elastic, preconditioner); pcout << " Solved in " << solver_control.last_step () << " iterations." << std::endl; constraints_elastic.distribute (completely_distributed_solution_elastic); locally_relevant_solution_elastic = completely_distributed_solution_elastic; } // ----------------------------- // ---------- DAMAGE ----------- // ----------------------------- template<int dim> void Elasticity<dim>::setup_constraints_alpha() { constraints_damage.clear (); constraints_damage.reinit (locally_relevant_dofs_damage); DoFTools::make_hanging_node_constraints (dof_handler_damage, constraints_damage); constraints_damage.close (); } template<int dim> void Elasticity<dim>::setup_system_alpha() { TimerOutput::Scope ts (computing_timer, "setup_system_damage"); locally_owned_dofs_damage = dof_handler_damage.locally_owned_dofs (); locally_relevant_dofs_damage = DoFTools::extract_locally_relevant_dofs (dof_handler_damage); locally_relevant_solution_damage.reinit (locally_owned_dofs_damage, locally_relevant_dofs_damage, mpi_communicator); locally_damageLB.reinit (locally_owned_dofs_damage, locally_relevant_dofs_damage, mpi_communicator); system_rhs_damage.reinit (locally_owned_dofs_damage, mpi_communicator); completely_distributed_solution_damage.reinit (locally_owned_dofs_damage, mpi_communicator); completely_distributed_damageLB.reinit (locally_owned_dofs_damage, mpi_communicator); completely_distributed_damageLB = completely_distributed_damageLB_old; completely_distributed_damageUB.reinit (locally_owned_dofs_damage, mpi_communicator); completely_distributed_damageUB = 1; DynamicSparsityPattern dsp (locally_relevant_dofs_damage); DoFTools::make_sparsity_pattern (dof_handler_damage, dsp, constraints_damage, false); SparsityTools::distribute_sparsity_pattern (dsp, dof_handler_damage.locally_owned_dofs (), mpi_communicator, locally_relevant_dofs_damage); system_matrix_damage.reinit (locally_owned_dofs_damage, locally_owned_dofs_damage, dsp, mpi_communicator); } template<int dim> void Elasticity<dim>::assemble_system_alpha(PETScWrappers::MPI::Vector &present_solution_alpha, PETScWrappers::MPI::Vector &system_rhs_alpha) { TimerOutput::Scope ts (computing_timer, "assembly_elastic"); // Clean the current matrices system_rhs_damage = 0; system_matrix_damage = 0; FEValues<dim> fe_values_damage (fe_damage, quadrature_formula_damage, update_values | update_gradients | update_JxW_values | update_quadrature_points); FEValues<dim> fe_values_elastic (fe_elastic, quadrature_formula_damage, update_values | update_gradients | update_JxW_values | update_quadrature_points); const unsigned int dofs_per_cell = fe_damage.n_dofs_per_cell (); const unsigned int n_q_points = quadrature_formula_damage.size (); FullMatrix<double> cell_matrix_damage (dofs_per_cell, dofs_per_cell); Vector<double> cell_rhs_damage (dofs_per_cell); std::vector<types::global_dof_index> local_dof_indices (dofs_per_cell); std::vector<SymmetricTensor<2, dim>> strain_values (n_q_points); std::vector<double> local_solution_alpha(n_q_points); std::vector<Tensor<1, dim>> local_grad_alpha (n_q_points); for (const auto &cell : dof_handler_damage.active_cell_iterators ()) { if (cell->is_locally_owned ()) { // Clear degli elementi locali cell_matrix_damage = 0; cell_rhs_damage = 0; // Inizializzo i fe_values sulla cella fe_values_damage.reinit (cell); const typename DoFHandler<dim>::active_cell_iterator elastic_cell = cell->as_dof_handler_iterator(dof_handler_elastic); // const DoFHandler<dim>::active_cell_iterator elastic_cell = Triangulation<dim>::active_cell_iterator (cell)->as_dof_handler_iterator (dof_handler_elastic); fe_values_elastic.reinit (elastic_cell); // Estraggo valori danno ed elasticità fe_values_damage.get_function_values(locally_relevant_solution_damage, local_solution_alpha); fe_values_damage.get_function_gradients(locally_relevant_solution_damage, local_grad_alpha); const FEValuesExtractors::Vector displacements (/* first vector component = */0); fe_values_elastic[displacements].get_function_symmetric_gradients (locally_relevant_solution_elastic, strain_values); // Loop sui punti di gauss for (const unsigned int q_index : fe_values_damage.quadrature_point_indices ()) { // Estraggo i valori relevant sui punti di gauss const SymmetricTensor<2,dim> eps_u = strain_values[q_index]; double elastic_source=0.; elastic_source = 0.5* eps_u * stress_strain_tensor * eps_u; const auto &x_q = fe_values_damage.quadrature_point (q_index); double Gc_dmg = gc(Gc, 0.95, 0.495, 0.505, x_q); for (unsigned int i=0; i<dofs_per_cell; ++i) { for (unsigned int j=0; j<dofs_per_cell; ++j) { cell_matrix_damage(i,j)+= (fe_values_damage.shape_grad(i,q_index) * fe_values_damage.shape_grad(j,q_index) * (2.*Gc_dmg*ell/c_w) + fe_values_damage.shape_value(i,q_index) * fe_values_damage.shape_value(j,q_index) * (Gc_dmg/(ell*c_w)*w_second_alpha() + g_second_alpha()*elastic_source)) * fe_values_damage.JxW(q_index); } cell_rhs_damage(i) += (g_prime_alpha(local_solution_alpha[q_index])*elastic_source+ w_prime_alpha(local_solution_alpha[q_index])*Gc_dmg/(ell*c_w)) * fe_values_damage.shape_value(i,q_index) * fe_values_damage.JxW(q_index); cell_rhs_damage(i) += (local_grad_alpha[q_index]*2.*Gc_dmg*ell/c_w) * fe_values_damage.shape_grad(i,q_index) * fe_values_damage.JxW(q_index); } } cell->get_dof_indices(local_dof_indices); constraints_damage.distribute_local_to_global (cell_matrix_damage, cell_rhs_damage, local_dof_indices, system_matrix_damage, system_rhs_damage); } } system_matrix_damage.compress (VectorOperation::add); system_rhs_damage.compress (VectorOperation::add); // Set BC on damage std::map<types::global_dof_index, double> boundary_values; VectorTools::interpolate_boundary_values(dof_handler_damage, 0, Functions::ZeroFunction<dim>(), boundary_values); VectorTools::interpolate_boundary_values(dof_handler_damage, 1, Functions::ZeroFunction<dim>(), boundary_values); // Qui riuso il vettore petsc MPI cosi da applicarci le BC PETScWrappers::MPI::Vector tmp(locally_owned_dofs_damage, mpi_communicator); MatrixTools::apply_boundary_values(boundary_values, system_matrix_damage, tmp, system_rhs_damage, false); completely_distributed_solution_damage = tmp; } // Function used to create the FormFunction Input for the SNESSetFunction template <int dim> PetscErrorCode Elasticity<dim>::FormFunction(SNES snes, Vec x, Vec f, void* ctx) { const auto p_ctx = static_cast<Elasticity*>(ctx); p_ctx->assemble_system_alpha(p_ctx->completely_distributed_solution_damage, p_ctx->system_rhs_damage); return 0; } // Function used to create the FormFunction Input for the SNESSetJacobian template <int dim> PetscErrorCode Elasticity<dim>::FormJacobian(SNES snes, Vec x, Mat jac, Mat B, void* ctx) { const auto p_ctx = static_cast<Elasticity*>(ctx); p_ctx->system_matrix_damage; return 0; } // ----------------------------- // ---------- OUTPUT ----------- // ----------------------------- template <int dim> void Elasticity<dim>::output_results (const unsigned int load_step) const { std::vector<std::string> displacement_names (dim, "displacement"); std::vector<DataComponentInterpretation::DataComponentInterpretation> displacement_component_interpretation (dim, DataComponentInterpretation::component_is_part_of_vector); DataOut<dim> data_out_phasefield; data_out_phasefield.add_data_vector (dof_handler_elastic, locally_relevant_solution_elastic, displacement_names, displacement_component_interpretation); data_out_phasefield.add_data_vector (dof_handler_damage, locally_relevant_solution_damage, "damage"); Vector<double> subdomain (triangulation.n_active_cells ()); for (unsigned int i = 0; i < subdomain.size (); ++i) { subdomain (i) = triangulation.locally_owned_subdomain (); } data_out_phasefield.add_data_vector (subdomain, "subdomain"); data_out_phasefield.build_patches (); const std::string pvtu_filename = data_out_phasefield.write_vtu_with_pvtu_record ("./", "solution", load_step, mpi_communicator, 2, 0); if (this_mpi_process == 0) { static std::vector<std::pair<double, std::string>> times_and_names; times_and_names.push_back(std::pair<double, std::string>(load_step, pvtu_filename)); std::ofstream pvd_output("./solution_u.pvd"); DataOutBase::write_pvd_record(pvd_output, times_and_names); } } // ----------------------------- // ----------- RUN ------------- // ----------------------------- template <int dim> void Elasticity<dim>::run() { Timer timer; timer.start (); pcout << "Running on " << Utilities::MPI::n_mpi_processes (mpi_communicator) << " MPI rank(s)..." << std::endl; create_mesh(); // Loop over load steps for (unsigned int load_step = 0; load_step <= num_load_steps; load_step++) { pcout << " --- Load increment number : " << load_step << std::endl; double error_alternate = 1.0; const double error_toll = 1.e-5; unsigned int iter_counter_am = 0; const unsigned int max_iteration = 500; double error_elastic; const double error_toll_elastic=1.e-6; unsigned int iter_elastic; const unsigned int max_iteration_elastic = 10; bool solve_step; // Alternate Minimization while (error_alternate > error_toll && iter_counter_am <max_iteration) { pcout << " ------ Alternate minimization: " << iter_counter_am << std::endl; // --- Elasticity problem pcout << " --- Solving Elastic problem..." << std::endl; iter_elastic = 0; solve_step = true; setup_elasticity (load_step); assemble_elasticity (load_step, solve_step); solve_linear_problem (solve_step); // Damage problem pcout << " --- Solving Damage problem..." << std::endl; setup_constraints_alpha(); setup_system_alpha(); // Solve with SNES SNES snes; PetscErrorCode ierr; ierr = SNESCreate(mpi_communicator, &snes); ierr = SNESSetType(snes, SNESVINEWTONRSLS); ierr = SNESSetFunction(snes, system_rhs_damage, FormFunction, this); ierr = SNESSetJacobian(snes, system_matrix_damage, system_matrix_damage, FormJacobian, this); ierr = SNESVISetVariableBounds(snes, completely_distributed_damageLB, completely_distributed_damageUB); ierr = SNESSetFromOptions(snes); ierr = SNESSolve(snes, nullptr, completely_distributed_solution_damage); ierr = SNESDestroy(&snes); // End SNES constraints_damage.distribute(completely_distributed_solution_damage); locally_relevant_solution_damage = completely_distributed_solution_damage; // Update ghost values after the solution locally_relevant_solution_elastic.update_ghost_values(); locally_relevant_solution_damage.update_ghost_values(); // Check convergence PETScWrappers::MPI::Vector temp_damage(locally_owned_dofs_damage, mpi_communicator); temp_damage = locally_relevant_solution_damage; temp_damage -= completely_distributed_solution_damage_old; error_alternate = temp_damage.linfty_norm(); pcout << " Number of iteration: " << iter_counter_am << std::endl; pcout << " Error_on_alpha: " << error_alternate << std::endl; pcout << " Alpha_max: " << completely_distributed_solution_damage.linfty_norm() << std::endl; // Prepare for refinement completely_distributed_solution_elastic_old = locally_relevant_solution_elastic; completely_distributed_solution_damage_old = locally_relevant_solution_damage; if (error_alternate > error_toll) { refine_mesh(load_step); pcout << " Total New Number of globally active cells: " << triangulation.n_global_active_cells () << std::endl << " New Number of degrees of freedom for elasticity: " << dof_handler_elastic.n_dofs () << std::endl; } output_results (load_step*100 + iter_counter_am); iter_counter_am++; } completely_distributed_damageLB = completely_distributed_solution_damage; completely_distributed_damageLB_old = completely_distributed_solution_damage; output_results (load_step*100+max_iteration); computing_timer.print_summary (); computing_timer.reset (); pcout << std::endl; } timer.stop (); pcout << "Total run time: " << timer.wall_time () << " seconds." << std::endl; } } // End of namespace Elasticity // ----------------------------- // ---------- MAIIN ------------ // ----------------------------- int main (int argc, char *argv[]) { try { using namespace dealii; using namespace elas; Utilities::MPI::MPI_InitFinalize mpi_initialization (argc, argv, 1); Elasticity<2> elasticity; elasticity.run (); } catch (std::exception &exc) { std::cerr << std::endl << std::endl << "----------------------------------------------------" << std::endl; std::cerr << "Exception on processing: " << std::endl << exc.what () << std::endl << "Aborting!" << std::endl << "----------------------------------------------------" << std::endl; return 1; } catch (...) { std::cerr << std::endl << std::endl << "----------------------------------------------------" << std::endl; std::cerr << "Unknown exception!" << std::endl << "Aborting!" << std::endl << "----------------------------------------------------" << std::endl; return 1; } return 0; }