diff --git a/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.cc b/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.cc index 46b64efc5..9ddf21d73 100644 --- a/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.cc +++ b/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.cc @@ -1,1045 +1,984 @@ /** * @file material_cohesive_linear.cc * * @author Marco Vocialta * @author Mauro Corrado * * @date creation: Tue May 08 2012 * @date last modification: Thu Nov 19 2015 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * @section LICENSE * * Copyright (©) 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include #include /* -------------------------------------------------------------------------- */ #include "material_cohesive_linear.hh" #include "solid_mechanics_model_cohesive.hh" #include "sparse_matrix.hh" #include "dof_synchronizer.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template MaterialCohesiveLinear::MaterialCohesiveLinear(SolidMechanicsModel & model, const ID & id) : MaterialCohesive(model,id), sigma_c_eff("sigma_c_eff", *this), delta_c_eff("delta_c_eff", *this), insertion_stress("insertion_stress", *this), opening_prec("opening_prec", *this), residual_sliding("residual_sliding", *this), friction_force("friction_force", *this), reduction_penalty("reduction_penalty", *this) { AKANTU_DEBUG_IN(); this->registerParam("beta", beta, Real(0.), _pat_parsable | _pat_readable, "Beta parameter"); this->registerParam("G_c", G_c, Real(0.), _pat_parsable | _pat_readable, "Mode I fracture energy"); this->registerParam("penalty", penalty, Real(0.), _pat_parsable | _pat_readable, "Penalty coefficient"); this->registerParam("volume_s", volume_s, Real(0.), _pat_parsable | _pat_readable, "Reference volume for sigma_c scaling"); this->registerParam("m_s", m_s, Real(1.), _pat_parsable | _pat_readable, "Weibull exponent for sigma_c scaling"); this->registerParam("kappa", kappa, Real(1.), _pat_parsable | _pat_readable, "Kappa parameter"); this->registerParam("contact_after_breaking", contact_after_breaking, false, _pat_parsable | _pat_readable, "Activation of contact when the elements are fully damaged"); this->registerParam("max_quad_stress_insertion", max_quad_stress_insertion, false, _pat_parsable | _pat_readable, "Insertion of cohesive element when stress is high enough just on one quadrature point"); this->registerParam("friction", friction, false, _pat_parsable | _pat_readable, "Activation of friction in case of contact"); this->registerParam("mu", mu_max, Real(0.), _pat_parsable | _pat_readable, "Maximum value of the friction coefficient"); this->registerParam("penalty_for_friction", friction_penalty, Real(0.), _pat_parsable | _pat_readable, "Penalty parameter for the friction behavior"); this->registerParam("recompute", recompute, false, _pat_parsable | _pat_modifiable, "recompute solution"); use_previous_delta_max = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialCohesiveLinear::initMaterial() { AKANTU_DEBUG_IN(); MaterialCohesive::initMaterial(); /// compute scalars beta2_kappa2 = beta * beta/kappa/kappa; beta2_kappa = beta * beta/kappa; if (Math::are_float_equal(beta, 0)) beta2_inv = 0; else beta2_inv = 1./beta/beta; sigma_c_eff.initialize(1); delta_c_eff.initialize(1); insertion_stress.initialize(spatial_dimension); opening_prec.initialize(spatial_dimension); friction_force.initialize(spatial_dimension); residual_sliding.initialize(1); reduction_penalty.initialize(1); if (!Math::are_float_equal(delta_c, 0.)) delta_c_eff.setDefaultValue(delta_c); else delta_c_eff.setDefaultValue(2 * G_c / sigma_c); if (model->getIsExtrinsic()) scaleInsertionTraction(); residual_sliding.initializeHistory(); opening_prec.initializeHistory(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialCohesiveLinear::scaleInsertionTraction() { AKANTU_DEBUG_IN(); // do nothing if volume_s hasn't been specified by the user if (Math::are_float_equal(volume_s, 0.)) return; const Mesh & mesh_facets = model->getMeshFacets(); const FEEngine & fe_engine = model->getFEEngine(); const FEEngine & fe_engine_facet = model->getFEEngine("FacetsFEEngine"); // loop over facet type Mesh::type_iterator first = mesh_facets.firstType(spatial_dimension - 1); Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1); Real base_sigma_c = sigma_c; for(;first != last; ++first) { ElementType type_facet = *first; const Array< std::vector > & facet_to_element = mesh_facets.getElementToSubelement(type_facet); UInt nb_facet = facet_to_element.getSize(); UInt nb_quad_per_facet = fe_engine_facet.getNbIntegrationPoints(type_facet); // iterator to modify sigma_c for all the quadrature points of a facet Array::vector_iterator sigma_c_iterator = sigma_c(type_facet).begin_reinterpret(nb_quad_per_facet, nb_facet); for (UInt f = 0; f < nb_facet; ++f, ++sigma_c_iterator) { const std::vector & element_list = facet_to_element(f); // compute bounding volume Real volume = 0; std::vector::const_iterator elem = element_list.begin(); std::vector::const_iterator elem_end = element_list.end(); for (; elem != elem_end; ++elem) { if (*elem == ElementNull) continue; // unit vector for integration in order to obtain the volume UInt nb_quadrature_points = fe_engine.getNbIntegrationPoints(elem->type); Vector unit_vector(nb_quadrature_points, 1); volume += fe_engine.integrate(unit_vector, elem->type, elem->element, elem->ghost_type); } // scale sigma_c *sigma_c_iterator -= base_sigma_c; *sigma_c_iterator *= std::pow(volume_s / volume, 1. / m_s); *sigma_c_iterator += base_sigma_c; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialCohesiveLinear::checkInsertion(bool check_only) { AKANTU_DEBUG_IN(); const Mesh & mesh_facets = model->getMeshFacets(); CohesiveElementInserter & inserter = model->getElementInserter(); Real tolerance = Math::getTolerance(); Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1); Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1); for (; it != last; ++it) { ElementType type_facet = *it; ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet); const Array & facets_check = inserter.getCheckFacets(type_facet); Array & f_insertion = inserter.getInsertionFacets(type_facet); Array & f_filter = facet_filter(type_facet); Array & sig_c_eff = sigma_c_eff(type_cohesive); Array & del_c = delta_c_eff(type_cohesive); Array & ins_stress = insertion_stress(type_cohesive); Array & trac_old = tractions_old(type_cohesive); Array & open_prec = opening_prec(type_cohesive); Array & res_sliding = residual_sliding(type_cohesive); Array & red_penalty = reduction_penalty(type_cohesive); const Array & f_stress = model->getStressOnFacets(type_facet); const Array & sigma_lim = sigma_c(type_facet); Real max_ratio = 0.; UInt index_f = 0; UInt index_filter = 0; UInt nn = 0; UInt nb_quad_facet = model->getFEEngine("FacetsFEEngine").getNbIntegrationPoints(type_facet); UInt nb_facet = f_filter.getSize(); // if (nb_facet == 0) continue; Array::const_iterator sigma_lim_it = sigma_lim.begin(); Matrix stress_tmp(spatial_dimension, spatial_dimension); Matrix normal_traction(spatial_dimension, nb_quad_facet); Vector stress_check(nb_quad_facet); UInt sp2 = spatial_dimension * spatial_dimension; const Array & tangents = model->getTangents(type_facet); const Array & normals = model->getFEEngine("FacetsFEEngine").getNormalsOnIntegrationPoints(type_facet); Array::const_vector_iterator normal_begin = normals.begin(spatial_dimension); Array::const_vector_iterator tangent_begin = tangents.begin(tangents.getNbComponent()); Array::const_matrix_iterator facet_stress_begin = f_stress.begin(spatial_dimension, spatial_dimension * 2); std::vector new_sigmas; std::vector< Vector > new_normal_traction; std::vector new_delta_c; // loop over each facet belonging to this material for (UInt f = 0; f < nb_facet; ++f, ++sigma_lim_it) { UInt facet = f_filter(f); // skip facets where check shouldn't be realized if (!facets_check(facet)) continue; // compute the effective norm on each quadrature point of the facet for (UInt q = 0; q < nb_quad_facet; ++q) { UInt current_quad = facet * nb_quad_facet + q; const Vector & normal = normal_begin[current_quad]; const Vector & tangent = tangent_begin[current_quad]; const Matrix & facet_stress_it = facet_stress_begin[current_quad]; // compute average stress on the current quadrature point Matrix stress_1(facet_stress_it.storage(), spatial_dimension, spatial_dimension); Matrix stress_2(facet_stress_it.storage() + sp2, spatial_dimension, spatial_dimension); stress_tmp.copy(stress_1); stress_tmp += stress_2; stress_tmp /= 2.; Vector normal_traction_vec(normal_traction(q)); // compute normal and effective stress stress_check(q) = computeEffectiveNorm(stress_tmp, normal, tangent, normal_traction_vec); } // verify if the effective stress overcomes the threshold Real final_stress = stress_check.mean(); if (max_quad_stress_insertion) final_stress = *std::max_element(stress_check.storage(), stress_check.storage() + nb_quad_facet); if (final_stress > (*sigma_lim_it - tolerance)) { if (model->isExplicit()){ f_insertion(facet) = true; if (!check_only) { // store the new cohesive material parameters for each quadrature point for (UInt q = 0; q < nb_quad_facet; ++q) { Real new_sigma = stress_check(q); Vector normal_traction_vec(normal_traction(q)); if (spatial_dimension != 3) normal_traction_vec *= -1.; new_sigmas.push_back(new_sigma); new_normal_traction.push_back(normal_traction_vec); Real new_delta; // set delta_c in function of G_c or a given delta_c value if (Math::are_float_equal(delta_c, 0.)) new_delta = 2 * G_c / new_sigma; else new_delta = (*sigma_lim_it) / new_sigma * delta_c; new_delta_c.push_back(new_delta); } } }else{ Real ratio = final_stress/(*sigma_lim_it); if (ratio > max_ratio){ ++nn; max_ratio = ratio; index_f = f; index_filter = f_filter(f); } } } } /// Insertion of only 1 cohesive element in case of implicit approach. The one subjected to the highest stress. if (!model->isExplicit()){ StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Array abs_max(comm.getNbProc()); abs_max(comm.whoAmI()) = max_ratio; comm.allGather(abs_max.storage(), 1); Array::scalar_iterator it = std::max_element(abs_max.begin(), abs_max.end()); Int pos = it - abs_max.begin(); if (pos != comm.whoAmI()) { AKANTU_DEBUG_OUT(); return; } if (nn) { f_insertion(index_filter) = true; if (!check_only) { // Array::iterator > normal_traction_it = // normal_traction.begin_reinterpret(nb_quad_facet, spatial_dimension, nb_facet); Array::const_iterator sigma_lim_it = sigma_lim.begin(); for (UInt q = 0; q < nb_quad_facet; ++q) { // Vector ins_s(normal_traction_it[index_f].storage() + q * spatial_dimension, // spatial_dimension); Real new_sigma = (sigma_lim_it[index_f]); Vector normal_traction_vec(spatial_dimension, 0.0); new_sigmas.push_back(new_sigma); new_normal_traction.push_back(normal_traction_vec); Real new_delta; //set delta_c in function of G_c or a given delta_c value if (!Math::are_float_equal(delta_c, 0.)) new_delta = delta_c; else new_delta = 2 * G_c / (new_sigma); new_delta_c.push_back(new_delta); } } } } // update material data for the new elements UInt old_nb_quad_points = sig_c_eff.getSize(); UInt new_nb_quad_points = new_sigmas.size(); sig_c_eff.resize(old_nb_quad_points + new_nb_quad_points); ins_stress.resize(old_nb_quad_points + new_nb_quad_points); trac_old.resize(old_nb_quad_points + new_nb_quad_points); del_c.resize(old_nb_quad_points + new_nb_quad_points); open_prec.resize(old_nb_quad_points + new_nb_quad_points); res_sliding.resize(old_nb_quad_points + new_nb_quad_points); red_penalty.resize(old_nb_quad_points + new_nb_quad_points); for (UInt q = 0; q < new_nb_quad_points; ++q) { sig_c_eff(old_nb_quad_points + q) = new_sigmas[q]; del_c(old_nb_quad_points + q) = new_delta_c[q]; res_sliding(old_nb_quad_points + q) = 0.; red_penalty(old_nb_quad_points + q) = false; for (UInt dim = 0; dim < spatial_dimension; ++dim) { ins_stress(old_nb_quad_points + q, dim) = new_normal_traction[q](dim); trac_old(old_nb_quad_points + q, dim) = new_normal_traction[q](dim); open_prec(old_nb_quad_points + q, dim) = 0.; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialCohesiveLinear::computeTraction(const Array & normal, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators Array::vector_iterator traction_it = tractions(el_type, ghost_type).begin(spatial_dimension); Array::vector_iterator opening_it = opening(el_type, ghost_type).begin(spatial_dimension); Array::vector_iterator opening_prec_it = opening_prec(el_type, ghost_type).begin(spatial_dimension); Array::vector_iterator opening_prec_prev_it = opening_prec.previous(el_type, ghost_type).begin(spatial_dimension); Array::vector_iterator contact_traction_it = contact_tractions(el_type, ghost_type).begin(spatial_dimension); Array::vector_iterator contact_opening_it = contact_opening(el_type, ghost_type).begin(spatial_dimension); Array::const_iterator< Vector > normal_it = normal.begin(spatial_dimension); Array::vector_iterator traction_end = tractions(el_type, ghost_type).end(spatial_dimension); Array::iteratorsigma_c_it = sigma_c_eff(el_type, ghost_type).begin(); Array::iteratordelta_max_it = delta_max(el_type, ghost_type).begin(); Array::iteratordelta_max_prev_it = delta_max.previous(el_type, ghost_type).begin(); Array::iteratordelta_c_it = delta_c_eff(el_type, ghost_type).begin(); Array::iteratordamage_it = damage(el_type, ghost_type).begin(); Array::vector_iterator insertion_stress_it = insertion_stress(el_type, ghost_type).begin(spatial_dimension); Array::iteratorres_sliding_it = residual_sliding(el_type, ghost_type).begin(); Array::iteratorres_sliding_prev_it = residual_sliding.previous(el_type, ghost_type).begin(); Array::vector_iterator friction_force_it = friction_force(el_type, ghost_type).begin(spatial_dimension); Array::iterator reduction_penalty_it = reduction_penalty(el_type, ghost_type).begin(); Real * memory_space = new Real[2*spatial_dimension]; Vector normal_opening(memory_space, spatial_dimension); Vector tangential_opening(memory_space + spatial_dimension, spatial_dimension); - Vector open_prec(spatial_dimension); - Vector open(spatial_dimension); - Real max_delta_open = 0.0; - Int nn = 0; + // Vector open_prec(spatial_dimension); + // Vector open(spatial_dimension); /// loop on each quadrature point for (; traction_it != traction_end; ++traction_it, ++opening_it, ++opening_prec_it, ++normal_it, ++sigma_c_it, ++delta_max_it, ++delta_c_it, ++damage_it, ++contact_traction_it, ++insertion_stress_it, ++contact_opening_it, ++delta_max_prev_it, ++res_sliding_it, ++res_sliding_prev_it, ++opening_prec_prev_it, ++friction_force_it, ++reduction_penalty_it) { if (!model->isExplicit()) *delta_max_it = *delta_max_prev_it; // check if the local displacement increment is too large. If so, // reduce arbitrary it in order to prevent problems of // instability Real normal_opening_prec_norm = opening_prec_it->dot(*normal_it); - open_prec = *opening_prec_it; - Real open_prec_norm = open_prec.norm(); - open = *opening_it; - Real open_norm = open.norm(); - Real delta_open = std::abs(open_norm - open_prec_norm); - - // std::cout << "delta_open UPDATE RESIDUAL = " << delta_open << std::endl; - max_delta_open = std::max(max_delta_open, delta_open); - - // if (delta_open > 1.0e-01){ - // *opening_it = *opening_prec_it + ((*opening_it - *opening_prec_it) / 50.0); - // } - *opening_prec_it = *opening_it; - - Vector aa(spatial_dimension); - aa = *opening_prec_it; - // std::cout << "opening_prec_it = " << aa(0) << ", " << aa(1) << std::endl; +// open_prec = *opening_prec_it; +// Real open_prec_norm = open_prec.norm(); +// open = *opening_it; +// Real open_norm = open.norm(); +// Real delta_open = std::abs(open_norm - open_prec_norm); +// +// // if (delta_open > 1.0e-01){ +// // *opening_it = *opening_prec_it + ((*opening_it - *opening_prec_it) / 50.0); +// // } +// *opening_prec_it = *opening_it; /// compute normal and tangential opening vectors Real normal_opening_norm = opening_it->dot(*normal_it); normal_opening = (*normal_it); normal_opening *= normal_opening_norm; - Vector perpend(spatial_dimension); - perpend = *normal_it; - // std::cout << "normal = " << perpend(0) << perpend(1) << std::endl; - Vector displ(spatial_dimension); - displ = *opening_it; tangential_opening = *opening_it; tangential_opening -= normal_opening; Real tangential_opening_norm = tangential_opening.norm(); /** * compute effective opening displacement * @f$ \delta = \sqrt{ * \frac{\beta^2}{\kappa^2} \Delta_t^2 + \Delta_n^2 } @f$ */ Real delta = tangential_opening_norm * tangential_opening_norm * beta2_kappa2; - ++nn; - // std::cout << "normal opening of gp no. " << nn << " = " << normal_opening_norm << std::endl; bool penetration = normal_opening_norm < -Math::getTolerance(); if (contact_after_breaking == false && Math::are_float_equal(*damage_it, 1.)) penetration = false; /// if during the convergence loop a cohesive element continues to /// jumps from penetration to opening, and convergence is not /// reached, its penalty parameter will be reduced in the - /// recomputation of the same incremental step + /// recomputation of the same incremental step. recompute is set + /// equal to true when convergence is not reached in the + /// solveStepCohesive function and the execution of the program + /// goes back to the main file where the variable load_reduction + /// is set equal to true. if (!model->isExplicit() && !recompute) if ((normal_opening_prec_norm * normal_opening_norm) < -Math::getTolerance()){ *reduction_penalty_it = true; - - // std::cout << "recompute" << recompute << std::endl; } - // Vector friction_force(spatial_dimension); - // friction_force.clear(); if (penetration) { Real current_penalty = 0.; if (recompute && *reduction_penalty_it){ + /// the penalty parameter is locally reduced current_penalty = penalty / 1000.; - // std::cout << "recompute" << recompute << std::endl; - // std::cout << "penalty reduced" << std::endl; } else current_penalty = penalty; /// use penalty coefficient in case of penetration *contact_traction_it = normal_opening; *contact_traction_it *= current_penalty; *contact_opening_it = normal_opening; - /* ----------------------------------------- */ /// ADD FRICTION if (friction){ Real damage = std::min(*delta_max_prev_it / *delta_c_it, Real(1.)); - Real mu = mu_max * damage; - Vector check(spatial_dimension); - check = *opening_prec_prev_it; + Real mu = mu_max * std::sqrt(damage); Real normal_opening_prec_norm = opening_prec_prev_it->dot(*normal_it); Vector normal_opening_prec = (*normal_it); normal_opening_prec *= normal_opening_prec_norm; Real tau_max = mu * current_penalty * (normal_opening_prec.norm()); Real delta_sliding_norm = std::abs(tangential_opening_norm - *res_sliding_prev_it); // tau is the norm of the friction force, acting tangentially to the surface Real tau = std::min(friction_penalty * delta_sliding_norm, tau_max); if ((tangential_opening_norm - *res_sliding_it) < -Math::getTolerance()) tau = -tau; // from tau get the x and y components of friction, to be added in the force vector Vector tangent(spatial_dimension); tangent = tangential_opening / tangential_opening_norm; *friction_force_it = tau * tangent; - // std::cout << "mu = " << mu << std::endl; - //std::cout << "damage = " << damage << std::endl; - // std::cout << "opening_prev_prec_it = " << check(0) << ", " << check(1) << std::endl; - // std::cout << "normal opening prec norm = " << normal_opening_prec_norm << std::endl; - // std::cout << "normal opening prec = " << normal_opening_prec(0) << ", " << normal_opening_prec(1) << std::endl; - // std::cout << "tau_max = " << tau_max << std::endl; - - // std::cout << "friction force = " << friction_force(0) << ", " << friction_force(1) << std::endl; - //update residual_sliding *res_sliding_it = tangential_opening_norm - (tau / friction_penalty); } /// end add friction /* ----------------------------------------- */ /// don't consider penetration contribution for delta *opening_it = tangential_opening; normal_opening.clear(); } else { delta += normal_opening_norm * normal_opening_norm; contact_traction_it->clear(); contact_opening_it->clear(); friction_force_it->clear(); } delta = std::sqrt(delta); /// update maximum displacement and damage *delta_max_it = std::max(*delta_max_it, delta); *damage_it = std::min(*delta_max_it / *delta_c_it, Real(1.)); /** * Compute traction @f$ \mathbf{T} = \left( * \frac{\beta^2}{\kappa} \Delta_t \mathbf{t} + \Delta_n * \mathbf{n} \right) \frac{\sigma_c}{\delta} \left( 1- * \frac{\delta}{\delta_c} \right)@f$ */ - Vector forze(spatial_dimension); if (Math::are_float_equal(*damage_it, 1.)) traction_it->clear(); else if (Math::are_float_equal(*damage_it, 0.)) { if (penetration) traction_it->clear(); else *traction_it = *insertion_stress_it; } else { *traction_it = tangential_opening; *traction_it *= beta2_kappa; *traction_it += normal_opening; AKANTU_DEBUG_ASSERT(*delta_max_it != 0., "Division by zero, tolerance might be too low"); *traction_it *= *sigma_c_it / *delta_max_it * (1. - *damage_it); - - forze = *traction_it; - - // std::cout << "cohesive shear = " << forze(0) << ", " << forze(1) << std::endl; } if (friction) *traction_it += *friction_force_it; - forze = *traction_it; - } - // if (max_delta_open > 1.0e-01) - // std::cout << "max_delta opening = " << max_delta_open << std::endl; - delete [] memory_space; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialCohesiveLinear::checkDeltaMax(GhostType ghost_type) { AKANTU_DEBUG_IN(); - /// This function set a predefined value to the parameter delta_max_prev of the - /// elements that have been inserted in the last loading step for which convergence - /// has not been reached. This is done before reducing the loading and re-doing the step. - /// Otherwise, the updating of delta_max_prev would be done with reference to the - /// non-convergent solution. + /// This function set a predefined value to the parameter + /// delta_max_prev of the elements that have been inserted in the + /// last loading step for which convergence has not been + /// reached. This is done before reducing the loading and re-doing + /// the step. Otherwise, the updating of delta_max_prev would be + /// done with reference to the non-convergent solution. In this + /// function also other variables related to the contact and + /// friction behavior are correctly set. Mesh & mesh = fem_cohesive->getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type, _ek_cohesive); + /// the variable "recompute" is set to true to activate the + /// procedure that reduce the penalty parameter for + /// compression. This procedure is set true only during the phase of + /// load_reduction, that has to be set in the maiin file. The + /// penalty parameter will be reduced only for the elements having + /// reduction_penalty = true. recompute = true; for(; it != last_type; ++it) { Array & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.getSize(); if (nb_element == 0) continue; ElementType el_type = *it; /// define iterators Array::iteratordelta_max_it = delta_max(el_type, ghost_type).begin(); Array::iteratordelta_max_end = delta_max(el_type, ghost_type).end(); Array::iteratordelta_max_prev_it = delta_max.previous(el_type, ghost_type).begin(); Array::iteratordelta_c_it = delta_c_eff(el_type, ghost_type).begin(); - Array::vector_iterator opening_prec_it = - opening_prec(el_type, ghost_type).begin(spatial_dimension); - - Array::vector_iterator opening_prec_prev_it = - opening_prec.previous(el_type, ghost_type).begin(spatial_dimension); +// Array::vector_iterator opening_prec_it = +// opening_prec(el_type, ghost_type).begin(spatial_dimension); +// +// Array::vector_iterator opening_prec_prev_it = +// opening_prec.previous(el_type, ghost_type).begin(spatial_dimension); Array::iteratorres_sliding_it = residual_sliding(el_type, ghost_type).begin(); Array::iteratorres_sliding_prev_it = residual_sliding.previous(el_type, ghost_type).begin(); /// loop on each quadrature point for (; delta_max_it != delta_max_end; ++delta_max_it, ++delta_max_prev_it, ++delta_c_it, - ++opening_prec_it, ++opening_prec_prev_it, + // ++opening_prec_it, ++opening_prec_prev_it, ++res_sliding_it, ++res_sliding_prev_it) { if (*delta_max_prev_it == 0) /// elements inserted in the last incremental step, that did /// not converge *delta_max_it = *delta_c_it / 1000; else /// elements introduced in previous incremental steps, for /// which a correct value of delta_max_prev already exists *delta_max_it = *delta_max_prev_it; /// in case convergence is not reached, set opening_prec to the /// value referred to the previous incremental step - *opening_prec_it = *opening_prec_prev_it; + // *opening_prec_it = *opening_prec_prev_it; - /// the same thing for the residual sliding for the friction law + /// in case convergence is not reached, set "residual_sliding" + /// for the friction behaviour to the value referred to the + /// previous incremental step *res_sliding_it = *res_sliding_prev_it; } } } /* -------------------------------------------------------------------------- */ template void MaterialCohesiveLinear::resetVariables(GhostType ghost_type) { AKANTU_DEBUG_IN(); - /// This function set a predefined value to the parameter delta_max_prev of the - /// elements that have been inserted in the last loading step for which convergence - /// has not been reached. This is done before reducing the loading and re-doing the step. - /// Otherwise, the updating of delta_max_prev would be done with reference to the - /// non-convergent solution. + /// This function set the variables "recompute" and + /// "reduction_penalty" to false. It is called by solveStepCohesive + /// when convergence is reached. Such variables, in fact, have to be + /// false at the beginning of a new incremental step. Mesh & mesh = fem_cohesive->getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type, _ek_cohesive); recompute = false; // std::cout << "RESET VARIABLE" << std::endl; for(; it != last_type; ++it) { Array & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.getSize(); if (nb_element == 0) continue; ElementType el_type = *it; Array::iterator reduction_penalty_it = reduction_penalty(el_type, ghost_type).begin(); Array::iterator reduction_penalty_end = reduction_penalty(el_type, ghost_type).end(); /// loop on each quadrature point for (; reduction_penalty_it != reduction_penalty_end; ++reduction_penalty_it) { *reduction_penalty_it = false; } } } /* -------------------------------------------------------------------------- */ template void MaterialCohesiveLinear::computeTangentTraction(const ElementType & el_type, Array & tangent_matrix, const Array & normal, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators Array::matrix_iterator tangent_it = tangent_matrix.begin(spatial_dimension, spatial_dimension); Array::matrix_iterator tangent_end = tangent_matrix.end(spatial_dimension, spatial_dimension); Array::const_vector_iterator normal_it = normal.begin(spatial_dimension); Array::vector_iterator opening_it = opening(el_type, ghost_type).begin(spatial_dimension); Array::vector_iterator opening_prec_it = opening_prec.previous(el_type, ghost_type).begin(spatial_dimension); /// NB: delta_max_it points on delta_max_previous, i.e. the /// delta_max related to the solution of the previous incremental /// step Array::iteratordelta_max_it = delta_max.previous(el_type, ghost_type).begin(); Array::iteratorsigma_c_it = sigma_c_eff(el_type, ghost_type).begin(); Array::iteratordelta_c_it = delta_c_eff(el_type, ghost_type).begin(); Array::iteratordamage_it = damage(el_type, ghost_type).begin(); Array::iterator< Vector > contact_opening_it = contact_opening(el_type, ghost_type).begin(spatial_dimension); Array::iteratorres_sliding_prev_it = residual_sliding.previous(el_type, ghost_type).begin(); Array::iterator reduction_penalty_it = reduction_penalty(el_type, ghost_type).begin(); Vector normal_opening(spatial_dimension); Vector tangential_opening(spatial_dimension); - Vector open_prec(spatial_dimension); - Vector open(spatial_dimension); - Real max_delta_open = 0.0; - - Array tang_output(spatial_dimension,spatial_dimension); - for (; tangent_it != tangent_end; ++tangent_it, ++normal_it, ++opening_it, ++opening_prec_it, ++delta_max_it, ++sigma_c_it, ++delta_c_it, ++damage_it, ++contact_opening_it, ++res_sliding_prev_it, ++reduction_penalty_it) { - /// check if the local displacement increment is too large. In - /// case, reduce arbitrary it in order to prevent problems of - /// instability - open_prec = *opening_prec_it; - Real open_prec_norm = open_prec.norm(); - // std::cout << "open_prec_norm = " << open_prec_norm << std::endl; - - /// During the update of the residual (called just before the - /// assembly of the matrix) the interpenetrations are stored in - /// the array "contact_opening", therefore, in the array "opening" - /// there are only the tangential components. + /// During the update of the residual the interpenetrations are + /// stored in the array "contact_opening", therefore, in the case + /// of penetration, in the array "opening" there are only the + /// tangential components. *opening_it += *contact_opening_it; - open = *opening_it; - Real open_norm = open.norm(); - // std::cout << "open_norm = " << open_norm << std::endl; - Real delta_open = std::abs(open_norm - open_prec_norm); - - max_delta_open = std::max(max_delta_open, delta_open); - - // if (delta_open > 1.0e-01){ - // *opening_it = *opening_prec_it + ((*opening_it - *opening_prec_it) / 50.0); - // std::cout << "delta_open TANGENT STIFFNESS = " << delta_open << std::endl; - // } - /// compute normal and tangential opening vectors Real normal_opening_norm = opening_it->dot(*normal_it); normal_opening = (*normal_it); normal_opening *= normal_opening_norm; tangential_opening = *opening_it; tangential_opening -= normal_opening; Real tangential_opening_norm = tangential_opening.norm(); bool penetration = normal_opening_norm < -Math::getTolerance(); if (contact_after_breaking == false && Math::are_float_equal(*damage_it, 1.)) penetration = false; Real derivative = 0; // derivative = d(t/delta)/ddelta Real t = 0; Real delta = tangential_opening_norm * tangential_opening_norm * beta2_kappa2; Matrix n_outer_n(spatial_dimension, spatial_dimension); n_outer_n.outerProduct(*normal_it, *normal_it); if (penetration){ Real current_penalty = 0.; - if (recompute && *reduction_penalty_it == 1) + if (recompute && *reduction_penalty_it) current_penalty = penalty / 1000.; else current_penalty = penalty; /// stiffness in compression given by the penalty parameter *tangent_it += n_outer_n; *tangent_it *= current_penalty; /* ------------------------------------- */ /// ADD FRICTION if (friction){ Real damage = std::min(*delta_max_it / *delta_c_it, Real(1.)); + // the friction coefficient mu is increasing with the + // damage. It equals the maximum value when damage = 1. Real mu = mu_max * damage; Real normal_opening_prec_norm = opening_prec_it->dot(*normal_it); Vector normal_opening_prec = (*normal_it); normal_opening_prec *= normal_opening_prec_norm; Real tau_max = mu * current_penalty * normal_opening_prec.norm(); Real delta_sliding_norm = std::abs(tangential_opening_norm - *res_sliding_prev_it); // tau is the norm of the friction force, acting tangentially to the surface Real tau = std::min(friction_penalty * delta_sliding_norm, tau_max); if (tau < tau_max && tau_max > Math::getTolerance()){ Matrix I(spatial_dimension, spatial_dimension); I.eye(1.); Matrix nn(n_outer_n); I -= nn; *tangent_it += I * friction_penalty; } } /// end add friction /* ------------------------------------- */ - /// don't consider penetration contribution for delta - // std::cout << " AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA penetration !!!" << std::endl; - *opening_it = tangential_opening; normal_opening_norm = opening_it->dot(*normal_it); normal_opening = (*normal_it); normal_opening *= normal_opening_norm; - // std::cout << "normal opening in case of penetration = " << normal_opening << std::endl; } else{ delta += normal_opening_norm * normal_opening_norm; } delta = std::sqrt(delta); - /// Delta has to be different from 0 to have finite values of tangential stiffness. - /// At the element insertion, delta = 0. Therefore, a fictictious value is defined, - /// for the evaluation of the first value of K. + /// Delta has to be different from 0 to have finite values of + /// tangential stiffness. At the element insertion, delta = + /// 0. Therefore, a fictictious value is defined, for the + /// evaluation of the first value of K. if (delta < Math::getTolerance()) delta = (*delta_c_it)/1000.; - //if (!penetration){ if (delta >= *delta_max_it){ if (delta <= *delta_c_it){ derivative = -*sigma_c_it/(delta * delta); t = *sigma_c_it * (1 - delta / *delta_c_it); } else { - // std::cout << " BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB delta>delta_c !!!" << std::endl; derivative = 0.; t = 0.; } } else if (delta < *delta_max_it){ Real tmax = *sigma_c_it * (1 - *delta_max_it / *delta_c_it); t = tmax / *delta_max_it * delta; } - // } /// computation of the derivative of the constitutive law (dT/ddelta) Matrix I(spatial_dimension, spatial_dimension); I.eye(beta2_kappa); Matrix nn(n_outer_n); nn *= (1 - beta2_kappa); nn += I; nn *= t/delta; Vector t_tilde(normal_opening); t_tilde *= (1 - beta2_kappa2); Vector mm(*opening_it); mm *= beta2_kappa2; t_tilde += mm; Vector t_hat(normal_opening); t_hat += beta2_kappa * tangential_opening; Matrix prov(spatial_dimension, spatial_dimension); prov.outerProduct(t_hat, t_tilde); prov *= derivative/delta; prov += nn; Matrix tmp(spatial_dimension, spatial_dimension); for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < spatial_dimension; ++j) { tmp(j,i) = prov(i,j); } } *tangent_it += tmp; /// check if the tangential stiffness matrix is symmetric // for (UInt h = 0; h < spatial_dimension; ++h){ // for (UInt l = h; l < spatial_dimension; ++l){ // if (l > h){ // Real k_ls = (*tangent_it)[spatial_dimension*h+l]; // Real k_us = (*tangent_it)[spatial_dimension*l+h]; // // std::cout << "k_ls = " << k_ls << std::endl; // // std::cout << "k_us = " << k_us << std::endl; // if (std::abs(k_ls) > 1e-13 && std::abs(k_us) > 1e-13){ // Real error = std::abs((k_ls - k_us) / k_us); // if (error > 1e-10){ // std::cout << "non symmetric cohesive matrix" << std::endl; // // std::cout << "error " << error << std::endl; // } // } // } // } // } } - - // if (max_delta_open > 1.0e-05) - // std::cout << "max_delta opening > 1e-05 in COMPUTE TANGENT STIFFNESS" << std::endl; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANTIATE_MATERIAL(MaterialCohesiveLinear); __END_AKANTU__ diff --git a/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.hh b/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.hh index 8a73e0eb6..fbe80397b 100644 --- a/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.hh +++ b/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.hh @@ -1,208 +1,208 @@ /** * @file material_cohesive_linear.hh * * @author Marco Vocialta * * @date creation: Tue May 08 2012 * @date last modification: Tue Jul 29 2014 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * @section LICENSE * * Copyright (©) 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "material_cohesive.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_COHESIVE_LINEAR_HH__ #define __AKANTU_MATERIAL_COHESIVE_LINEAR_HH__ /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /** * Cohesive material linear damage for extrinsic case * * parameters in the material files : * - sigma_c : critical stress sigma_c (default: 0) * - beta : weighting parameter for sliding and normal opening (default: 0) * - G_cI : fracture energy for mode I (default: 0) * - G_cII : fracture energy for mode II (default: 0) * - penalty : stiffness in compression to prevent penetration */ template class MaterialCohesiveLinear : public MaterialCohesive { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialCohesiveLinear(SolidMechanicsModel & model, const ID & id = ""); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material parameters virtual void initMaterial(); /// check stress for cohesive elements' insertion virtual void checkInsertion(bool check_only = false); /// compute effective stress norm for insertion check Real computeEffectiveNorm(const Matrix & stress, const Vector & normal, const Vector & tangent, Vector & normal_stress) const; protected: /// constitutive law virtual void computeTraction(const Array & normal, ElementType el_type, GhostType ghost_type = _not_ghost); /// check delta_max for cohesive elements in case of no convergence /// in the solveStep (only for extrinsic-implicit) void checkDeltaMax(GhostType ghost_type = _not_ghost); /// reset variables when convergence is reached (only for /// extrinsic-implicit) void resetVariables(GhostType ghost_type = _not_ghost); /// compute tangent stiffness matrix void computeTangentTraction(const ElementType & el_type, Array & tangent_matrix, const Array & normal, GhostType ghost_type); /** * Scale insertion traction sigma_c according to the volume of the * two elements surrounding a facet * * see the article: F. Zhou and J. F. Molinari "Dynamic crack * propagation with cohesive elements: a methodology to address mesh * dependency" International Journal for Numerical Methods in * Engineering (2004) */ void scaleInsertionTraction(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get sigma_c_eff AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(InsertionTraction, sigma_c_eff, Real); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// beta parameter Real beta; /// beta square inverse to compute effective norm Real beta2_inv; /// mode I fracture energy Real G_c; /// kappa parameter Real kappa; /// constitutive law scalar to compute delta Real beta2_kappa2; /// constitutive law scalar to compute traction Real beta2_kappa; /// penalty coefficient Real penalty; /// reference volume used to scale sigma_c Real volume_s; /// weibull exponent used to scale sigma_c Real m_s; /// maximum value of the friction coefficient Real mu_max; /// penalty parameter for the friction law Real friction_penalty; - /// variable to define if we are recomputing the last loading step + /// variable defining if we are recomputing the last loading step /// after load_reduction bool recompute; /// critical effective stress RandomInternalField sigma_c_eff; /// effective critical displacement (each element can have a /// different value) CohesiveInternalField delta_c_eff; /// stress at insertion CohesiveInternalField insertion_stress; /// delta of the previous step CohesiveInternalField opening_prec; /// history parameter for the friction law CohesiveInternalField residual_sliding; /// friction force CohesiveInternalField friction_force; /// variable that defines if the penalty parameter for compression /// has to be decreased for problems of convergence in the solution /// loops CohesiveInternalField reduction_penalty; /// variable saying if there should be penalty contact also after /// breaking the cohesive elements bool contact_after_breaking; /// insertion of cohesive element when stress is high enough just on /// one quadrature point bool max_quad_stress_insertion; /// variable saying if friction has to be added to the cohesive behavior bool friction; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "material_cohesive_linear_inline_impl.cc" __END_AKANTU__ #endif /* __AKANTU_MATERIAL_COHESIVE_LINEAR_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.cc b/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.cc index 7068f20a2..b8193bb85 100644 --- a/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.cc +++ b/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.cc @@ -1,621 +1,622 @@ /** * @file material_cohesive.cc * * @author Seyedeh Mohadeseh Taheri Mousavi * @author Marco Vocialta * @author Nicolas Richart * * @date creation: Wed Feb 22 2012 * @date last modification: Tue Jul 29 2014 * * @brief Specialization of the material class for cohesive elements * * @section LICENSE * * Copyright (©) 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "material_cohesive.hh" #include "solid_mechanics_model_cohesive.hh" #include "sparse_matrix.hh" #include "dof_synchronizer.hh" #include "aka_random_generator.hh" #include "shape_cohesive.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ MaterialCohesive::MaterialCohesive(SolidMechanicsModel & model, const ID & id) : Material(model, id), facet_filter("facet_filter", id, this->getMemoryID()), fem_cohesive(&(model.getFEEngineClass("CohesiveFEEngine"))), reversible_energy("reversible_energy", *this), total_energy("total_energy", *this), opening("opening", *this), opening_old("opening (old)", *this), tractions("tractions", *this), tractions_old("tractions (old)", *this), contact_tractions("contact_tractions", *this), contact_opening("contact_opening", *this), delta_max("delta max", *this), use_previous_delta_max(false), damage("damage", *this), sigma_c("sigma_c", *this), normal(0, spatial_dimension, "normal") { AKANTU_DEBUG_IN(); this->model = dynamic_cast(&model); this->registerParam("sigma_c", sigma_c, _pat_parsable | _pat_readable, "Critical stress"); this->registerParam("delta_c", delta_c, Real(0.), _pat_parsable | _pat_readable, "Critical displacement"); this->model->getMesh().initElementTypeMapArray(this->element_filter, 1, spatial_dimension, false, _ek_cohesive); if (this->model->getIsExtrinsic()) this->model->getMeshFacets().initElementTypeMapArray(facet_filter, 1, spatial_dimension - 1); this->reversible_energy.initialize(1 ); this->total_energy .initialize(1 ); this->tractions_old .initialize(spatial_dimension); this->tractions .initialize(spatial_dimension); this->opening_old .initialize(spatial_dimension); this->contact_tractions.initialize(spatial_dimension); this->contact_opening .initialize(spatial_dimension); this->opening .initialize(spatial_dimension); this->delta_max .initialize(1 ); this->damage .initialize(1 ); if (this->model->getIsExtrinsic()) this->sigma_c.initialize(1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ MaterialCohesive::~MaterialCohesive() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::initMaterial() { AKANTU_DEBUG_IN(); Material::initMaterial(); if (this->use_previous_delta_max) this->delta_max.initializeHistory(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::assembleResidual(GhostType ghost_type) { AKANTU_DEBUG_IN(); #if defined(AKANTU_DEBUG_TOOLS) debug::element_manager.printData(debug::_dm_material_cohesive, "Cohesive Tractions", tractions); #endif Array & residual = const_cast &>(model->getResidual()); Mesh & mesh = fem_cohesive->getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type, _ek_cohesive); for(; it != last_type; ++it) { Array & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.getSize(); if (nb_element == 0) continue; const Array & shapes = fem_cohesive->getShapes(*it, ghost_type); Array & traction = tractions(*it, ghost_type); Array & contact_traction = contact_tractions(*it, ghost_type); UInt size_of_shapes = shapes.getNbComponent(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it); UInt nb_quadrature_points = fem_cohesive->getNbIntegrationPoints(*it, ghost_type); /// compute @f$t_i N_a@f$ Array * traction_cpy = new Array(nb_element * nb_quadrature_points, spatial_dimension * size_of_shapes); Array::iterator > traction_it = traction.begin(spatial_dimension, 1); Array::iterator > contact_traction_it = contact_traction.begin(spatial_dimension, 1); Array::const_iterator > shapes_filtered_begin = shapes.begin(1, size_of_shapes); Array::iterator > traction_cpy_it = traction_cpy->begin(spatial_dimension, size_of_shapes); Matrix traction_tmp(spatial_dimension, 1); for (UInt el = 0; el < nb_element; ++el) { UInt current_quad = elem_filter(el) * nb_quadrature_points; for (UInt q = 0; q < nb_quadrature_points; ++q, ++traction_it, ++contact_traction_it, ++current_quad, ++traction_cpy_it) { const Matrix & shapes_filtered = shapes_filtered_begin[current_quad]; traction_tmp.copy(*traction_it); traction_tmp += *contact_traction_it; traction_cpy_it->mul(traction_tmp, shapes_filtered); } } /** * compute @f$\int t \cdot N\, dS@f$ by @f$ \sum_q \mathbf{N}^t * \mathbf{t}_q \overline w_q J_q@f$ */ Array * int_t_N = new Array(nb_element, spatial_dimension*size_of_shapes, "int_t_N"); fem_cohesive->integrate(*traction_cpy, *int_t_N, spatial_dimension * size_of_shapes, *it, ghost_type, elem_filter); delete traction_cpy; int_t_N->extendComponentsInterlaced(2, int_t_N->getNbComponent()); Real * int_t_N_val = int_t_N->storage(); for (UInt el = 0; el < nb_element; ++el) { for (UInt n = 0; n < size_of_shapes * spatial_dimension; ++n) int_t_N_val[n] *= -1.; int_t_N_val += nb_nodes_per_element * spatial_dimension; } /// assemble model->getFEEngineBoundary().assembleArray(*int_t_N, residual, model->getDOFSynchronizer().getLocalDOFEquationNumbers(), residual.getNbComponent(), *it, ghost_type, elem_filter, 1); delete int_t_N; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::assembleStiffnessMatrix(GhostType ghost_type) { AKANTU_DEBUG_IN(); SparseMatrix & K = const_cast(model->getStiffnessMatrix()); Mesh & mesh = fem_cohesive->getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type, _ek_cohesive); for(; it != last_type; ++it) { UInt nb_quadrature_points = fem_cohesive->getNbIntegrationPoints(*it, ghost_type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it); const Array & shapes = fem_cohesive->getShapes(*it, ghost_type); Array & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.getSize(); if(!nb_element) continue; UInt size_of_shapes = shapes.getNbComponent(); Array * shapes_filtered = new Array(nb_element*nb_quadrature_points, size_of_shapes, "filtered shapes"); Real * shapes_val = shapes.storage(); Real * shapes_filtered_val = shapes_filtered->storage(); UInt * elem_filter_val = elem_filter.storage(); for (UInt el = 0; el < nb_element; ++el) { shapes_val = shapes.storage() + elem_filter_val[el] * size_of_shapes * nb_quadrature_points; memcpy(shapes_filtered_val, shapes_val, size_of_shapes * nb_quadrature_points * sizeof(Real)); shapes_filtered_val += size_of_shapes * nb_quadrature_points; } /** * compute A matrix @f$ \mathbf{A} = \left[\begin{array}{c c c c c c c c c c c c} * 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 0 & 0 & 0 \\ * 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 0 & 0 \\ * 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 & 0 \\ * 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 & 0 \\ * 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 & 0 \\ * 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 & -1 * \end{array} \right]@f$ **/ // UInt size_of_A = spatial_dimension*size_of_shapes*spatial_dimension*nb_nodes_per_element; // Real * A = new Real[size_of_A]; // memset(A, 0, size_of_A*sizeof(Real)); Matrix A(spatial_dimension*size_of_shapes, spatial_dimension*nb_nodes_per_element); for ( UInt i = 0; i < spatial_dimension*size_of_shapes; ++i) { A(i, i) = 1; A(i, i + spatial_dimension*size_of_shapes) = -1; } - /// compute traction + /// compute traction. This call is not necessary for the linear + /// cohesive law that, currently, is the only one used for the + /// extrinsic approach. if (!model->getIsExtrinsic()){ - std::cout << "HELLO!!" << std::endl; computeTraction(ghost_type); } /// get the tangent matrix @f$\frac{\partial{(t/\delta)}}{\partial{\delta}} @f$ Array * tangent_stiffness_matrix = new Array(nb_element * nb_quadrature_points, spatial_dimension * spatial_dimension, "tangent_stiffness_matrix"); // Array * normal = new Array(nb_element * nb_quadrature_points, spatial_dimension, "normal"); normal.resize(nb_quadrature_points); computeNormal(model->getCurrentPosition(), normal, *it, ghost_type); /// compute openings @f$\mathbf{\delta}@f$ //computeOpening(model->getDisplacement(), opening(*it, ghost_type), *it, ghost_type); tangent_stiffness_matrix->clear(); computeTangentTraction(*it, *tangent_stiffness_matrix, normal, ghost_type); // delete normal; UInt size_at_nt_d_n_a = spatial_dimension*nb_nodes_per_element*spatial_dimension*nb_nodes_per_element; Array * at_nt_d_n_a = new Array (nb_element*nb_quadrature_points, size_at_nt_d_n_a, "A^t*N^t*D*N*A"); Array::iterator > shapes_filt_it = shapes_filtered->begin(size_of_shapes); Array::matrix_iterator D_it = tangent_stiffness_matrix->begin(spatial_dimension, spatial_dimension); Array::matrix_iterator At_Nt_D_N_A_it = at_nt_d_n_a->begin(spatial_dimension * nb_nodes_per_element, spatial_dimension * nb_nodes_per_element); Array::matrix_iterator At_Nt_D_N_A_end = at_nt_d_n_a->end(spatial_dimension * nb_nodes_per_element, spatial_dimension * nb_nodes_per_element); Matrix N (spatial_dimension, spatial_dimension * size_of_shapes); Matrix N_A (spatial_dimension, spatial_dimension * nb_nodes_per_element); Matrix D_N_A(spatial_dimension, spatial_dimension * nb_nodes_per_element); for(; At_Nt_D_N_A_it != At_Nt_D_N_A_end; ++At_Nt_D_N_A_it, ++D_it, ++shapes_filt_it) { N.clear(); /** * store the shapes in voigt notations matrix @f$\mathbf{N} = * \begin{array}{cccccc} N_0(\xi) & 0 & N_1(\xi) &0 & N_2(\xi) & 0 \\ * 0 & * N_0(\xi)& 0 &N_1(\xi)& 0 & N_2(\xi) \end{array} @f$ **/ for (UInt i = 0; i < spatial_dimension ; ++i) for (UInt n = 0; n < size_of_shapes; ++n) N(i, i + spatial_dimension * n) = (*shapes_filt_it)(n); /** * compute stiffness matrix @f$ \mathbf{K} = \delta \mathbf{U}^T * \int_{\Gamma_c} {\mathbf{P}^t \frac{\partial{\mathbf{t}}} {\partial{\delta}} * \mathbf{P} d\Gamma \Delta \mathbf{U}} @f$ **/ N_A.mul(N, A); D_N_A.mul(*D_it, N_A); (*At_Nt_D_N_A_it).mul(D_N_A, N_A); } delete tangent_stiffness_matrix; delete shapes_filtered; Array * K_e = new Array(nb_element, size_at_nt_d_n_a, "K_e"); fem_cohesive->integrate(*at_nt_d_n_a, *K_e, size_at_nt_d_n_a, *it, ghost_type, elem_filter); delete at_nt_d_n_a; model->getFEEngine().assembleMatrix(*K_e, K, spatial_dimension, *it, ghost_type, elem_filter); delete K_e; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- * * Compute traction from displacements * * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ void MaterialCohesive::computeTraction(GhostType ghost_type) { AKANTU_DEBUG_IN(); #if defined(AKANTU_DEBUG_TOOLS) debug::element_manager.printData(debug::_dm_material_cohesive, "Cohesive Openings", opening); #endif Mesh & mesh = fem_cohesive->getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, ghost_type, _ek_cohesive); for(; it != last_type; ++it) { Array & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.getSize(); if (nb_element == 0) continue; UInt nb_quadrature_points = nb_element*fem_cohesive->getNbIntegrationPoints(*it, ghost_type); normal.resize(nb_quadrature_points); /// compute normals @f$\mathbf{n}@f$ computeNormal(model->getCurrentPosition(), normal, *it, ghost_type); /// compute openings @f$\mathbf{\delta}@f$ computeOpening(model->getDisplacement(), opening(*it, ghost_type), *it, ghost_type); /// compute traction @f$\mathbf{t}@f$ computeTraction(normal, *it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::computeNormal(const Array & position, Array & normal, ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); if (type == _cohesive_1d_2) fem_cohesive->computeNormalsOnIntegrationPoints(position, normal, type, ghost_type); else { #define COMPUTE_NORMAL(type) \ fem_cohesive->getShapeFunctions(). \ computeNormalsOnIntegrationPoints(position, \ normal, \ ghost_type, \ element_filter(type, ghost_type)); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(COMPUTE_NORMAL); #undef COMPUTE_NORMAL } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::computeOpening(const Array & displacement, Array & opening, ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); #define COMPUTE_OPENING(type) \ fem_cohesive->getShapeFunctions(). \ interpolateOnIntegrationPoints(displacement, \ opening, \ spatial_dimension, \ ghost_type, \ element_filter(type, ghost_type)); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(COMPUTE_OPENING); #undef COMPUTE_OPENING AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::computeEnergies() { AKANTU_DEBUG_IN(); Mesh & mesh = fem_cohesive->getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _not_ghost, _ek_cohesive); Real * memory_space = new Real[2*spatial_dimension]; Vector b(memory_space, spatial_dimension); Vector h(memory_space + spatial_dimension, spatial_dimension); for(; it != last_type; ++it) { Array::iterator erev = reversible_energy(*it, _not_ghost).begin(); Array::iterator etot = total_energy(*it, _not_ghost).begin(); Array::vector_iterator traction_it = tractions(*it, _not_ghost).begin(spatial_dimension); Array::vector_iterator traction_old_it = tractions_old(*it, _not_ghost).begin(spatial_dimension); Array::vector_iterator opening_it = opening(*it, _not_ghost).begin(spatial_dimension); Array::vector_iterator opening_old_it = opening_old(*it, _not_ghost).begin(spatial_dimension); Array::vector_iterator traction_end = tractions(*it, _not_ghost).end(spatial_dimension); /// loop on each quadrature point for (; traction_it != traction_end; ++traction_it, ++traction_old_it, ++opening_it, ++opening_old_it, ++erev, ++etot) { /// trapezoidal integration b = *opening_it; b -= *opening_old_it; h = *traction_old_it; h += *traction_it; *etot += .5 * b.dot(h); *erev = .5 * traction_it->dot(*opening_it); } } delete [] memory_space; /// update old values it = mesh.firstType(spatial_dimension, _not_ghost, _ek_cohesive); GhostType ghost_type = _not_ghost; for(; it != last_type; ++it) { tractions_old(*it, ghost_type).copy(tractions(*it, ghost_type)); opening_old(*it, ghost_type).copy(opening(*it, ghost_type)); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getReversibleEnergy() { AKANTU_DEBUG_IN(); Real erev = 0.; /// integrate reversible energy for each type of elements Mesh & mesh = fem_cohesive->getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _not_ghost, _ek_cohesive); for(; it != last_type; ++it) { erev += fem_cohesive->integrate(reversible_energy(*it, _not_ghost), *it, _not_ghost, element_filter(*it, _not_ghost)); } AKANTU_DEBUG_OUT(); return erev; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getDissipatedEnergy() { AKANTU_DEBUG_IN(); Real edis = 0.; /// integrate dissipated energy for each type of elements Mesh & mesh = fem_cohesive->getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _not_ghost, _ek_cohesive); for(; it != last_type; ++it) { Array dissipated_energy(total_energy(*it, _not_ghost)); dissipated_energy -= reversible_energy(*it, _not_ghost); edis += fem_cohesive->integrate(dissipated_energy, *it, _not_ghost, element_filter(*it, _not_ghost)); } AKANTU_DEBUG_OUT(); return edis; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getContactEnergy() { AKANTU_DEBUG_IN(); Real econ = 0.; /// integrate contact energy for each type of elements Mesh & mesh = fem_cohesive->getMesh(); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_cohesive); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _not_ghost, _ek_cohesive); for(; it != last_type; ++it) { Array & el_filter = element_filter(*it, _not_ghost); UInt nb_quad_per_el = fem_cohesive->getNbIntegrationPoints(*it, _not_ghost); UInt nb_quad_points = el_filter.getSize() * nb_quad_per_el; Array contact_energy(nb_quad_points); Array::vector_iterator contact_traction_it = contact_tractions(*it, _not_ghost).begin(spatial_dimension); Array::vector_iterator contact_opening_it = contact_opening(*it, _not_ghost).begin(spatial_dimension); /// loop on each quadrature point for (UInt el = 0; el < nb_quad_points; ++contact_traction_it, ++contact_opening_it, ++el) { contact_energy(el) = .5 * contact_traction_it->dot(*contact_opening_it); } econ += fem_cohesive->integrate(contact_energy, *it, _not_ghost, el_filter); } AKANTU_DEBUG_OUT(); return econ; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getEnergy(std::string type) { AKANTU_DEBUG_IN(); if (type == "reversible") return getReversibleEnergy(); else if (type == "dissipated") return getDissipatedEnergy(); else if (type == "cohesive contact") return getContactEnergy(); AKANTU_DEBUG_OUT(); return 0.; } /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive.hh index f39d42b9c..67229209c 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive.hh @@ -1,331 +1,332 @@ /** * @file solid_mechanics_model_cohesive.hh * * @author Marco Vocialta * * @date creation: Tue May 08 2012 * @date last modification: Tue Sep 02 2014 * * @brief Solid mechanics model for cohesive elements * * @section LICENSE * * Copyright (©) 2014 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_HH__ #define __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_HH__ #include "solid_mechanics_model.hh" #include "solid_mechanics_model_event_handler.hh" #include "cohesive_element_inserter.hh" #include "material_selector.hh" #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) # include "facet_synchronizer.hh" # include "facet_stress_synchronizer.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ struct SolidMechanicsModelCohesiveOptions : public SolidMechanicsModelOptions { SolidMechanicsModelCohesiveOptions(AnalysisMethod analysis_method = _explicit_lumped_mass, bool extrinsic = false, bool no_init_materials = false) : SolidMechanicsModelOptions(analysis_method, no_init_materials), extrinsic(extrinsic) {} bool extrinsic; }; extern const SolidMechanicsModelCohesiveOptions default_solid_mechanics_model_cohesive_options; /* -------------------------------------------------------------------------- */ /* Solid Mechanics Model for Cohesive elements */ /* -------------------------------------------------------------------------- */ class SolidMechanicsModelCohesive : public SolidMechanicsModel, public SolidMechanicsModelEventHandler{ /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: class NewCohesiveNodesEvent : public NewNodesEvent { public: AKANTU_GET_MACRO_NOT_CONST(OldNodesList, old_nodes, Array &); AKANTU_GET_MACRO(OldNodesList, old_nodes, const Array &); protected: Array old_nodes; }; typedef FEEngineTemplate MyFEEngineCohesiveType; SolidMechanicsModelCohesive(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "solid_mechanics_model_cohesive", const MemoryID & memory_id = 0); virtual ~SolidMechanicsModelCohesive(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// set the value of the time step void setTimeStep(Real time_step); /// assemble the residual for the explicit scheme virtual void updateResidual(bool need_initialize = true); /// function to print the contain of the class virtual void printself(std::ostream & stream, int indent = 0) const; /// function to perform a stress check on each facet and insert /// cohesive elements if needed (returns the number of new cohesive /// elements) UInt checkCohesiveStress(); /// interpolate stress on facets void interpolateStress(); /// initialize the cohesive model void initFull(const ModelOptions & options = default_solid_mechanics_model_cohesive_options); /// initialize the model void initModel(); /// initialize cohesive material void initMaterials(); /// init facet filters for cohesive materials void initFacetFilter(); /// limit the cohesive element insertion to a given area void limitInsertion(BC::Axis axis, Real first_limit, Real second_limit); /// update automatic insertion after a change in the element inserter void updateAutomaticInsertion(); /// insert intrinsic cohesive elements void insertIntrinsicElements(); template bool solveStepCohesive(Real tolerance, Real & error, UInt max_iteration = 100, bool load_reduction = false, + Real tol_increase_factor = 1.0, bool do_not_factorize = false); /// initialize stress interpolation void initStressInterpolation(); private: /// initialize cohesive material with intrinsic insertion (by default) void initIntrinsicCohesiveMaterials(UInt cohesive_index); /// initialize cohesive material with intrinsic insertion (if physical surfaces are precised) void initIntrinsicCohesiveMaterials(std::string cohesive_surfaces); /// insert cohesive elements along a given physical surface of the mesh void insertElementsFromMeshData(std::string physical_name); /// initialize completely the model for extrinsic elements void initAutomaticInsertion(); /// compute facets' normals void computeNormals(); /// resize facet stress void resizeFacetStress(); /// init facets_check array void initFacetsCheck(); /* ------------------------------------------------------------------------ */ /* Mesh Event Handler inherited members */ /* ------------------------------------------------------------------------ */ protected: virtual void onNodesAdded (const Array & nodes_list, const NewNodesEvent & event); virtual void onElementsAdded (const Array & nodes_list, const NewElementsEvent & event); /* ------------------------------------------------------------------------ */ /* SolidMechanicsModelEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: virtual void onEndSolveStep(const AnalysisMethod & method); /* ------------------------------------------------------------------------ */ /* Dumpable interface */ /* ------------------------------------------------------------------------ */ public: virtual void onDump(); virtual void addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, const ElementKind & element_kind, bool padding_flag); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get facet mesh AKANTU_GET_MACRO(MeshFacets, mesh.getMeshFacets(), const Mesh &); /// get stress on facets vector AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(StressOnFacets, facet_stress, Real); /// get facet material AKANTU_GET_MACRO_BY_ELEMENT_TYPE(FacetMaterial, facet_material, UInt); /// get facet material AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(FacetMaterial, facet_material, UInt); /// get facet material AKANTU_GET_MACRO(FacetMaterial, facet_material, const ElementTypeMapArray &); /// @todo THIS HAS TO BE CHANGED AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Tangents, tangents, Real); /// get element inserter AKANTU_GET_MACRO_NOT_CONST(ElementInserter, *inserter, CohesiveElementInserter &); /// get is_extrinsic boolean AKANTU_GET_MACRO(IsExtrinsic, is_extrinsic, bool); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// @todo store tangents when normals are computed: ElementTypeMapArray tangents; /// stress on facets on the two sides by quadrature point ElementTypeMapArray facet_stress; /// material to use if a cohesive element is created on a facet ElementTypeMapArray facet_material; bool is_extrinsic; /// cohesive element inserter CohesiveElementInserter * inserter; #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) #include "solid_mechanics_model_cohesive_parallel.hh" #endif }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /** * class that assigns the first cohesive material by default to the * cohesive elements */ class DefaultMaterialCohesiveSelector : public DefaultMaterialSelector { public: DefaultMaterialCohesiveSelector(const SolidMechanicsModelCohesive & model) : DefaultMaterialSelector(model.getMaterialByElement()), facet_material(model.getFacetMaterial()), mesh(model.getMesh()) { } inline virtual UInt operator()(const Element & element) { if(Mesh::getKind(element.type) == _ek_cohesive) { try { const Array & cohesive_el_to_facet = mesh.getMeshFacets().getSubelementToElement(element.type, element.ghost_type); bool third_dimension = (mesh.getSpatialDimension() == 3); const Element & facet = cohesive_el_to_facet(element.element, third_dimension); if(facet_material.exists(facet.type, facet.ghost_type)) { return facet_material(facet.type, facet.ghost_type)(facet.element); } else { return MaterialSelector::operator()(element); } } catch (...) { return MaterialSelector::operator()(element); } } else if (Mesh::getSpatialDimension(element.type) == mesh.getSpatialDimension() - 1) { return facet_material(element.type, element.ghost_type)(element.element); } else { return DefaultMaterialSelector::operator()(element); } } private: const ElementTypeMapArray & facet_material; const Mesh & mesh; }; /* -------------------------------------------------------------------------- */ /// To be used with intrinsic elements inserted along mesh physical surfaces class MeshDataMaterialCohesiveSelector : public MeshDataMaterialSelector { public: MeshDataMaterialCohesiveSelector(const SolidMechanicsModelCohesive & model): MeshDataMaterialSelector("physical_names",model), mesh_facets(model.getMeshFacets()), material_index(mesh_facets.getData("physical_names")) { third_dimension = (model.getSpatialDimension()==3);} inline virtual UInt operator() (const Element & element) { if(element.kind == _ek_cohesive) { const Array & cohesive_el_to_facet = mesh_facets.getSubelementToElement(element.type, element.ghost_type); const Element & facet = cohesive_el_to_facet(element.element,third_dimension); UInt material_id = material_index(facet.type,facet.ghost_type)(facet.element); return material_id; } else return MeshDataMaterialSelector::operator()(element); } protected: const Mesh & mesh_facets; const ElementTypeMapArray & material_index; bool third_dimension; }; /* -------------------------------------------------------------------------- */ /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const SolidMechanicsModelCohesive & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #if defined (AKANTU_INCLUDE_INLINE_IMPL) # include "solid_mechanics_model_cohesive_inline_impl.cc" #endif #endif /* __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive_inline_impl.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive_inline_impl.cc index f9c17ab0a..c3393e80a 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive_inline_impl.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive_inline_impl.cc @@ -1,282 +1,304 @@ /** * @file solid_mechanics_model_cohesive_inline_impl.cc * * @author Mauro Corrado * * @date Thu Feb 26 14:23:45 2015 * * @brief Implementation of inline functions for the Cohesive element model * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include #include "material_cohesive.hh" #ifndef __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_INLINE_IMPL_CC__ #define __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_INLINE_IMPL_CC__ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template bool SolidMechanicsModelCohesive::solveStepCohesive(Real tolerance, Real & error, UInt max_iteration, bool load_reduction, + Real tol_increase_factor, bool do_not_factorize) { EventManager::sendEvent(SolidMechanicsModelEvent::BeforeSolveStepEvent(method)); this->implicitPred(); bool insertion_new_element = true; bool converged = false; Array * displacement_tmp = NULL; Array * velocity_tmp = NULL; Array * acceleration_tmp = NULL; StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int prank = comm.whoAmI(); /// Loop for the insertion of new cohesive elements while (insertion_new_element) { - //insertion_new_element = false; - if (is_extrinsic) { - // If in extrinsic saves the current displacements, velocities and accelerations + /// If in extrinsic the solution of the previous incremental + /// step is saved in temporary arrays created for displacements, + /// velocities and accelerations. Such arrays are used to find + /// the solution with the Newton-Raphson scheme (this is done by + /// pointing the pointer "displacement" to displacement_tmp). In + /// this way, inside the array "displacement" is kept the + /// solution of the previous incremental step, and in + /// "displacement_tmp" is saved the current solution. Array * tmp_swap; if(!displacement_tmp) { displacement_tmp = new Array(*(this->displacement)); } else { displacement_tmp->resize(this->displacement->getSize()); displacement_tmp->copy(*(this->displacement)); } tmp_swap = displacement_tmp; displacement_tmp = this->displacement; this->displacement = tmp_swap; if(!velocity_tmp) { velocity_tmp = new Array(*(this->velocity)); } else { velocity_tmp->resize(this->velocity->getSize()); velocity_tmp->copy(*(this->velocity)); } tmp_swap = velocity_tmp; velocity_tmp = this->velocity; this->velocity = tmp_swap; if(!acceleration_tmp) { acceleration_tmp = new Array(*(this->acceleration)); } else { acceleration_tmp->resize(this->acceleration->getSize()); acceleration_tmp->copy(*(this->acceleration)); } tmp_swap = acceleration_tmp; acceleration_tmp = this->acceleration; this->acceleration = tmp_swap; } this->updateResidual(); AKANTU_DEBUG_ASSERT(stiffness_matrix != NULL, "You should first initialize the implicit solver and assemble the stiffness matrix"); bool need_factorize = !do_not_factorize; if (method ==_implicit_dynamic) { AKANTU_DEBUG_ASSERT(mass_matrix != NULL, "You should first initialize the implicit solver and assemble the mass matrix"); } switch (cmethod) { case _scm_newton_raphson_tangent: case _scm_newton_raphson_tangent_not_computed: break; case _scm_newton_raphson_tangent_modified: this->assembleStiffnessMatrix(); break; default: AKANTU_DEBUG_ERROR("The resolution method " << cmethod << " has not been implemented!"); } UInt iter = 0; converged = false; error = 0.; if(criteria == _scc_residual) { converged = this->testConvergence (tolerance, error); if(converged) return converged; } /// Loop to solve the nonlinear system do { if (cmethod == _scm_newton_raphson_tangent) this->assembleStiffnessMatrix(); solve (*increment, 1., need_factorize); this->implicitCorr(); this->updateResidual(); - // dump(); - // dump("cohesive elements"); - converged = this->testConvergence (tolerance, error); iter++; AKANTU_DEBUG_INFO("[" << criteria << "] Convergence iteration " << std::setw(std::log10(max_iteration)) << iter << ": error " << error << (converged ? " < " : " > ") << tolerance); switch (cmethod) { case _scm_newton_raphson_tangent: need_factorize = true; break; case _scm_newton_raphson_tangent_not_computed: case _scm_newton_raphson_tangent_modified: need_factorize = false; break; default: AKANTU_DEBUG_ERROR("The resolution method " << cmethod << " has not been implemented!"); } } while (!converged && iter < max_iteration); /// This is to save the obtained result and proceed with the /// simulation even if the error is higher than the pre-fixed - /// tolerance. - if (load_reduction && (error < tolerance * 1.0e8)) converged = true; + /// tolerance. This is done only after loading reduction + /// (load_reduction = true). + if (load_reduction && (error < tolerance * tol_increase_factor)) converged = true; if (converged) { // EventManager::sendEvent(SolidMechanicsModelEvent::AfterSolveStepEvent(method)); // !!! add sendEvent to call computeCauchyStress !!!! if (prank==0){ std::cout << "Error after convergence: " << error << std::endl; std::cout << "no. of iterations: " << iter << std::endl; } } else if(iter == max_iteration) { if (prank==0){ AKANTU_DEBUG_WARNING("[" << criteria << "] Convergence not reached after " << std::setw(std::log10(max_iteration)) << iter << " iteration" << (iter == 1 ? "" : "s") << "!" << std::endl); std::cout << "Error after NON convergence: " << error << std::endl; } } if (is_extrinsic) { + /// If is extrinsic the pointer "displacement" is moved back to + /// the array displacement. In this way, the array displacement + /// is correctly resized during the checkCohesiveStress function + /// (in case new cohesive elements are added). This is possible + /// because the procedure called by checkCohesiveStress does not + /// use the displacement field (the correct one is now stored in + /// displacement_tmp), but directly the stress field that is + /// already computed. Array * tmp_swap; tmp_swap = displacement_tmp; displacement_tmp = this->displacement; this->displacement = tmp_swap; tmp_swap = velocity_tmp; velocity_tmp = this->velocity; this->velocity = tmp_swap; tmp_swap = acceleration_tmp; acceleration_tmp = this->acceleration; this->acceleration = tmp_swap; - - // if (converged || (load_reduction && error < tolerance * 1.0e9)){ + /// If convergence is reached, call checkCohesiveStress in order + /// to check if cohesive elements have to be introduced if (converged){ UInt new_cohesive_elements = checkCohesiveStress(); if(new_cohesive_elements == 0){ insertion_new_element = false; } else { insertion_new_element = true; if (prank==0) std::cout << "No. cohesive elements inserted = " << new_cohesive_elements << std::endl; } } } + if (!converged && load_reduction) insertion_new_element = false; - // if (!converged && !load_reduction){ - if (!converged) { + /// If convergence is not reached, there is the possibility to + /// return back to the main file and reduce the load. Before doing + /// this, a pre-fixed value as to be defined for the parameter + /// delta_max of the cohesive elements introduced in the current + /// incremental step. This is done by calling the function + /// checkDeltaMax. + if (!converged) { insertion_new_element = false; for (UInt m = 0; m < materials.size(); ++m) { try { MaterialCohesive & mat = dynamic_cast(*materials[m]); mat.checkDeltaMax(_not_ghost); } catch(std::bad_cast&) { } } } - } //end while insertion_new_element + } //end loop for the insertion of new cohesive elements - //if ((is_extrinsic && converged) || (is_extrinsic && load_reduction)) { + /// When the solution to the current incremental step is computed + /// (no more cohesive elements have to be introduced), call the + /// function to compute the energies. if ((is_extrinsic && converged)) { for(UInt m = 0; m < materials.size(); ++m) { try { MaterialCohesive & mat = dynamic_cast(*materials[m]); mat.computeEnergies(); } catch (std::bad_cast & bce) { } } EventManager::sendEvent(SolidMechanicsModelEvent::AfterSolveStepEvent(method)); - + /// The function resetVariables is necessary to correctly set a + /// variable that permit to decrease locally the penalty parameter + /// for compression. for (UInt m = 0; m < materials.size(); ++m) { try { MaterialCohesive & mat = dynamic_cast(*materials[m]); mat.resetVariables(_not_ghost); } catch(std::bad_cast&) { } } - + /// The correct solution is saved this->displacement->copy(*displacement_tmp); this->velocity ->copy(*velocity_tmp); this->acceleration->copy(*acceleration_tmp); delete displacement_tmp; delete velocity_tmp; delete acceleration_tmp; } return insertion_new_element; } __END_AKANTU__ #if defined (AKANTU_PARALLEL_COHESIVE_ELEMENT) # include "solid_mechanics_model_cohesive_parallel_inline_impl.cc" #endif #endif /* __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_INLINE_IMPL_CC__ */