diff --git a/extra_packages/extra-materials b/extra_packages/extra-materials index 27835edcf..b6e70a3df 160000 --- a/extra_packages/extra-materials +++ b/extra_packages/extra-materials @@ -1 +1 @@ -Subproject commit 27835edcf205dedb552ddb9d82d3bc9e39b0156a +Subproject commit b6e70a3dfb54b4021a10b37a9e4e6c26a64f9854 diff --git a/extra_packages/parallel-cohesive-element b/extra_packages/parallel-cohesive-element index 93c04c339..c46ced178 160000 --- a/extra_packages/parallel-cohesive-element +++ b/extra_packages/parallel-cohesive-element @@ -1 +1 @@ -Subproject commit 93c04c33905f63fc4addef7160fa400409b154fb +Subproject commit c46ced1786aec62d4e082dd3624eb539a96413f4 diff --git a/python/swig/aka_common.i b/python/swig/aka_common.i index 6079d8ef9..fd9c3b4ec 100644 --- a/python/swig/aka_common.i +++ b/python/swig/aka_common.i @@ -1,25 +1,30 @@ %{ #include "aka_common.hh" %} namespace akantu { %ignore getStaticParser; %ignore getUserParser; %ignore initialize(int & argc, char ** & argv); %ignore initialize(const std::string & input_file, int & argc, char ** & argv); } %inline %{ namespace akantu { void initialize(const std::string & input_file) { int argc = 0; char ** argv = NULL; initialize(input_file, argc, argv); } + void initialize() { + int argc = 0; + char ** argv = NULL; + initialize(argc, argv); + } } %} %include "aka_common.hh" diff --git a/python/swig/akantu.i b/python/swig/akantu.i index 31ab927fe..d9232e07c 100644 --- a/python/swig/akantu.i +++ b/python/swig/akantu.i @@ -1,26 +1,29 @@ %module akantu %include "stl.i" #define __attribute__(x) %ignore akantu::operator <<; %include "aka_common.i" %include "aka_array.i" %define print_self(MY_CLASS) %extend akantu::MY_CLASS { std::string __str__() { std::stringstream sstr; sstr << *($self); return sstr.str(); } } %enddef %include "mesh.i" %include "mesh_utils.i" %include "model.i" %include "solid_mechanics_model.i" - +#if defined(AKANTU_STRUCTURAL_MECHANICS) +%include "load_functions.i" +%include "structural_mechanics_model.i" +#endif diff --git a/python/swig/load_functions.i b/python/swig/load_functions.i new file mode 100644 index 000000000..046c3bfe0 --- /dev/null +++ b/python/swig/load_functions.i @@ -0,0 +1,14 @@ +%inline %{ + namespace akantu { + + static void lin_load(double * position, double * load, + __attribute__ ((unused)) Real * normal, + __attribute__ ((unused)) UInt surface_id) { + + memset(load,0,sizeof(Real)*3); + if (position[0]<=10){ + load[1]= -6000; + } + } + } + %} diff --git a/python/swig/mesh.i b/python/swig/mesh.i index 283f68965..d5740a174 100644 --- a/python/swig/mesh.i +++ b/python/swig/mesh.i @@ -1,95 +1,113 @@ %{ #include "mesh.hh" #include "node_group.hh" #include "solid_mechanics_model.hh" using akantu::Vector; using akantu::ElementTypeMapArray; using akantu::MatrixProxy; using akantu::Matrix; using akantu::UInt; using akantu::Real; using akantu::Array; using akantu::SolidMechanicsModel; %} namespace akantu { %ignore NewNodesEvent; %ignore RemovedNodesEvent; %ignore NewElementsEvent; %ignore RemovedElementsEvent; %ignore MeshEventHandler; %ignore MeshEvent< UInt >; %ignore MeshEvent< Element >; %ignore Mesh::extractNodalCoordinatesFromPBCElement; %ignore Mesh::getGroupDumer; } print_self(Mesh) + +%extend akantu::Mesh { + + void resizeMesh(UInt nb_nodes, UInt nb_element, const ElementType & type) { + + Array<Real> & nodes = const_cast<Array<Real> &>($self->getNodes()); + nodes.resize(nb_nodes); + + $self->addConnectivityType(type); + Array<UInt> & connectivity = const_cast<Array<UInt> &>($self->getConnectivity(type)); + connectivity.resize(nb_element); + + + + } + +} + %extend akantu::GroupManager { void createGroupsFromStringMeshData(const std::string & dataset_name) { $self->createGroupsFromMeshData<std::string>(dataset_name); } void createGroupsFromUIntMeshData(const std::string & dataset_name) { $self->createGroupsFromMeshData<akantu::UInt>(dataset_name); } } %extend akantu::NodeGroup { akantu::Array<akantu::Real> & getGroupedNodes(akantu::Array<akantu::Real, true> & surface_array, Mesh & mesh) { akantu::Array<akantu::UInt> group_node = $self->getNodes(); akantu::Array<akantu::Real> & full_array = mesh.getNodes(); surface_array.resize(group_node.getSize()); for (UInt i = 0; i < group_node.getSize(); ++i) { for (UInt cmp = 0; cmp < full_array.getNbComponent(); ++cmp) { surface_array(i,cmp) = full_array(group_node(i),cmp); } } akantu::Array<akantu::Real> & res(surface_array); return res; } akantu::Array<akantu::Real> & getGroupedArray(akantu::Array<akantu::Real, true> & surface_array, akantu::SolidMechanicsModel & model, int type) { akantu::Array<akantu::Real> * full_array; switch (type) { case 0 : full_array = new akantu::Array<akantu::Real>(model.getDisplacement()); break; case 1 : full_array = new akantu::Array<akantu::Real>(model.getVelocity()); break; case 2 : full_array = new akantu::Array<akantu::Real>(model.getForce()); break; } akantu::Array<akantu::UInt> group_node = $self->getNodes(); surface_array.resize(group_node.getSize()); for (UInt i = 0; i < group_node.getSize(); ++i) { for (UInt cmp = 0; cmp < full_array->getNbComponent(); ++cmp) { surface_array(i,cmp) = (*full_array)(group_node(i),cmp); } } akantu::Array<akantu::Real> & res(surface_array); return res; } } %include "group_manager.hh" %include "element_group.hh" %include "node_group.hh" %include "mesh.hh" diff --git a/python/swig/structural_mechanics_model.i b/python/swig/structural_mechanics_model.i new file mode 100644 index 000000000..c6f45e515 --- /dev/null +++ b/python/swig/structural_mechanics_model.i @@ -0,0 +1,40 @@ +%{ + #include "structural_mechanics_model.hh" + #include "sparse_matrix.hh" +%} + +namespace akantu { + %ignore StructuralMechanicsModel::initArrays; + %ignore StructuralMechanicsModel::initModel; + + %ignore StructuralMechanicsModel::initSolver; + %ignore StructuralMechanicsModel::initImplicit; + + static void lin_load(double * position, double * load, + __attribute__ ((unused)) Real * normal, + __attribute__ ((unused)) UInt surface_id) { + + memset(load,0,sizeof(Real)*3); + if (position[0]<=10){ + load[1]= -6000; + } + } +} + +%include "dumpable.hh" +%include "structural_mechanics_model.hh" + +%extend akantu::StructuralMechanicsModel { + + bool solveStep(Real tolerance, UInt max_iteration) { + + return $self->solveStep<akantu::SolveConvergenceMethod::_scm_newton_raphson_tangent, akantu::SolveConvergenceCriteria::_scc_residual>(tolerance, max_iteration); + + } + + void computeForcesFromFunctionBeam2d(BoundaryFunctionType function_type) { + + $self->computeForcesFromFunction<akantu::ElementType::_bernoulli_beam_2>(akantu::lin_load, function_type); + + } + } 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 1cbf916c7..352ffd4b6 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,655 +1,656 @@ /** * @file material_cohesive_linear.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue May 08 2012 * @date last modification: Thu Aug 07 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include <numeric> /* -------------------------------------------------------------------------- */ #include "material_cohesive_linear.hh" #include "solid_mechanics_model_cohesive.hh" #include "sparse_matrix.hh" #include "dof_synchronizer.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> MaterialCohesiveLinear<spatial_dimension>::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) { AKANTU_DEBUG_IN(); this->registerParam("beta" , beta , 0. , _pat_parsable | _pat_readable, "Beta parameter" ); this->registerParam("G_c" , G_c , 0. , _pat_parsable | _pat_readable, "Mode I fracture energy" ); this->registerParam("penalty", penalty, 0. , _pat_parsable | _pat_readable, "Penalty coefficient" ); this->registerParam("volume_s", volume_s, 0. , _pat_parsable | _pat_readable, "Reference volume for sigma_c scaling"); this->registerParam("m_s", m_s, 1. , _pat_parsable | _pat_readable, "Weibull exponent for sigma_c scaling"); this->registerParam("kappa" , kappa , 1. , _pat_parsable | _pat_readable, "Kappa parameter"); // if (!model->isExplicit()) use_previous_delta_max = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::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); 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(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::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<Element> > & facet_to_element = mesh_facets.getElementToSubelement(type_facet); UInt nb_facet = facet_to_element.getSize(); UInt nb_quad_per_facet = fe_engine_facet.getNbQuadraturePoints(type_facet); // iterator to modify sigma_c for all the quadrature points of a facet Array<Real>::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> & element_list = facet_to_element(f); // compute bounding volume Real volume = 0; std::vector<Element>::const_iterator elem = element_list.begin(); std::vector<Element>::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.getNbQuadraturePoints(elem->type); Vector<Real> 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<UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::checkInsertion() { 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<bool> & facets_check = inserter.getCheckFacets(type_facet); Array<bool> & f_insertion = inserter.getInsertionFacets(type_facet); Array<UInt> & f_filter = facet_filter(type_facet); Array<Real> & sig_c_eff = sigma_c_eff(type_cohesive); Array<Real> & del_c = delta_c_eff(type_cohesive); Array<Real> & ins_stress = insertion_stress(type_cohesive); Array<Real> & trac_old = tractions_old(type_cohesive); const Array<Real> & f_stress = model->getStressOnFacets(type_facet); const Array<Real> & sigma_lim = sigma_c(type_facet); Real max_ratio = 0.; UInt index_f = 0; UInt index_filter = 0; UInt nn = 0; //Real sigma_c_tmp = 0.0; UInt nb_quad_facet = model->getFEEngine("FacetsFEEngine").getNbQuadraturePoints(type_facet); UInt nb_facet = f_filter.getSize(); if (nb_facet == 0) continue; Array<Real>::const_iterator<Real> sigma_lim_it = sigma_lim.begin(); Matrix<Real> stress_tmp(spatial_dimension, spatial_dimension); Matrix<Real> normal_traction(spatial_dimension, nb_quad_facet); Vector<Real> stress_check(nb_quad_facet); UInt sp2 = spatial_dimension * spatial_dimension; const Array<Real> & tangents = model->getTangents(type_facet); const Array<Real> & normals = model->getFEEngine("FacetsFEEngine").getNormalsOnQuadPoints(type_facet); Array<Real>::const_vector_iterator normal_begin = normals.begin(spatial_dimension); Array<Real>::const_vector_iterator tangent_begin = tangents.begin(tangents.getNbComponent()); Array<Real>::const_matrix_iterator facet_stress_begin = f_stress.begin(spatial_dimension, spatial_dimension * 2); std::vector<Real> new_sigmas; std::vector< Vector<Real> > new_normal_traction; std::vector<Real> 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<Real> & normal = normal_begin[current_quad]; const Vector<Real> & tangent = tangent_begin[current_quad]; const Matrix<Real> & facet_stress_it = facet_stress_begin[current_quad]; // compute average stress on the current quadrature point Matrix<Real> stress_1(facet_stress_it.storage(), spatial_dimension, spatial_dimension); Matrix<Real> stress_2(facet_stress_it.storage() + sp2, spatial_dimension, spatial_dimension); stress_tmp.copy(stress_1); stress_tmp += stress_2; stress_tmp /= 2.; Vector<Real> 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 if (stress_check.mean() > (*sigma_lim_it - tolerance)) { if (model->isExplicit()){ f_insertion(facet) = true; // 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<Real> 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 = stress_check.mean()/(*sigma_lim_it); if (ratio > max_ratio){ ++nn; max_ratio = ratio; index_f = f; index_filter = f_filter(f); //sigma_c_tmp = *sigma_lim_it; //sigma_ins_tmp = ins_s_; } } } } - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); - Array<Real> abs_max(comm.getNbProc()); - abs_max(comm.whoAmI()) = max_ratio; - comm.allGather(abs_max.storage(), 1); - - Array<Real>::scalar_iterator it = std::max_element(abs_max.begin(), abs_max.end()); - UInt pos = it - abs_max.begin(); - - if (pos != comm.whoAmI()) { - AKANTU_DEBUG_OUT(); - return; - } - /// insertion of only 1 cohesive element in case of implicit approach. The one subjected to the highest stress. - if (!model->isExplicit() && nn){ - f_insertion(index_filter) = true; + if (!model->isExplicit()){ + StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + Array<Real> abs_max(comm.getNbProc()); + abs_max(comm.whoAmI()) = max_ratio; + comm.allGather(abs_max.storage(), 1); + + Array<Real>::scalar_iterator it = std::max_element(abs_max.begin(), abs_max.end()); + UInt pos = it - abs_max.begin(); + + if (pos != comm.whoAmI()) { + AKANTU_DEBUG_OUT(); + return; + } - // Array<Real>::iterator<Matrix<Real> > normal_traction_it = - // normal_traction.begin_reinterpret(nb_quad_facet, spatial_dimension, nb_facet); - Array<Real>::const_iterator<Real> sigma_lim_it = sigma_lim.begin(); + if (nn) { + f_insertion(index_filter) = true; - for (UInt q = 0; q < nb_quad_facet; ++q) { + // Array<Real>::iterator<Matrix<Real> > normal_traction_it = + // normal_traction.begin_reinterpret(nb_quad_facet, spatial_dimension, nb_facet); + Array<Real>::const_iterator<Real> sigma_lim_it = sigma_lim.begin(); - // Vector<Real> ins_s(normal_traction_it[index_f].storage() + q * spatial_dimension, - // spatial_dimension); + for (UInt q = 0; q < nb_quad_facet; ++q) { - Real new_sigma = (sigma_lim_it[index_f]); + // Vector<Real> ins_s(normal_traction_it[index_f].storage() + q * spatial_dimension, + // spatial_dimension); - new_sigmas.push_back(new_sigma); - new_normal_traction.push_back(0.0); + Real new_sigma = (sigma_lim_it[index_f]); - //// sig_c_eff.push_back(new_sigma); - // ins_stress.push_back(ins_s); - // trac_old.push_back(ins_s); - //// ins_stress.push_back(0.0); - //// trac_old.push_back(0.0); + new_sigmas.push_back(new_sigma); + new_normal_traction.push_back(0.0); - Real new_delta; + //// sig_c_eff.push_back(new_sigma); + // ins_stress.push_back(ins_s); + // trac_old.push_back(ins_s); + //// ins_stress.push_back(0.0); + //// trac_old.push_back(0.0); - //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); + Real new_delta; - new_delta_c.push_back(new_delta); - ////del_c.push_back(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); + ////del_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); 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]; 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); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> inline Real MaterialCohesiveLinear<spatial_dimension>::computeEffectiveNorm(const Matrix<Real> & stress, const Vector<Real> & normal, const Vector<Real> & tangent, Vector<Real> & normal_traction) { normal_traction.mul<false>(stress, normal); Real normal_contrib = normal_traction.dot(normal); /// in 3D tangential components must be summed Real tangent_contrib = 0; if (spatial_dimension == 2) { Real tangent_contrib_tmp = normal_traction.dot(tangent); tangent_contrib += tangent_contrib_tmp * tangent_contrib_tmp; } else if (spatial_dimension == 3) { for (UInt s = 0; s < spatial_dimension - 1; ++s) { const Vector<Real> tangent_v(tangent.storage() + s * spatial_dimension, spatial_dimension); Real tangent_contrib_tmp = normal_traction.dot(tangent_v); tangent_contrib += tangent_contrib_tmp * tangent_contrib_tmp; } } tangent_contrib = std::sqrt(tangent_contrib); normal_contrib = std::max(0., normal_contrib); return std::sqrt(normal_contrib * normal_contrib + tangent_contrib * tangent_contrib * beta2_inv); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::computeTraction(const Array<Real> & normal, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators Array<Real>::iterator< Vector<Real> > traction_it = tractions(el_type, ghost_type).begin(spatial_dimension); Array<Real>::iterator< Vector<Real> > opening_it = opening(el_type, ghost_type).begin(spatial_dimension); Array<Real>::iterator< Vector<Real> > contact_traction_it = contact_tractions(el_type, ghost_type).begin(spatial_dimension); Array<Real>::iterator< Vector<Real> > contact_opening_it = contact_opening(el_type, ghost_type).begin(spatial_dimension); Array<Real>::const_iterator< Vector<Real> > normal_it = normal.begin(spatial_dimension); Array<Real>::iterator< Vector<Real> >traction_end = tractions(el_type, ghost_type).end(spatial_dimension); Array<Real>::iterator<Real>sigma_c_it = sigma_c_eff(el_type, ghost_type).begin(); Array<Real>::iterator<Real>delta_max_it = delta_max(el_type, ghost_type).begin(); Array<Real>::iterator<Real>delta_max_prev_it = delta_max.previous(el_type, ghost_type).begin(); Array<Real>::iterator<Real>delta_c_it = delta_c_eff(el_type, ghost_type).begin(); Array<Real>::iterator<Real>damage_it = damage(el_type, ghost_type).begin(); Array<Real>::iterator<Vector<Real> > insertion_stress_it = insertion_stress(el_type, ghost_type).begin(spatial_dimension); Real * memory_space = new Real[2*spatial_dimension]; Vector<Real> normal_opening(memory_space, spatial_dimension); Vector<Real> tangential_opening(memory_space + spatial_dimension, spatial_dimension); /// loop on each quadrature point for (; traction_it != traction_end; ++traction_it, ++opening_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) { if (!model->isExplicit()) *delta_max_it = *delta_max_prev_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; 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; bool penetration = normal_opening_norm < -Math::getTolerance(); if (penetration) { /// use penalty coefficient in case of penetration *contact_traction_it = normal_opening; *contact_traction_it *= penalty; *contact_opening_it = normal_opening; /// 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(); } 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, 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$ */ 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); } } delete [] memory_space; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt spatial_dimension> void MaterialCohesiveLinear<spatial_dimension>::computeTangentTraction(const ElementType & el_type, Array<Real> & tangent_matrix, const Array<Real> & normal, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators Array<Real>::matrix_iterator tangent_it = tangent_matrix.begin(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator tangent_end = tangent_matrix.end(spatial_dimension, spatial_dimension); Array<Real>::const_vector_iterator normal_it = normal.begin(spatial_dimension); Array<Real>::vector_iterator opening_it = opening(el_type, ghost_type).begin(spatial_dimension); Array<Real>::iterator<Real>delta_max_it = delta_max.previous(el_type, ghost_type).begin(); Array<Real>::iterator<Real>sigma_c_it = sigma_c_eff(el_type, ghost_type).begin(); Array<Real>::iterator<Real>delta_c_it = delta_c_eff(el_type, ghost_type).begin(); Array<Real>::iterator<Real>damage_it = damage(el_type, ghost_type).begin(); Array<Real>::iterator< Vector<Real> > contact_opening_it = contact_opening(el_type, ghost_type).begin(spatial_dimension); Vector<Real> normal_opening(spatial_dimension); Vector<Real> tangential_opening(spatial_dimension); for (; tangent_it != tangent_end; ++tangent_it, ++normal_it, ++opening_it, ++ delta_max_it, ++sigma_c_it, ++delta_c_it, ++damage_it, ++contact_opening_it) { /// compute normal and tangential opening vectors *opening_it += *contact_opening_it; 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(); Real derivative = 0; Real t = 0; Real delta = tangential_opening_norm * tangential_opening_norm * beta2_kappa2; delta += normal_opening_norm * normal_opening_norm; delta = std::sqrt(delta); if (delta < Math::getTolerance()) delta = (*delta_c_it)/1000.; //0.0000001; if (normal_opening_norm >= 0.0){ if (delta >= *delta_max_it){ derivative = -*sigma_c_it/(delta * delta); t = *sigma_c_it * (1 - delta / *delta_c_it); } else if (delta < *delta_max_it){ Real tmax = *sigma_c_it * (1 - *delta_max_it / *delta_c_it); t = tmax / *delta_max_it * delta; } } Matrix<Real> n_outer_n(spatial_dimension, spatial_dimension); n_outer_n.outerProduct(*normal_it, *normal_it); if (penetration){ ///don't consider penetration contribution for delta *opening_it = tangential_opening; *tangent_it += n_outer_n; *tangent_it *= penalty; } Matrix<Real> I(spatial_dimension, spatial_dimension); I.eye(beta2_kappa); Matrix<Real> nn(n_outer_n); nn *= (1 - beta2_kappa); nn += I; nn *= t/delta; Vector<Real> t_tilde(normal_opening); t_tilde *= (1 - beta2_kappa2); Vector<Real> mm(*opening_it); mm *= beta2_kappa2; t_tilde += mm; Vector<Real> t_hat(normal_opening); t_hat += beta2_kappa * tangential_opening; Matrix<Real> prov(spatial_dimension, spatial_dimension); prov.outerProduct(t_hat, t_tilde); prov *= derivative/delta; prov += nn; *tangent_it += prov; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANSIATE_MATERIAL(MaterialCohesiveLinear); __END_AKANTU__ diff --git a/src/model/solid_mechanics/materials/material_embedded/embedded_internal_field.hh b/src/model/solid_mechanics/materials/material_embedded/embedded_internal_field.hh index dd1d2a83f..2692bcc3a 100644 --- a/src/model/solid_mechanics/materials/material_embedded/embedded_internal_field.hh +++ b/src/model/solid_mechanics/materials/material_embedded/embedded_internal_field.hh @@ -1,74 +1,81 @@ /** * @file embedded_internal_field.hh * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Thu Mar 19 2015 * @date last modification: Thu Mar 19 2015 * * @brief Embedded Material internal properties * * @section LICENSE * * Copyright (©) 2015 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "internal_field.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_EMBEDDED_INTERNAL_FIELD_HH__ #define __AKANTU_EMBEDDED_INTERNAL_FIELD_HH__ __BEGIN_AKANTU__ class Material; class FEEngine; template<typename T> class EmbeddedInternalField : public InternalField<T> { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: EmbeddedInternalField(const ID & id, Material & material): InternalField<T>(id, material, material.getModel().getFEEngine("EmbeddedInterfaceFEEngine"), material.getElementFilter()) { this->spatial_dimension = 1; } EmbeddedInternalField(const ID & id, const EmbeddedInternalField & other): InternalField<T>(id, other) { this->spatial_dimension = 1; } void operator=(const EmbeddedInternalField & other) { InternalField<T>::operator=(other); this->spatial_dimension = 1; } }; +template<> +inline void ParsableParamTyped< EmbeddedInternalField<Real> >::parseParam(const ParserParameter & in_param) { + ParsableParam::parseParam(in_param); + Real r = in_param; + param.setDefaultValue(r); +} + __END_AKANTU__ #endif // __AKANTU_EMBEDDED_INTERNAL_FIELD_HH__ diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc index 347ee03f2..2b160ef21 100644 --- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc +++ b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.cc @@ -1,673 +1,676 @@ /** * @file material_reinforcement.cc * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Thu Mar 12 2015 * @date last modification: Thu Mar 12 2015 * * @brief Reinforcement material * * @section LICENSE * * Copyright (©) 2010-2012, 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_voigthelper.hh" #include "material_reinforcement.hh" __BEGIN_AKANTU__ template<UInt dim> MaterialReinforcement<dim>::MaterialReinforcement(SolidMechanicsModel & model, const ID & id): Material(model, id), model(NULL), gradu("gradu_embedded", *this), stress("stress_embedded", *this), directing_cosines("directing_cosines", *this), + pre_stress("pre_stress", *this), area(1.0), shape_derivatives() { this->model = dynamic_cast<EmbeddedInterfaceModel *>(&model); AKANTU_DEBUG_ASSERT(this->model != NULL, "MaterialReinforcement needs an EmbeddedInterfaceModel"); this->model->getInterfaceMesh().initElementTypeMapArray(element_filter, 1, 1, false, _ek_regular); this->registerParam("area", area, _pat_parsable | _pat_modifiable, "Reinforcement cross-sectional area"); + this->registerParam("pre_stress", pre_stress, _pat_parsable | _pat_modifiable, "Uniform pre-stress"); } /* -------------------------------------------------------------------------- */ template<UInt dim> MaterialReinforcement<dim>::~MaterialReinforcement() { AKANTU_DEBUG_IN(); ElementTypeMap<ElementTypeMapArray<Real> *>::type_iterator it = shape_derivatives.firstType(); ElementTypeMap<ElementTypeMapArray<Real> *>::type_iterator end = shape_derivatives.lastType(); for (; it != end ; ++it) { delete shape_derivatives(*it, _not_ghost); delete shape_derivatives(*it, _ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::initMaterial() { Material::initMaterial(); gradu.initialize(dim * dim); stress.initialize(dim * dim); + pre_stress.initialize(1); /// We initialise the stuff that is not going to change during the simulation this->allocBackgroundShapeDerivatives(); this->initBackgroundShapeDerivatives(); this->initDirectingCosines(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::allocBackgroundShapeDerivatives() { AKANTU_DEBUG_IN(); Mesh & interface_mesh = model->getInterfaceMesh(); Mesh & mesh = model->getMesh(); ghost_type_t::iterator int_ghost_it = ghost_type_t::begin(); // Loop over interface ghosts for (; int_ghost_it != ghost_type_t::end() ; ++int_ghost_it) { Mesh::type_iterator interface_type_it = interface_mesh.firstType(); Mesh::type_iterator interface_type_end = interface_mesh.lastType(); for (; interface_type_it != interface_type_end ; ++interface_type_it) { Mesh::type_iterator background_type_it = mesh.firstType(dim, *int_ghost_it); Mesh::type_iterator background_type_end = mesh.lastType(dim, *int_ghost_it); for (; background_type_it != background_type_end ; ++background_type_it) { const ElementType & int_type = *interface_type_it; const ElementType & back_type = *background_type_it; const GhostType & int_ghost = *int_ghost_it; std::string shaped_id = "embedded_shape_derivatives"; if (int_ghost == _ghost) shaped_id += ":ghost"; ElementTypeMapArray<Real> * shaped_etma = new ElementTypeMapArray<Real>(shaped_id, this->name); UInt nb_points = Mesh::getNbNodesPerElement(back_type); UInt nb_quad_points = model->getFEEngine("EmbeddedInterfaceFEEngine").getNbQuadraturePoints(int_type); UInt nb_elements = element_filter(int_type, int_ghost).getSize(); shaped_etma->alloc(nb_elements * nb_quad_points, dim * nb_points, back_type); shape_derivatives(shaped_etma, int_type, int_ghost); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::initBackgroundShapeDerivatives() { AKANTU_DEBUG_IN(); Mesh & mesh = model->getMesh(); Mesh::type_iterator type_it = mesh.firstType(dim, _not_ghost); Mesh::type_iterator type_end = mesh.lastType(dim, _not_ghost); for (; type_it != type_end ; ++type_it) { computeBackgroundShapeDerivatives(*type_it, _not_ghost); //computeBackgroundShapeDerivatives(*type_it, _ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::initDirectingCosines() { AKANTU_DEBUG_IN(); Mesh & mesh = model->getInterfaceMesh(); Mesh::type_iterator type_it = mesh.firstType(1, _not_ghost); Mesh::type_iterator type_end = mesh.lastType(1, _not_ghost); const UInt voigt_size = getTangentStiffnessVoigtSize(dim); directing_cosines.initialize(voigt_size * voigt_size); for (; type_it != type_end ; ++type_it) { computeDirectingCosines(*type_it, _not_ghost); computeDirectingCosines(*type_it, _ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::assembleStiffnessMatrix(GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = model->getInterfaceMesh(); Mesh::type_iterator type_it = interface_mesh.firstType(); Mesh::type_iterator type_end = interface_mesh.lastType(); for (; type_it != type_end ; ++type_it) { assembleStiffnessMatrix(*type_it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::updateResidual(GhostType ghost_type) { AKANTU_DEBUG_IN(); computeAllStresses(ghost_type); assembleResidual(ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::assembleResidual(GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = model->getInterfaceMesh(); Mesh::type_iterator type_it = interface_mesh.firstType(); Mesh::type_iterator type_end = interface_mesh.lastType(); for (; type_it != type_end ; ++type_it) { assembleResidual(*type_it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::computeGradU(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array<UInt> & elem_filter = element_filter(type, ghost_type); UInt nb_element = elem_filter.getSize(); UInt nb_quad_points = model->getFEEngine("EmbeddedInterfaceFEEngine").getNbQuadraturePoints(type); Array<Real> & gradu_vec = gradu(type, ghost_type); Mesh::type_iterator back_it = model->getMesh().firstType(dim, ghost_type); Mesh::type_iterator back_end = model->getMesh().lastType(dim, ghost_type); for (; back_it != back_end ; ++back_it) { UInt nodes_per_background_e = Mesh::getNbNodesPerElement(*back_it); Array<Real> * shapesd_filtered = new Array<Real>(nb_element, dim * nodes_per_background_e, "shapesd_filtered"); FEEngine::filterElementalData(model->getInterfaceMesh(), shape_derivatives(type, ghost_type)->operator()(*back_it, ghost_type), *shapesd_filtered, type, ghost_type, elem_filter); Array<UInt> * background_filter = new Array<UInt>(nb_element, 1, "background_filter"); filterInterfaceBackgroundElements(*background_filter, *back_it, type, ghost_type, ghost_type); Array<Real> * disp_per_element = new Array<Real>(0, dim * nodes_per_background_e, "disp_elem"); FEEngine::extractNodalToElementField(model->getMesh(), model->getDisplacement(), *disp_per_element, *back_it, ghost_type, *background_filter); Array<Real>::matrix_iterator disp_it = disp_per_element->begin(dim, nodes_per_background_e); Array<Real>::matrix_iterator disp_end = disp_per_element->end(dim, nodes_per_background_e); Array<Real>::matrix_iterator shapes_it = shapesd_filtered->begin(dim, nodes_per_background_e); Array<Real>::matrix_iterator grad_u_it = gradu_vec.begin(dim, dim); for (; disp_it != disp_end ; ++disp_it) { for (UInt i = 0; i < nb_quad_points; i++, ++shapes_it, ++grad_u_it) { Matrix<Real> & B = *shapes_it; Matrix<Real> & du = *grad_u_it; Matrix<Real> & u = *disp_it; du.mul<false, true>(u, B); } } delete shapesd_filtered; delete background_filter; delete disp_per_element; } AKANTU_DEBUG_OUT(); } template<UInt dim> void MaterialReinforcement<dim>::computeAllStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh::type_iterator it = model->getInterfaceMesh().firstType(); Mesh::type_iterator last_type = model->getInterfaceMesh().lastType(); for(; it != last_type; ++it) { computeGradU(*it, ghost_type); computeStress(*it, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::assembleResidual(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & mesh = model->getMesh(); Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type); Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type); for (; type_it != type_end ; ++type_it) { assembleResidual(type, *type_it, ghost_type, _not_ghost); //assembleResidual(type, *type_it, ghost_type, _ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::assembleResidual(const ElementType & interface_type, const ElementType & background_type, GhostType interface_ghost, GhostType background_ghost) { AKANTU_DEBUG_IN(); UInt voigt_size = getTangentStiffnessVoigtSize(dim); Array<Real> & residual = const_cast<Array<Real> &>(model->getResidual()); FEEngine & interface_engine = model->getFEEngine("EmbeddedInterfaceFEEngine"); FEEngine & background_engine = model->getFEEngine(); Array<UInt> & elem_filter = element_filter(interface_type, interface_ghost); UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type); UInt nb_quadrature_points = interface_engine.getNbQuadraturePoints(interface_type, interface_ghost); UInt nb_element = elem_filter.getSize(); UInt back_dof = dim * nodes_per_background_e; Array<Real> & shapesd = shape_derivatives(interface_type, interface_ghost)->operator()(background_type, background_ghost); Array<Real> * shapesd_filtered = new Array<Real>(nb_element * nb_quadrature_points, back_dof, "background_shapesd"); FEEngine::filterElementalData(model->getInterfaceMesh(), shapesd, *shapesd_filtered, interface_type, interface_ghost, elem_filter); Array<Real> * integrant = new Array<Real>(nb_quadrature_points * nb_element, back_dof, "integrant"); Array<Real>::vector_iterator integrant_it = integrant->begin(back_dof); Array<Real>::vector_iterator integrant_end = integrant->end(back_dof); Array<Real>::matrix_iterator B_it = shapesd_filtered->begin(dim, nodes_per_background_e); Array<Real>::matrix_iterator C_it = directing_cosines(interface_type, interface_ghost).begin(voigt_size, voigt_size); Array<Real>::matrix_iterator sigma_it = stress(interface_type, interface_ghost).begin(dim, dim); Vector<Real> sigma(voigt_size); Matrix<Real> Bvoigt(voigt_size, back_dof); Vector<Real> Ct_sigma(voigt_size); for (; integrant_it != integrant_end ; ++integrant_it, ++B_it, ++C_it, ++sigma_it) { VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(*B_it, Bvoigt, nodes_per_background_e); Matrix<Real> & C = *C_it; Vector<Real> & BtCt_sigma = *integrant_it; stressTensorToVoigtVector(*sigma_it, sigma); Ct_sigma.mul<true>(C, sigma); BtCt_sigma.mul<true>(Bvoigt, Ct_sigma); BtCt_sigma *= area; } delete shapesd_filtered; Array<Real> * residual_interface = new Array<Real>(nb_element, back_dof, "residual_interface"); interface_engine.integrate(*integrant, *residual_interface, back_dof, interface_type, interface_ghost, elem_filter); delete integrant; Array<UInt> * background_filter = new Array<UInt>(nb_element, 1, "background_filter"); filterInterfaceBackgroundElements(*background_filter, background_type, interface_type, background_ghost, interface_ghost); background_engine.assembleArray(*residual_interface, residual, model->getDOFSynchronizer().getLocalDOFEquationNumbers(), dim, background_type, background_ghost, *background_filter, -1.0); delete residual_interface; delete background_filter; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::filterInterfaceBackgroundElements(Array<UInt> & filter, const ElementType & type, const ElementType & interface_type, GhostType ghost_type, GhostType interface_ghost_type) { AKANTU_DEBUG_IN(); filter.resize(0); filter.clear(); Array<Element> & elements = model->getInterfaceAssociatedElements(interface_type, interface_ghost_type); Array<UInt> & elem_filter = element_filter(interface_type, interface_ghost_type); Array<UInt>::scalar_iterator filter_it = elem_filter.begin(), filter_end = elem_filter.end(); for (; filter_it != filter_end ; ++filter_it) { Element & elem = elements(*filter_it); if (elem.type == type) filter.push_back(elem.element); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::computeDirectingCosines(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = this->model->getInterfaceMesh(); const UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const UInt steel_dof = dim * nb_nodes_per_element; const UInt voigt_size = getTangentStiffnessVoigtSize(dim); const UInt nb_quad_points = model->getFEEngine("EmbeddedInterfaceFEEngine").getNbQuadraturePoints(type, ghost_type); Array<Real> node_coordinates(this->element_filter(type, ghost_type).getSize(), steel_dof); this->model->getFEEngine().template extractNodalToElementField<Real>(interface_mesh, interface_mesh.getNodes(), node_coordinates, type, ghost_type, this->element_filter(type, ghost_type)); Array<Real>::matrix_iterator directing_cosines_it = directing_cosines(type, ghost_type).begin(voigt_size, voigt_size); Array<Real>::matrix_iterator node_coordinates_it = node_coordinates.begin(dim, nb_nodes_per_element); Array<Real>::matrix_iterator node_coordinates_end = node_coordinates.end(dim, nb_nodes_per_element); for (; node_coordinates_it != node_coordinates_end ; ++node_coordinates_it) { for (UInt i = 0 ; i < nb_quad_points ; i++, ++directing_cosines_it) { Matrix<Real> & nodes = *node_coordinates_it; Matrix<Real> & cosines = *directing_cosines_it; computeDirectingCosinesOnQuad(nodes, cosines); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim> void MaterialReinforcement<dim>::assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & mesh = model->getMesh(); Mesh::type_iterator type_it = mesh.firstType(dim, ghost_type); Mesh::type_iterator type_end = mesh.lastType(dim, ghost_type); for (; type_it != type_end ; ++type_it) { assembleStiffnessMatrix(type, *type_it, ghost_type, _not_ghost); //assembleStiffnessMatrix(type, *type_it, ghost_type, _ghost); } AKANTU_DEBUG_OUT(); } template<UInt dim> void MaterialReinforcement<dim>::assembleStiffnessMatrix(const ElementType & interface_type, const ElementType & background_type, GhostType interface_ghost, GhostType background_ghost) { AKANTU_DEBUG_IN(); UInt voigt_size = getTangentStiffnessVoigtSize(dim); SparseMatrix & K = const_cast<SparseMatrix &>(model->getStiffnessMatrix()); FEEngine & background_engine = model->getFEEngine(); FEEngine & interface_engine = model->getFEEngine("EmbeddedInterfaceFEEngine"); Array<UInt> & elem_filter = element_filter(interface_type, interface_ghost); Array<Real> & grad_u = gradu(interface_type, interface_ghost); UInt nb_element = elem_filter.getSize(); UInt nodes_per_background_e = Mesh::getNbNodesPerElement(background_type); UInt nb_quadrature_points = interface_engine.getNbQuadraturePoints(interface_type, interface_ghost); UInt back_dof = dim * nodes_per_background_e; UInt integrant_size = back_dof; grad_u.resize(nb_quadrature_points * nb_element); //need function model->getInterfaceDisplacement() /*interface_engine.gradientOnQuadraturePoints(model->getInterfaceDisplacement(), grad_u, dim, interface_type, interface_ghost, elem_filter);*/ Array<Real> * tangent_moduli = new Array<Real>(nb_element * nb_quadrature_points, 1, "interface_tangent_moduli"); tangent_moduli->clear(); computeTangentModuli(interface_type, *tangent_moduli, interface_ghost); Array<Real> & shapesd = shape_derivatives(interface_type, interface_ghost)->operator()(background_type, background_ghost); Array<Real> * shapesd_filtered = new Array<Real>(nb_element * nb_quadrature_points, back_dof, "background_shapesd"); FEEngine::filterElementalData(model->getInterfaceMesh(), shapesd, *shapesd_filtered, interface_type, interface_ghost, elem_filter); Array<Real> * integrant = new Array<Real>(nb_element * nb_quadrature_points, integrant_size * integrant_size, "B^t*C^t*D*C*B"); integrant->clear(); /// Temporary matrices for integrant product Matrix<Real> Bvoigt(voigt_size, back_dof); Matrix<Real> DC(voigt_size, voigt_size); Matrix<Real> DCB(voigt_size, back_dof); Matrix<Real> CtDCB(voigt_size, back_dof); Array<Real>::scalar_iterator D_it = tangent_moduli->begin(); Array<Real>::scalar_iterator D_end = tangent_moduli->end(); Array<Real>::matrix_iterator C_it = directing_cosines(interface_type, interface_ghost).begin(voigt_size, voigt_size); Array<Real>::matrix_iterator B_it = shapesd_filtered->begin(dim, nodes_per_background_e); Array<Real>::matrix_iterator integrant_it = integrant->begin(integrant_size, integrant_size); for (; D_it != D_end ; ++D_it, ++C_it, ++B_it, ++integrant_it) { Real & D = *D_it; Matrix<Real> & C = *C_it; Matrix<Real> & B = *B_it; Matrix<Real> & BtCtDCB = *integrant_it; VoigtHelper<dim>::transferBMatrixToSymVoigtBMatrix(B, Bvoigt, nodes_per_background_e); DC.clear(); DC(0, 0) = D * area; DC *= C; DCB.mul<false, false>(DC, Bvoigt); CtDCB.mul<true, false>(C, DCB); BtCtDCB.mul<true, false>(Bvoigt, CtDCB); } delete tangent_moduli; delete shapesd_filtered; Array<Real> * K_interface = new Array<Real>(nb_element, integrant_size * integrant_size, "K_interface"); interface_engine.integrate(*integrant, *K_interface, integrant_size * integrant_size, interface_type, interface_ghost, elem_filter); delete integrant; Array<UInt> * background_filter = new Array<UInt>(nb_element, 1, "background_filter"); filterInterfaceBackgroundElements(*background_filter, background_type, interface_type, background_ghost, interface_ghost); background_engine.assembleMatrix(*K_interface, K, dim, background_type, background_ghost, *background_filter); delete K_interface; delete background_filter; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /// In this function, type and ghost type refer to background elements template<UInt dim> void MaterialReinforcement<dim>::computeBackgroundShapeDerivatives(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Mesh & interface_mesh = model->getInterfaceMesh(); FEEngine & engine = model->getFEEngine(); FEEngine & interface_engine = model->getFEEngine("EmbeddedInterfaceFEEngine"); Mesh::type_iterator interface_type = interface_mesh.firstType(); Mesh::type_iterator interface_last = interface_mesh.lastType(); for (; interface_type != interface_last ; ++interface_type) { Array<UInt> & filter = element_filter(*interface_type, ghost_type); const UInt nb_elements = filter.getSize(); const UInt nb_nodes = Mesh::getNbNodesPerElement(type); const UInt nb_quad_per_element = interface_engine.getNbQuadraturePoints(*interface_type); Array<Real> quad_pos(nb_quad_per_element * nb_elements, dim, "interface_quad_points"); quad_pos.resize(nb_quad_per_element * nb_elements); interface_engine.interpolateOnQuadraturePoints(interface_mesh.getNodes(), quad_pos, dim, *interface_type, ghost_type, filter); Array<Real> & background_shapesd = shape_derivatives(*interface_type, ghost_type)->operator()(type, ghost_type); background_shapesd.clear(); Array<UInt> * background_elements = new Array<UInt>(nb_elements, 1, "computeBackgroundShapeDerivatives:background_filter"); filterInterfaceBackgroundElements(*background_elements, type, *interface_type, ghost_type, ghost_type); Array<UInt>::scalar_iterator back_it = background_elements->begin(), back_end = background_elements->end(); Array<Real>::matrix_iterator shapesd_it = background_shapesd.begin(dim, nb_nodes); Array<Real>::vector_iterator quad_pos_it = quad_pos.begin(dim); for (; back_it != back_end ; ++back_it) { for (UInt i = 0 ; i < nb_quad_per_element ; i++, ++shapesd_it, ++quad_pos_it) engine.computeShapeDerivatives(*quad_pos_it, *back_it, type, *shapesd_it, ghost_type); } delete background_elements; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ INSTANSIATE_MATERIAL(MaterialReinforcement); /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh index 0ccfc3409..1283badbe 100644 --- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh +++ b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement.hh @@ -1,166 +1,169 @@ /** * @file material_reinforcement.hh * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Thu Mar 12 2015 * @date last modification: Thu Mar 12 2015 * * @brief Reinforcement material * * @section LICENSE * * Copyright (©) 2010-2012, 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_REINFORCEMENT_HH__ #define __AKANTU_MATERIAL_REINFORCEMENT_HH__ #include "aka_common.hh" #include "material.hh" #include "embedded_interface_model.hh" #include "embedded_internal_field.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ template<UInt dim> class MaterialReinforcement : virtual public Material { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: /// Constructor MaterialReinforcement(SolidMechanicsModel & model, const ID & id = ""); /// Destructor virtual ~MaterialReinforcement(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// Init the material virtual void initMaterial(); /// Init the background shape derivatives void initBackgroundShapeDerivatives(); /// Init the cosine matrices void initDirectingCosines(); /// Assemble stiffness matrix virtual void assembleStiffnessMatrix(GhostType ghost_type); /// Update the residual virtual void updateResidual(GhostType ghost_type = _not_ghost); /// Assembled the residual virtual void assembleResidual(GhostType ghost_type); /// Compute all the stresses ! virtual void computeAllStresses(GhostType ghost_type); /// Compute the stiffness parameter for elements of a type virtual void computeTangentModuli(const ElementType & type, Array<Real> & tangent, GhostType ghost_type) = 0; /* ------------------------------------------------------------------------ */ /* Protected methods */ /* ------------------------------------------------------------------------ */ protected: /// Allocate the background shape derivatives void allocBackgroundShapeDerivatives(); /// Compute the directing cosines matrix for one element type void computeDirectingCosines(const ElementType & type, GhostType ghost_type); /// Compute the directing cosines matrix on quadrature points inline void computeDirectingCosinesOnQuad(const Matrix<Real> & nodes, Matrix<Real> & cosines); /// Assemble the stiffness matrix for an element type (typically _segment_2) void assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type); /// Assemble the stiffness matrix for background & interface types void assembleStiffnessMatrix(const ElementType & interface_type, const ElementType & background_type, GhostType interface_ghost, GhostType background_ghost); /// Compute the background shape derivatives for a type (typically _triangle_3 / _tetrahedron_4) void computeBackgroundShapeDerivatives(const ElementType & type, GhostType ghost_type); /// Filter elements crossed by interface of a type void filterInterfaceBackgroundElements(Array<UInt> & filter, const ElementType & type, const ElementType & interface_type, GhostType ghost_type, GhostType interface_ghost_type); /// Assemble the residual of one type of element (typically _segment_2) void assembleResidual(const ElementType & type, GhostType ghost_type); /// Assemble the residual for a pair of elements void assembleResidual(const ElementType & interface_type, const ElementType & background_type, GhostType interface_ghost, GhostType background_ghost); /// TODO figure out why voigt size is 4 in 2D inline void stressTensorToVoigtVector(const Matrix<Real> & tensor, Vector<Real> & vector); inline void strainTensorToVoigtVector(const Matrix<Real> & tensor, Vector<Real> & vector); /// Compute gradu on the interface quadrature points virtual void computeGradU(const ElementType & type, GhostType ghost_type); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// Embedded model EmbeddedInterfaceModel * model; /// grad_u EmbeddedInternalField<Real> gradu; /// stress EmbeddedInternalField<Real> stress; /// C matrix on quad EmbeddedInternalField<Real> directing_cosines; + /// Prestress on quad + EmbeddedInternalField<Real> pre_stress; + /// Cross-sectional area Real area; /// Background mesh shape derivatives ElementTypeMap< ElementTypeMapArray<Real> * > shape_derivatives; }; #include "material_reinforcement_inline_impl.cc" __END_AKANTU__ #endif // __AKANTU_MATERIAL_REINFORCEMENT_HH__ diff --git a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template_inline_impl.cc b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template_inline_impl.cc index 5fa2de99b..98212fa47 100644 --- a/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template_inline_impl.cc +++ b/src/model/solid_mechanics/materials/material_embedded/material_reinforcement_template_inline_impl.cc @@ -1,178 +1,180 @@ /** * @file material_reinforcement_template.cc * * @author Lucas Frérot <lucas.frerot@epfl.ch> * * @date creation: Mon Mar 16 2015 * @date last modification: Mon Mar 16 2015 * * @brief Reinforcement material templated with constitutive law * * @section LICENSE * * Copyright (©) 2010-2012, 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ template<UInt dim, class ConstLaw> MaterialReinforcementTemplate<dim, ConstLaw>::MaterialReinforcementTemplate(SolidMechanicsModel & model, const ID & id): Material(model, id), MaterialReinforcement<dim>(model, id), ConstLaw(model, id) {} /* -------------------------------------------------------------------------- */ template<UInt dim, class ConstLaw> MaterialReinforcementTemplate<dim, ConstLaw>::~MaterialReinforcementTemplate() {} /* -------------------------------------------------------------------------- */ template<UInt dim, class ConstLaw> void MaterialReinforcementTemplate<dim, ConstLaw>::initMaterial() { MaterialReinforcement<dim>::initMaterial(); // Gotta change the dimension from here onwards this->ConstLaw::spatial_dimension = 1; ConstLaw::initMaterial(); this->ConstLaw::gradu.free(); this->ConstLaw::stress.free(); this->ConstLaw::delta_T.free(); this->ConstLaw::sigma_th.free(); this->ConstLaw::potential_energy.free(); Mesh::type_iterator type_it = this->MaterialReinforcement<dim>::model->getInterfaceMesh().firstType(); Mesh::type_iterator type_end = this->MaterialReinforcement<dim>::model->getInterfaceMesh().lastType(); // Reshape the ConstLaw internal fields for (; type_it != type_end ; ++type_it) { UInt nb_elements = this->MaterialReinforcement<dim>::element_filter(*type_it).getSize(); FEEngine & interface_engine = this->MaterialReinforcement<dim>::model->getFEEngine("EmbeddedInterfaceFEEngine"); UInt nb_quad = interface_engine.getNbQuadraturePoints(*type_it); this->ConstLaw::gradu.alloc(nb_elements * nb_quad, 1, *type_it, _not_ghost); this->ConstLaw::stress.alloc(nb_elements * nb_quad, 1, *type_it, _not_ghost); this->ConstLaw::delta_T.alloc(nb_elements * nb_quad, 1, *type_it, _not_ghost); this->ConstLaw::sigma_th.alloc(nb_elements * nb_quad, 1, *type_it, _not_ghost); this->ConstLaw::potential_energy.alloc(nb_elements * nb_quad, 1, *type_it, _not_ghost); //this->ConstLaw::gradu.alloc(0, dim * dim, *type_it, _ghost); } } /* -------------------------------------------------------------------------- */ template<UInt dim, class ConstLaw> void MaterialReinforcementTemplate<dim, ConstLaw>::computeGradU(const ElementType & el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); MaterialReinforcement<dim>::computeGradU(el_type, ghost_type); const UInt voigt_size = Material::getTangentStiffnessVoigtSize(dim); Array<Real>::matrix_iterator full_gradu_it = this->MaterialReinforcement<dim>::gradu(el_type, ghost_type).begin(dim, dim); Array<Real>::matrix_iterator full_gradu_end = this->MaterialReinforcement<dim>::gradu(el_type, ghost_type).end(dim, dim); Array<Real>::scalar_iterator gradu_it = this->ConstLaw::gradu(el_type, ghost_type).begin(); Array<Real>::matrix_iterator cosines_it = this->directing_cosines(el_type, ghost_type).begin(voigt_size, voigt_size); for (; full_gradu_it != full_gradu_end ; ++full_gradu_it, ++gradu_it, ++cosines_it) { Matrix<Real> & full_gradu = *full_gradu_it; Real & gradu = *gradu_it; Matrix<Real> & C = *cosines_it; computeInterfaceGradUOnQuad(full_gradu, gradu, C); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim, class ConstLaw> void MaterialReinforcementTemplate<dim, ConstLaw>::computeInterfaceGradUOnQuad(const Matrix<Real> & full_gradu, Real & gradu, const Matrix<Real> & C) { const UInt voigt_size = Material::getTangentStiffnessVoigtSize(dim); Matrix<Real> epsilon(dim, dim); Vector<Real> e_voigt(voigt_size); Vector<Real> e_interface_voigt(voigt_size); epsilon = 0.5 * (full_gradu + full_gradu.transpose()); MaterialReinforcement<dim>::strainTensorToVoigtVector(epsilon, e_voigt); e_interface_voigt.mul<false>(C, e_voigt); gradu = e_interface_voigt(0); } /* -------------------------------------------------------------------------- */ template<UInt dim, class ConstLaw> void MaterialReinforcementTemplate<dim, ConstLaw>::computeTangentModuli(const ElementType & el_type, Array<Real> & tangent, GhostType ghost_type) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(tangent.getNbComponent() == 1, "Reinforcements only work in 1D"); ConstLaw::computeTangentModuli(el_type, tangent, ghost_type); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<UInt dim, class ConstLaw> void MaterialReinforcementTemplate<dim, ConstLaw>::computeStress(ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); ConstLaw::computeStress(type, ghost_type); Array<Real>::matrix_iterator full_sigma_it = this->MaterialReinforcement<dim>::stress(type, ghost_type).begin(dim, dim); Array<Real>::matrix_iterator full_sigma_end = this->MaterialReinforcement<dim>::stress(type, ghost_type).end(dim, dim); Array<Real>::scalar_iterator sigma_it = this->ConstLaw::stress(type, ghost_type).begin(); + Array<Real>::scalar_iterator pre_stress_it = + this->MaterialReinforcement<dim>::pre_stress(type, ghost_type).begin(); - for (; full_sigma_it != full_sigma_end ; ++full_sigma_it, ++sigma_it) { + for (; full_sigma_it != full_sigma_end ; ++full_sigma_it, ++sigma_it, ++pre_stress_it) { Matrix<Real> & sigma = *full_sigma_it; - sigma(0, 0) = *sigma_it; + sigma(0, 0) = *sigma_it + *pre_stress_it; } AKANTU_DEBUG_OUT(); } diff --git a/src/model/solid_mechanics/solid_mechanics_model.cc b/src/model/solid_mechanics/solid_mechanics_model.cc index 78de0b7d5..d9dad7b21 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.cc +++ b/src/model/solid_mechanics/solid_mechanics_model.cc @@ -1,1833 +1,1832 @@ /** * @file solid_mechanics_model.cc * * @author Guillaume Anciaux <guillaume.anciaux@epfl.ch> * @author David Simon Kammer <david.kammer@epfl.ch> * @author Aurelia Isabel Cuba Ramos <aurelia.cubaramos@epfl.ch> * @author Daniel Pino Muñoz <daniel.pinomunoz@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * * @date creation: Tue Jul 27 2010 * @date last modification: Fri Sep 19 2014 * * @brief Implementation of the SolidMechanicsModel class * * @section LICENSE * * Copyright (©) 2010-2012, 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "aka_math.hh" #include "aka_common.hh" #include "solid_mechanics_model.hh" #include "group_manager_inline_impl.cc" #include "dumpable_inline_impl.hh" #include "integration_scheme_2nd_order.hh" #include "element_group.hh" #include "static_communicator.hh" #include "dof_synchronizer.hh" #include "element_group.hh" #include <cmath> #ifdef AKANTU_USE_MUMPS #include "solver_mumps.hh" #endif #ifdef AKANTU_USE_PETSC #include "solver_petsc.hh" #include "petsc_matrix.hh" #endif #ifdef AKANTU_USE_IOHELPER # include "dumper_field.hh" # include "dumper_paraview.hh" # include "dumper_homogenizing_field.hh" # include "dumper_material_internal_field.hh" # include "dumper_elemental_field.hh" # include "dumper_material_padders.hh" # include "dumper_element_partition.hh" # include "dumper_iohelper.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ const SolidMechanicsModelOptions default_solid_mechanics_model_options(_explicit_lumped_mass, false); /* -------------------------------------------------------------------------- */ /** * A solid mechanics model need a mesh and a dimension to be created. the model * by it self can not do a lot, the good init functions should be called in * order to configure the model depending on what we want to do. * * @param mesh mesh representing the model we want to simulate * @param dim spatial dimension of the problem, if dim = 0 (default value) the * dimension of the problem is assumed to be the on of the mesh * @param id an id to identify the model */ SolidMechanicsModel::SolidMechanicsModel(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) : Model(mesh, dim, id, memory_id), BoundaryCondition<SolidMechanicsModel>(), time_step(NAN), f_m2a(1.0), mass_matrix(NULL), velocity_damping_matrix(NULL), stiffness_matrix(NULL), jacobian_matrix(NULL), material_index("material index", id), material_local_numbering("material local numbering", id), material_selector(new DefaultMaterialSelector(material_index)), is_default_material_selector(true), integrator(NULL), increment_flag(false), solver(NULL), synch_parallel(NULL), are_materials_instantiated(false) { AKANTU_DEBUG_IN(); createSynchronizerRegistry(this); registerFEEngineObject<MyFEEngineType>("SolidMechanicsFEEngine", mesh, spatial_dimension); this->displacement = NULL; this->mass = NULL; this->velocity = NULL; this->acceleration = NULL; this->force = NULL; this->residual = NULL; this->blocked_dofs = NULL; this->increment = NULL; this->increment_acceleration = NULL; this->dof_synchronizer = NULL; this->previous_displacement = NULL; materials.clear(); mesh.registerEventHandler(*this); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper<DumperParaview>("paraview_all", id, true); this->mesh.addDumpMesh(mesh, spatial_dimension, _not_ghost, _ek_regular); #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SolidMechanicsModel::~SolidMechanicsModel() { AKANTU_DEBUG_IN(); std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { delete *mat_it; } materials.clear(); delete integrator; delete solver; delete mass_matrix; delete velocity_damping_matrix; if(stiffness_matrix && stiffness_matrix != jacobian_matrix) delete stiffness_matrix; delete jacobian_matrix; delete synch_parallel; if(is_default_material_selector) { delete material_selector; material_selector = NULL; } AKANTU_DEBUG_OUT(); } void SolidMechanicsModel::setTimeStep(Real time_step) { this->time_step = time_step; #if defined(AKANTU_USE_IOHELPER) this->mesh.getDumper().setTimeStep(time_step); #endif } /* -------------------------------------------------------------------------- */ /* Initialisation */ /* -------------------------------------------------------------------------- */ /** * This function groups many of the initialization in on function. For most of * basics case the function should be enough. The functions initialize the * model, the internal vectors, set them to 0, and depending on the parameters * it also initialize the explicit or implicit solver. * * @param material_file the file containing the materials to use * @param method the analysis method wanted. See the akantu::AnalysisMethod for * the different possibilities */ void SolidMechanicsModel::initFull(const ModelOptions & options) { Model::initFull(options); const SolidMechanicsModelOptions & smm_options = dynamic_cast<const SolidMechanicsModelOptions &>(options); method = smm_options.analysis_method; // initialize the vectors initArrays(); // set the initial condition to 0 force->clear(); velocity->clear(); acceleration->clear(); displacement->clear(); // initialize pcb if(pbc_pair.size()!=0) initPBC(); // initialize the time integration schemes switch(method) { case _explicit_lumped_mass: initExplicit(); break; case _explicit_consistent_mass: initSolver(); initExplicit(); break; case _implicit_dynamic: initImplicit(true); break; case _static: initImplicit(false); break; default: AKANTU_EXCEPTION("analysis method not recognised by SolidMechanicsModel"); break; } // initialize the materials if(this->parser->getLastParsedFile() != "") { instantiateMaterials(); } if(!smm_options.no_init_materials) { initMaterials(); } if(increment_flag) initBC(*this, *displacement, *increment, *force); else initBC(*this, *displacement, *force); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initParallel(MeshPartition * partition, DataAccessor * data_accessor) { AKANTU_DEBUG_IN(); if (data_accessor == NULL) data_accessor = this; synch_parallel = &createParallelSynch(partition,data_accessor); synch_registry->registerSynchronizer(*synch_parallel, _gst_material_id); synch_registry->registerSynchronizer(*synch_parallel, _gst_smm_mass); synch_registry->registerSynchronizer(*synch_parallel, _gst_smm_stress); synch_registry->registerSynchronizer(*synch_parallel, _gst_smm_boundary); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initFEEngineBoundary() { FEEngine & fem_boundary = getFEEngineBoundary(); fem_boundary.initShapeFunctions(_not_ghost); fem_boundary.initShapeFunctions(_ghost); fem_boundary.computeNormalsOnControlPoints(_not_ghost); fem_boundary.computeNormalsOnControlPoints(_ghost); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initExplicit(AnalysisMethod analysis_method) { AKANTU_DEBUG_IN(); //in case of switch from implicit to explicit if(!this->isExplicit()) method = analysis_method; if (integrator) delete integrator; integrator = new CentralDifference(); UInt nb_nodes = acceleration->getSize(); UInt nb_degree_of_freedom = acceleration->getNbComponent(); std::stringstream sstr; sstr << id << ":increment_acceleration"; increment_acceleration = &(alloc<Real>(sstr.str(), nb_nodes, nb_degree_of_freedom, Real())); AKANTU_DEBUG_OUT(); } void SolidMechanicsModel::initArraysPreviousDisplacment() { AKANTU_DEBUG_IN(); SolidMechanicsModel::setIncrementFlagOn(); UInt nb_nodes = mesh.getNbNodes(); std::stringstream sstr_disp_t; sstr_disp_t << id << ":previous_displacement"; previous_displacement = &(alloc<Real > (sstr_disp_t.str(), nb_nodes, spatial_dimension, 0.)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Allocate all the needed vectors. By default their are not necessarily set to * 0 * */ void SolidMechanicsModel::initArrays() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); std::stringstream sstr_disp; sstr_disp << id << ":displacement"; // std::stringstream sstr_mass; sstr_mass << id << ":mass"; std::stringstream sstr_velo; sstr_velo << id << ":velocity"; std::stringstream sstr_acce; sstr_acce << id << ":acceleration"; std::stringstream sstr_forc; sstr_forc << id << ":force"; std::stringstream sstr_resi; sstr_resi << id << ":residual"; std::stringstream sstr_boun; sstr_boun << id << ":blocked_dofs"; displacement = &(alloc<Real>(sstr_disp.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); // mass = &(alloc<Real>(sstr_mass.str(), nb_nodes, spatial_dimension, 0)); velocity = &(alloc<Real>(sstr_velo.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); acceleration = &(alloc<Real>(sstr_acce.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); force = &(alloc<Real>(sstr_forc.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); residual = &(alloc<Real>(sstr_resi.str(), nb_nodes, spatial_dimension, REAL_INIT_VALUE)); blocked_dofs = &(alloc<bool>(sstr_boun.str(), nb_nodes, spatial_dimension, false)); std::stringstream sstr_curp; sstr_curp << id << ":current_position"; current_position = &(alloc<Real>(sstr_curp.str(), 0, spatial_dimension, REAL_INIT_VALUE)); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; Mesh::type_iterator it = mesh.firstType(spatial_dimension, gt, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(spatial_dimension, gt, _ek_not_defined); for(; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it, gt); material_index.alloc(nb_element, 1, *it, gt); material_local_numbering.alloc(nb_element, 1, *it, gt); } } dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension); dof_synchronizer->initLocalDOFEquationNumbers(); dof_synchronizer->initGlobalDOFEquationNumbers(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Initialize the model,basically it pre-compute the shapes, shapes derivatives * and jacobian * */ void SolidMechanicsModel::initModel() { /// \todo add the current position as a parameter to initShapeFunctions for /// large deformation getFEEngine().initShapeFunctions(_not_ghost); getFEEngine().initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initPBC() { Model::initPBC(); registerPBCSynchronizer(); // as long as there are ones on the diagonal of the matrix, we can put boudandary true for slaves std::map<UInt, UInt>::iterator it = pbc_pair.begin(); std::map<UInt, UInt>::iterator end = pbc_pair.end(); UInt dim = mesh.getSpatialDimension(); while(it != end) { for (UInt i=0; i<dim; ++i) (*blocked_dofs)((*it).first,i) = true; ++it; } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::registerPBCSynchronizer(){ PBCSynchronizer * synch = new PBCSynchronizer(pbc_pair); synch_registry->registerSynchronizer(*synch, _gst_smm_uv); synch_registry->registerSynchronizer(*synch, _gst_smm_mass); synch_registry->registerSynchronizer(*synch, _gst_smm_res); synch_registry->registerSynchronizer(*synch, _gst_for_dump); changeLocalEquationNumberForPBC(pbc_pair, mesh.getSpatialDimension()); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateCurrentPosition() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); current_position->resize(nb_nodes); Real * current_position_val = current_position->storage(); Real * position_val = mesh.getNodes().storage(); Real * displacement_val = displacement->storage(); /// compute current_position = initial_position + displacement memcpy(current_position_val, position_val, nb_nodes*spatial_dimension*sizeof(Real)); for (UInt n = 0; n < nb_nodes*spatial_dimension; ++n) { *current_position_val++ += *displacement_val++; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initializeUpdateResidualData() { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); residual->resize(nb_nodes); /// copy the forces in residual for boundary conditions memcpy(residual->storage(), force->storage(), nb_nodes*spatial_dimension*sizeof(Real)); // start synchronization synch_registry->asynchronousSynchronize(_gst_smm_uv); synch_registry->waitEndSynchronize(_gst_smm_uv); updateCurrentPosition(); AKANTU_DEBUG_OUT(); } /*----------------------------------------------------------------------------*/ void SolidMechanicsModel::reInitialize() { } /* -------------------------------------------------------------------------- */ /* Explicit scheme */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /** * This function compute the second member of the motion equation. That is to * say the sum of forces @f$ r = F_{ext} - F_{int} @f$. @f$ F_{ext} @f$ is given * by the user in the force vector, and @f$ F_{int} @f$ is computed as @f$ * F_{int} = \int_{\Omega} N \sigma d\Omega@f$ * */ void SolidMechanicsModel::updateResidual(bool need_initialize) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the internal forces"); // f = f_ext - f_int // f = f_ext if(need_initialize) initializeUpdateResidualData(); AKANTU_DEBUG_INFO("Compute local stresses"); std::vector<Material *>::iterator mat_it; for (mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllStresses(_not_ghost); } #ifdef AKANTU_DAMAGE_NON_LOCAL /* ------------------------------------------------------------------------ */ /* Computation of the non local part */ synch_registry->asynchronousSynchronize(_gst_mnl_for_average); AKANTU_DEBUG_INFO("Compute non local stresses for local elements"); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllNonLocalStresses(_not_ghost); } AKANTU_DEBUG_INFO("Wait distant non local stresses"); synch_registry->waitEndSynchronize(_gst_mnl_for_average); AKANTU_DEBUG_INFO("Compute non local stresses for ghosts elements"); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllNonLocalStresses(_ghost); } #endif /* ------------------------------------------------------------------------ */ /* assembling the forces internal */ // communicate the stress AKANTU_DEBUG_INFO("Send data for residual assembly"); synch_registry->asynchronousSynchronize(_gst_smm_stress); AKANTU_DEBUG_INFO("Assemble residual for local elements"); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.assembleResidual(_not_ghost); } AKANTU_DEBUG_INFO("Wait distant stresses"); // finalize communications synch_registry->waitEndSynchronize(_gst_smm_stress); AKANTU_DEBUG_INFO("Assemble residual for ghost elements"); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.assembleResidual(_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::computeStresses() { if (isExplicit()) { // start synchronization synch_registry->asynchronousSynchronize(_gst_smm_uv); synch_registry->waitEndSynchronize(_gst_smm_uv); // compute stresses on all local elements for each materials std::vector<Material *>::iterator mat_it; for (mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllStresses(_not_ghost); } /* ------------------------------------------------------------------------ */ #ifdef AKANTU_DAMAGE_NON_LOCAL /* Computation of the non local part */ synch_registry->asynchronousSynchronize(_gst_mnl_for_average); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllNonLocalStresses(_not_ghost); } synch_registry->waitEndSynchronize(_gst_mnl_for_average); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllNonLocalStresses(_ghost); } #endif } else { std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; mat.computeAllStressesFromTangentModuli(_not_ghost); } } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateResidualInternal() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Update the residual"); // f = f_ext - f_int - Ma - Cv = r - Ma - Cv; if(method != _static) { // f -= Ma if(mass_matrix) { // if full mass_matrix Array<Real> * Ma = new Array<Real>(*acceleration, true, "Ma"); *Ma *= *mass_matrix; /// \todo check unit conversion for implicit dynamics // *Ma /= f_m2a *residual -= *Ma; delete Ma; } else if (mass) { // else lumped mass UInt nb_nodes = acceleration->getSize(); UInt nb_degree_of_freedom = acceleration->getNbComponent(); Real * mass_val = mass->storage(); Real * accel_val = acceleration->storage(); Real * res_val = residual->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes * nb_degree_of_freedom; ++n) { if(!(*blocked_dofs_val)) { *res_val -= *accel_val * *mass_val /f_m2a; } blocked_dofs_val++; res_val++; mass_val++; accel_val++; } } else { AKANTU_DEBUG_ERROR("No function called to assemble the mass matrix."); } // f -= Cv if(velocity_damping_matrix) { Array<Real> * Cv = new Array<Real>(*velocity); *Cv *= *velocity_damping_matrix; *residual -= *Cv; delete Cv; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateAcceleration() { AKANTU_DEBUG_IN(); updateResidualInternal(); if(method == _explicit_lumped_mass) { /* residual = residual_{n+1} - M * acceleration_n therefore solution = increment acceleration not acceleration */ solveLumped(*increment_acceleration, *mass, *residual, *blocked_dofs, f_m2a); } else if (method == _explicit_consistent_mass) { solve<NewmarkBeta::_acceleration_corrector>(*increment_acceleration); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::solveLumped(Array<Real> & x, const Array<Real> & A, const Array<Real> & b, const Array<bool> & blocked_dofs, Real alpha) { Real * A_val = A.storage(); Real * b_val = b.storage(); Real * x_val = x.storage(); bool * blocked_dofs_val = blocked_dofs.storage(); UInt nb_degrees_of_freedom = x.getSize() * x.getNbComponent(); for (UInt n = 0; n < nb_degrees_of_freedom; ++n) { if(!(*blocked_dofs_val)) { *x_val = alpha * (*b_val / *A_val); } x_val++; A_val++; b_val++; blocked_dofs_val++; } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::explicitPred() { AKANTU_DEBUG_IN(); if(increment_flag) { if(previous_displacement) increment->copy(*previous_displacement); else increment->copy(*displacement); } AKANTU_DEBUG_ASSERT(integrator,"itegrator should have been allocated: " << "have called initExplicit ? " << "or initImplicit ?"); integrator->integrationSchemePred(time_step, *displacement, *velocity, *acceleration, *blocked_dofs); if(increment_flag) { Real * inc_val = increment->storage(); Real * dis_val = displacement->storage(); UInt nb_degree_of_freedom = displacement->getSize() * displacement->getNbComponent(); for (UInt n = 0; n < nb_degree_of_freedom; ++n) { *inc_val = *dis_val - *inc_val; inc_val++; dis_val++; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::explicitCorr() { AKANTU_DEBUG_IN(); integrator->integrationSchemeCorrAccel(time_step, *displacement, *velocity, *acceleration, *blocked_dofs, *increment_acceleration); if(previous_displacement) previous_displacement->copy(*displacement); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::solveStep() { AKANTU_DEBUG_IN(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeSolveStepEvent(method)); this->explicitPred(); this->updateResidual(); this->updateAcceleration(); this->explicitCorr(); EventManager::sendEvent(SolidMechanicsModelEvent::AfterSolveStepEvent(method)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Implicit scheme */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /** * Initialize the solver and create the sparse matrices needed. * */ void SolidMechanicsModel::initSolver(__attribute__((unused)) SolverOptions & options) { #if !defined(AKANTU_USE_MUMPS) && !defined(AKANTU_USE_PETSC)// or other solver in the future \todo add AKANTU_HAS_SOLVER in CMake AKANTU_DEBUG_ERROR("You should at least activate one solver."); #else UInt nb_global_nodes = mesh.getNbGlobalNodes(); delete jacobian_matrix; std::stringstream sstr; sstr << id << ":jacobian_matrix"; #ifdef AKANTU_USE_PETSC jacobian_matrix = new PETScMatrix(nb_global_nodes * spatial_dimension, _symmetric, sstr.str(), memory_id); #else jacobian_matrix = new SparseMatrix(nb_global_nodes * spatial_dimension, _symmetric, sstr.str(), memory_id); #endif //AKANTU_USE PETSC jacobian_matrix->buildProfile(mesh, *dof_synchronizer, spatial_dimension); if (!isExplicit()) { delete stiffness_matrix; std::stringstream sstr_sti; sstr_sti << id << ":stiffness_matrix"; #ifdef AKANTU_USE_PETSC stiffness_matrix = new SparseMatrix(nb_global_nodes * spatial_dimension, _symmetric, sstr.str(), memory_id); stiffness_matrix->buildProfile(mesh, *dof_synchronizer, spatial_dimension); #else stiffness_matrix = new SparseMatrix(*jacobian_matrix, sstr_sti.str(), memory_id); #endif //AKANTU_USE_PETSC } delete solver; std::stringstream sstr_solv; sstr_solv << id << ":solver"; #ifdef AKANTU_USE_PETSC solver = new SolverPETSc(*jacobian_matrix, sstr_solv.str()); #elif defined(AKANTU_USE_MUMPS) solver = new SolverMumps(*jacobian_matrix, sstr_solv.str()); dof_synchronizer->initScatterGatherCommunicationScheme(); #else AKANTU_DEBUG_ERROR("You should at least activate one solver."); #endif //AKANTU_USE_MUMPS if(solver) solver->initialize(options); #endif //AKANTU_HAS_SOLVER } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initJacobianMatrix() { #if defined(AKANTU_USE_MUMPS) && !defined(AKANTU_USE_PETSC) // @todo make it more flexible: this is an ugly patch to treat the case of non // fix profile of the K matrix delete jacobian_matrix; std::stringstream sstr_sti; sstr_sti << id << ":jacobian_matrix"; jacobian_matrix = new SparseMatrix(*stiffness_matrix, sstr_sti.str(), memory_id); std::stringstream sstr_solv; sstr_solv << id << ":solver"; delete solver; solver = new SolverMumps(*jacobian_matrix, sstr_solv.str()); if(solver) solver->initialize(_solver_no_options); #else AKANTU_DEBUG_ERROR("You need to activate the solver mumps."); #endif } /* -------------------------------------------------------------------------- */ /** * Initialize the implicit solver, either for dynamic or static cases, * * @param dynamic */ void SolidMechanicsModel::initImplicit(bool dynamic, SolverOptions & solver_options) { AKANTU_DEBUG_IN(); method = dynamic ? _implicit_dynamic : _static; if (!increment) setIncrementFlagOn(); initSolver(solver_options); if(method == _implicit_dynamic) { if(integrator) delete integrator; integrator = new TrapezoidalRule2(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initialAcceleration() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Solving Ma = f"); Solver * acc_solver = NULL; std::stringstream sstr; sstr << id << ":tmp_mass_matrix"; SparseMatrix * tmp_mass = new SparseMatrix(*mass_matrix, sstr.str(), memory_id); #ifdef AKANTU_USE_MUMPS std::stringstream sstr_solver; sstr << id << ":solver_mass_matrix"; acc_solver = new SolverMumps(*mass_matrix, sstr_solver.str()); dof_synchronizer->initScatterGatherCommunicationScheme(); #else AKANTU_DEBUG_ERROR("You should at least activate one solver."); #endif //AKANTU_USE_MUMPS acc_solver->initialize(); tmp_mass->applyBoundary(*blocked_dofs); acc_solver->setRHS(*residual); acc_solver->solve(*acceleration); delete acc_solver; delete tmp_mass; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the new stiffness matrix."); stiffness_matrix->clear(); // call compute stiffness matrix on each local elements std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->assembleStiffnessMatrix(_not_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SparseMatrix & SolidMechanicsModel::initVelocityDampingMatrix() { if(!velocity_damping_matrix) velocity_damping_matrix = new SparseMatrix(*jacobian_matrix, id + ":velocity_damping_matrix", memory_id); return *velocity_damping_matrix; } /* -------------------------------------------------------------------------- */ template<> bool SolidMechanicsModel::testConvergence<_scc_increment>(Real tolerance, Real & error){ AKANTU_DEBUG_IN(); UInt nb_nodes = displacement->getSize(); UInt nb_degree_of_freedom = displacement->getNbComponent(); error = 0; Real norm[2] = {0., 0.}; Real * increment_val = increment->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); Real * displacement_val = displacement->storage(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); for (UInt d = 0; d < nb_degree_of_freedom; ++d) { if(!(*blocked_dofs_val) && is_local_node) { norm[0] += *increment_val * *increment_val; norm[1] += *displacement_val * *displacement_val; } blocked_dofs_val++; increment_val++; displacement_val++; } } StaticCommunicator::getStaticCommunicator().allReduce(norm, 2, _so_sum); norm[0] = sqrt(norm[0]); norm[1] = sqrt(norm[1]); AKANTU_DEBUG_ASSERT(!Math::isnan(norm[0]), "Something goes wrong in the solve phase"); if (norm[1] < Math::getTolerance()) { error = norm[0]; AKANTU_DEBUG_OUT(); // cout<<"Error 1: "<<error<<endl; return error < tolerance; } AKANTU_DEBUG_OUT(); if(norm[1] > Math::getTolerance()) error = norm[0] / norm[1]; else error = norm[0]; //In case the total displacement is zero! // cout<<"Error 2: "<<error<<endl; return (error < tolerance); } /* -------------------------------------------------------------------------- */ template<> bool SolidMechanicsModel::testConvergence<_scc_residual>(Real tolerance, Real & norm) { AKANTU_DEBUG_IN(); - - UInt nb_nodes = residual->getSize(); + UInt nb_degree_of_freedom = displacement->getNbComponent(); norm = 0; Real * residual_val = residual->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); if(is_local_node) { - for (UInt d = 0; d < spatial_dimension; ++d) { + for (UInt d = 0; d < nb_degree_of_freedom; ++d) { if(!(*blocked_dofs_val)) { norm += *residual_val * *residual_val; } blocked_dofs_val++; residual_val++; } } else { blocked_dofs_val += spatial_dimension; residual_val += spatial_dimension; } } StaticCommunicator::getStaticCommunicator().allReduce(&norm, 1, _so_sum); norm = sqrt(norm); AKANTU_DEBUG_ASSERT(!Math::isnan(norm), "Something goes wrong in the solve phase"); AKANTU_DEBUG_OUT(); return (norm < tolerance); } /* -------------------------------------------------------------------------- */ template<> bool SolidMechanicsModel::testConvergence<_scc_residual_mass_wgh>(Real tolerance, Real & norm) { AKANTU_DEBUG_IN(); UInt nb_nodes = residual->getSize(); norm = 0; Real * residual_val = residual->storage(); Real * mass_val = this->mass->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); if(is_local_node) { for (UInt d = 0; d < spatial_dimension; ++d) { if(!(*blocked_dofs_val)) { norm += *residual_val * *residual_val/(*mass_val * *mass_val); } blocked_dofs_val++; residual_val++; mass_val++; } } else { blocked_dofs_val += spatial_dimension; residual_val += spatial_dimension; mass_val += spatial_dimension; } } StaticCommunicator::getStaticCommunicator().allReduce(&norm, 1, _so_sum); norm = sqrt(norm); AKANTU_DEBUG_ASSERT(!Math::isnan(norm), "Something goes wrong in the solve phase"); AKANTU_DEBUG_OUT(); return (norm < tolerance); } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceResidual(Real tolerance){ AKANTU_DEBUG_IN(); Real error=0; bool res = this->testConvergence<_scc_residual>(tolerance, error); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceResidual(Real tolerance, Real & error){ AKANTU_DEBUG_IN(); bool res = this->testConvergence<_scc_residual>(tolerance, error); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceIncrement(Real tolerance){ AKANTU_DEBUG_IN(); Real error=0; bool res = this->testConvergence<_scc_increment>(tolerance, error); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::testConvergenceIncrement(Real tolerance, Real & error){ AKANTU_DEBUG_IN(); bool res = this->testConvergence<_scc_increment>(tolerance, error); AKANTU_DEBUG_OUT(); return res; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::implicitPred() { AKANTU_DEBUG_IN(); if(previous_displacement) previous_displacement->copy(*displacement); if(method == _implicit_dynamic) integrator->integrationSchemePred(time_step, *displacement, *velocity, *acceleration, *blocked_dofs); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::implicitCorr() { AKANTU_DEBUG_IN(); if(method == _implicit_dynamic) { integrator->integrationSchemeCorrDispl(time_step, *displacement, *velocity, *acceleration, *blocked_dofs, *increment); } else { UInt nb_nodes = displacement->getSize(); UInt nb_degree_of_freedom = displacement->getNbComponent() * nb_nodes; Real * incr_val = increment->storage(); Real * disp_val = displacement->storage(); bool * boun_val = blocked_dofs->storage(); for (UInt j = 0; j < nb_degree_of_freedom; ++j, ++disp_val, ++incr_val, ++boun_val){ *incr_val *= (1. - *boun_val); *disp_val += *incr_val; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateIncrement() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(previous_displacement,"The previous displacement has to be initialized." << " Are you working with Finite or Ineslactic deformations?"); UInt nb_nodes = displacement->getSize(); UInt nb_degree_of_freedom = displacement->getNbComponent() * nb_nodes; Real * incr_val = increment->storage(); Real * disp_val = displacement->storage(); Real * prev_disp_val = previous_displacement->storage(); for (UInt j = 0; j < nb_degree_of_freedom; ++j, ++disp_val, ++incr_val, ++prev_disp_val) *incr_val = (*disp_val - *prev_disp_val); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updatePreviousDisplacement() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(previous_displacement,"The previous displacement has to be initialized." << " Are you working with Finite or Ineslactic deformations?"); previous_displacement->copy(*displacement); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /* Information */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::synchronizeBoundaries() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(synch_registry,"Synchronizer registry was not initialized." << " Did you call initParallel?"); synch_registry->synchronize(_gst_smm_boundary); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::synchronizeResidual() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(synch_registry,"Synchronizer registry was not initialized." << " Did you call initPBC?"); synch_registry->synchronize(_gst_smm_res); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::setIncrementFlagOn() { AKANTU_DEBUG_IN(); if(!increment) { UInt nb_nodes = mesh.getNbNodes(); std::stringstream sstr_inc; sstr_inc << id << ":increment"; increment = &(alloc<Real>(sstr_inc.str(), nb_nodes, spatial_dimension, 0.)); } increment_flag = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep() { AKANTU_DEBUG_IN(); Real min_dt = getStableTimeStep(_not_ghost); /// reduction min over all processors StaticCommunicator::getStaticCommunicator().allReduce(&min_dt, 1, _so_min); AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep(const GhostType & ghost_type) { AKANTU_DEBUG_IN(); Material ** mat_val = &(materials.at(0)); Real min_dt = std::numeric_limits<Real>::max(); updateCurrentPosition(); Element elem; elem.ghost_type = ghost_type; elem.kind = _ek_regular; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator end = mesh.lastType(spatial_dimension, ghost_type); for(; it != end; ++it) { elem.type = *it; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(*it); UInt nb_element = mesh.getNbElement(*it); Array<UInt>::const_scalar_iterator mat_indexes = material_index(*it, ghost_type).begin(); Array<UInt>::const_scalar_iterator mat_loc_num = material_local_numbering(*it, ghost_type).begin(); Array<Real> X(0, nb_nodes_per_element*spatial_dimension); FEEngine::extractNodalToElementField(mesh, *current_position, X, *it, _not_ghost); Array<Real>::matrix_iterator X_el = X.begin(spatial_dimension, nb_nodes_per_element); for (UInt el = 0; el < nb_element; ++el, ++X_el, ++mat_indexes, ++mat_loc_num) { elem.element = *mat_loc_num; Real el_h = getFEEngine().getElementInradius(*X_el, *it); Real el_c = mat_val[*mat_indexes]->getCelerity(elem); Real el_dt = el_h / el_c; min_dt = std::min(min_dt, el_dt); } } AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getPotentialEnergy() { AKANTU_DEBUG_IN(); Real energy = 0.; /// call update residual on each local elements std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { energy += (*mat_it)->getPotentialEnergy(); } /// reduction sum over all processors StaticCommunicator::getStaticCommunicator().allReduce(&energy, 1, _so_sum); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getKineticEnergy() { AKANTU_DEBUG_IN(); if (!mass && !mass_matrix) AKANTU_DEBUG_ERROR("No function called to assemble the mass matrix."); Real ekin = 0.; UInt nb_nodes = mesh.getNbNodes(); Real * vel_val = velocity->storage(); Real * mass_val = mass->storage(); for (UInt n = 0; n < nb_nodes; ++n) { Real mv2 = 0; bool is_local_node = mesh.isLocalOrMasterNode(n); bool is_not_pbc_slave_node = !isPBCSlaveNode(n); bool count_node = is_local_node && is_not_pbc_slave_node; for (UInt i = 0; i < spatial_dimension; ++i) { if (count_node) mv2 += *vel_val * *vel_val * *mass_val; vel_val++; mass_val++; } ekin += mv2; } StaticCommunicator::getStaticCommunicator().allReduce(&ekin, 1, _so_sum); AKANTU_DEBUG_OUT(); return ekin * .5; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getKineticEnergy(const ElementType & type, UInt index) { AKANTU_DEBUG_IN(); UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(type); Array<Real> vel_on_quad(nb_quadrature_points, spatial_dimension); Array<UInt> filter_element(1, 1, index); getFEEngine().interpolateOnQuadraturePoints(*velocity, vel_on_quad, spatial_dimension, type, _not_ghost, filter_element); Array<Real>::vector_iterator vit = vel_on_quad.begin(spatial_dimension); Array<Real>::vector_iterator vend = vel_on_quad.end(spatial_dimension); Vector<Real> rho_v2(nb_quadrature_points); Real rho = materials[material_index(type)(index)]->getRho(); for (UInt q = 0; vit != vend; ++vit, ++q) { rho_v2(q) = rho * vit->dot(*vit); } AKANTU_DEBUG_OUT(); return .5*getFEEngine().integrate(rho_v2, type, index); } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getExternalWork() { AKANTU_DEBUG_IN(); Real * velo = velocity->storage(); Real * forc = force->storage(); Real * resi = residual->storage(); bool * boun = blocked_dofs->storage(); Real work = 0.; UInt nb_nodes = mesh.getNbNodes(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); bool is_not_pbc_slave_node = !isPBCSlaveNode(n); bool count_node = is_local_node && is_not_pbc_slave_node; for (UInt i = 0; i < spatial_dimension; ++i) { if (count_node) { if(*boun) work -= *resi * *velo * time_step; else work += *forc * *velo * time_step; } ++velo; ++forc; ++resi; ++boun; } } StaticCommunicator::getStaticCommunicator().allReduce(&work, 1, _so_sum); AKANTU_DEBUG_OUT(); return work; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getEnergy(const std::string & energy_id) { AKANTU_DEBUG_IN(); if (energy_id == "kinetic") { return getKineticEnergy(); } else if (energy_id == "external work"){ return getExternalWork(); } Real energy = 0.; std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { energy += (*mat_it)->getEnergy(energy_id); } /// reduction sum over all processors StaticCommunicator::getStaticCommunicator().allReduce(&energy, 1, _so_sum); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getEnergy(const std::string & energy_id, const ElementType & type, UInt index){ AKANTU_DEBUG_IN(); if (energy_id == "kinetic") { return getKineticEnergy(type, index); } std::vector<Material *>::iterator mat_it; UInt mat_index = this->material_index(type, _not_ghost)(index); UInt mat_loc_num = this->material_local_numbering(type, _not_ghost)(index); Real energy = this->materials[mat_index]->getEnergy(energy_id, type, mat_loc_num); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onElementsAdded(const Array<Element> & element_list, const NewElementsEvent & event) { AKANTU_DEBUG_IN(); this->getFEEngine().initShapeFunctions(_not_ghost); this->getFEEngine().initShapeFunctions(_ghost); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; Mesh::type_iterator it = this->mesh.firstType(spatial_dimension, gt, _ek_not_defined); Mesh::type_iterator end = this->mesh.lastType(spatial_dimension, gt, _ek_not_defined); for(; it != end; ++it) { UInt nb_element = this->mesh.getNbElement(*it, gt); if(!material_index.exists(*it, gt)) { this->material_index .alloc(nb_element, 1, *it, gt); this->material_local_numbering.alloc(nb_element, 1, *it, gt); } else { this->material_index (*it, gt).resize(nb_element); this->material_local_numbering(*it, gt).resize(nb_element); } } } Array<Element>::const_iterator<Element> it = element_list.begin(); Array<Element>::const_iterator<Element> end = element_list.end(); ElementTypeMapArray<UInt> filter("new_element_filter", this->getID()); for (UInt el = 0; it != end; ++it, ++el) { const Element & elem = *it; if(!filter.exists(elem.type, elem.ghost_type)) filter.alloc(0, 1, elem.type, elem.ghost_type); filter(elem.type, elem.ghost_type).push_back(elem.element); } this->assignMaterialToElements(&filter); std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->onElementsAdded(element_list, event); } if(method == _explicit_lumped_mass) this->assembleMassLumped(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onElementsRemoved(__attribute__((unused)) const Array<Element> & element_list, const ElementTypeMapArray<UInt> & new_numbering, const RemovedElementsEvent & event) { this->getFEEngine().initShapeFunctions(_not_ghost); this->getFEEngine().initShapeFunctions(_ghost); std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->onElementsRemoved(element_list, new_numbering, event); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onNodesAdded(const Array<UInt> & nodes_list, __attribute__((unused)) const NewNodesEvent & event) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); if(displacement) displacement->resize(nb_nodes); if(mass ) mass ->resize(nb_nodes); if(velocity ) velocity ->resize(nb_nodes); if(acceleration) acceleration->resize(nb_nodes); if(force ) force ->resize(nb_nodes); if(residual ) residual ->resize(nb_nodes); if(blocked_dofs) blocked_dofs->resize(nb_nodes); if(previous_displacement) previous_displacement->resize(nb_nodes); if(increment_acceleration) increment_acceleration->resize(nb_nodes); if(increment) increment->resize(nb_nodes); if(current_position) current_position->resize(nb_nodes); delete dof_synchronizer; dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension); dof_synchronizer->initLocalDOFEquationNumbers(); dof_synchronizer->initGlobalDOFEquationNumbers(); std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { (*mat_it)->onNodesAdded(nodes_list, event); } if (method != _explicit_lumped_mass) { this->initSolver(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onNodesRemoved(__attribute__((unused)) const Array<UInt> & element_list, const Array<UInt> & new_numbering, __attribute__((unused)) const RemovedNodesEvent & event) { if(displacement) mesh.removeNodesFromArray(*displacement, new_numbering); if(mass ) mesh.removeNodesFromArray(*mass , new_numbering); if(velocity ) mesh.removeNodesFromArray(*velocity , new_numbering); if(acceleration) mesh.removeNodesFromArray(*acceleration, new_numbering); if(force ) mesh.removeNodesFromArray(*force , new_numbering); if(residual ) mesh.removeNodesFromArray(*residual , new_numbering); if(blocked_dofs) mesh.removeNodesFromArray(*blocked_dofs, new_numbering); if(increment_acceleration) mesh.removeNodesFromArray(*increment_acceleration, new_numbering); if(increment) mesh.removeNodesFromArray(*increment , new_numbering); delete dof_synchronizer; dof_synchronizer = new DOFSynchronizer(mesh, spatial_dimension); dof_synchronizer->initLocalDOFEquationNumbers(); dof_synchronizer->initGlobalDOFEquationNumbers(); if (method != _explicit_lumped_mass) { this->initSolver(); } } /* -------------------------------------------------------------------------- */ bool SolidMechanicsModel::isInternal(const std::string & field_name, const ElementKind & element_kind){ bool is_internal = false; /// check if at least one material contains field_id as an internal for (UInt m = 0; m < materials.size() && !is_internal; ++m) { is_internal |= materials[m]->isInternal(field_name, element_kind); } return is_internal; } /* -------------------------------------------------------------------------- */ ElementTypeMap<UInt> SolidMechanicsModel::getInternalDataPerElem(const std::string & field_name, const ElementKind & element_kind){ if (!(this->isInternal(field_name,element_kind))) AKANTU_EXCEPTION("unknown internal " << field_name); for (UInt m = 0; m < materials.size() ; ++m) { if (materials[m]->isInternal(field_name, element_kind)) return materials[m]->getInternalDataPerElem(field_name,element_kind); } return ElementTypeMap<UInt>(); } /* -------------------------------------------------------------------------- */ ElementTypeMapArray<Real> & SolidMechanicsModel::flattenInternal(const std::string & field_name, const ElementKind & kind, const GhostType ghost_type){ std::pair<std::string,ElementKind> key(field_name,kind); if (this->registered_internals.count(key) == 0){ this->registered_internals[key] = new ElementTypeMapArray<Real>(field_name,this->id); } ElementTypeMapArray<Real> * internal_flat = this->registered_internals[key]; for (UInt m = 0; m < materials.size(); ++m) materials[m]->flattenInternal(field_name,*internal_flat,ghost_type,kind); return *internal_flat; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::flattenAllRegisteredInternals(const ElementKind & kind){ std::map<std::pair<std::string,ElementKind>,ElementTypeMapArray<Real> *> ::iterator it = this->registered_internals.begin(); std::map<std::pair<std::string,ElementKind>,ElementTypeMapArray<Real> *>::iterator end = this->registered_internals.end(); while (it != end){ if (kind == it->first.second) this->flattenInternal(it->first.first,kind); ++it; } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onDump(){ this->flattenAllRegisteredInternals(_ek_regular); } /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER dumper::Field * SolidMechanicsModel ::createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const ElementKind & kind){ dumper::Field * field = NULL; if(field_name == "partitions") field = mesh.createElementalField<UInt, dumper::ElementPartitionField>(mesh.getConnectivities(),group_name,this->spatial_dimension,kind); else if(field_name == "material_index") field = mesh.createElementalField<UInt, Vector, dumper::ElementalField >(material_index,group_name,this->spatial_dimension,kind); else { // this copy of field_name is used to compute derivated data such as // strain and von mises stress that are based on grad_u and stress std::string field_name_copy(field_name); if (field_name == "strain" || field_name == "Green strain" || field_name == "principal strain" || field_name == "principal Green strain") field_name_copy = "grad_u"; else if (field_name == "Von Mises stress") field_name_copy = "stress"; bool is_internal = this->isInternal(field_name_copy,kind); if (is_internal) { ElementTypeMap<UInt> nb_data_per_elem = this->getInternalDataPerElem(field_name_copy,kind); ElementTypeMapArray<Real> & internal_flat = this->flattenInternal(field_name_copy,kind); field = mesh.createElementalField<Real, dumper::InternalMaterialField>(internal_flat, group_name, this->spatial_dimension,kind,nb_data_per_elem); if (field_name == "strain"){ dumper::ComputeStrain<false> * foo = new dumper::ComputeStrain<false>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } else if (field_name == "Von Mises stress") { dumper::ComputeVonMisesStress * foo = new dumper::ComputeVonMisesStress(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } else if (field_name == "Green strain") { dumper::ComputeStrain<true> * foo = new dumper::ComputeStrain<true>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } else if (field_name == "principal strain") { dumper::ComputePrincipalStrain<false> * foo = new dumper::ComputePrincipalStrain<false>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } else if (field_name == "principal Green strain") { dumper::ComputePrincipalStrain<true> * foo = new dumper::ComputePrincipalStrain<true>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } //treat the paddings if (padding_flag){ if (field_name == "stress"){ if (this->spatial_dimension == 2) { dumper::StressPadder<2> * foo = new dumper::StressPadder<2>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } } else if (field_name == "strain" || field_name == "Green strain"){ if (this->spatial_dimension == 2) { dumper::StrainPadder<2> * foo = new dumper::StrainPadder<2>(*this); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } } } // homogenize the field dumper::ComputeFunctorInterface * foo = dumper::HomogenizerProxy::createHomogenizer(*field); field = dumper::FieldComputeProxy::createFieldCompute(field,*foo); } } return field; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { std::map<std::string,Array<Real>* > real_nodal_fields; real_nodal_fields["displacement" ] = displacement; real_nodal_fields["mass" ] = mass; real_nodal_fields["velocity" ] = velocity; real_nodal_fields["acceleration" ] = acceleration; real_nodal_fields["force" ] = force; real_nodal_fields["residual" ] = residual; real_nodal_fields["increment" ] = increment; dumper::Field * field = NULL; if (padding_flag) field = mesh.createNodalField(real_nodal_fields[field_name],group_name, 3); else field = mesh.createNodalField(real_nodal_fields[field_name],group_name); return field; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag) { std::map<std::string,Array<bool>* > uint_nodal_fields; uint_nodal_fields["blocked_dofs" ] = blocked_dofs; dumper::Field * field = NULL; field = mesh.createNodalField(uint_nodal_fields[field_name],group_name); return field; } /* -------------------------------------------------------------------------- */ #else /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel ::createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const ElementKind & kind){ return NULL; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { return NULL; } /* -------------------------------------------------------------------------- */ dumper::Field * SolidMechanicsModel::createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag) { return NULL; } #endif /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); synch_registry->synchronize(_gst_for_dump); mesh.dump(dumper_name); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name, UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); synch_registry->synchronize(_gst_for_dump); mesh.dump(dumper_name, step); } /* ------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(const std::string & dumper_name, Real time, UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); synch_registry->synchronize(_gst_for_dump); mesh.dump(dumper_name, time, step); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump() { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(step); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::dump(Real time, UInt step) { this->onDump(); EventManager::sendEvent(SolidMechanicsModelEvent::BeforeDumpEvent()); mesh.dump(time, step); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::computeCauchyStresses() { AKANTU_DEBUG_IN(); // call compute stiffness matrix on each local elements std::vector<Material *>::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { Material & mat = **mat_it; if(mat.isFiniteDeformation()) mat.computeAllCauchyStresses(_not_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::saveStressAndStrainBeforeDamage() { EventManager::sendEvent(SolidMechanicsModelEvent::BeginningOfDamageIterationEvent()); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateEnergiesAfterDamage() { EventManager::sendEvent(SolidMechanicsModelEvent::AfterDamageEvent()); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "Solid Mechanics Model [" << std::endl; stream << space << " + id : " << id << std::endl; stream << space << " + spatial dimension : " << spatial_dimension << std::endl; stream << space << " + fem [" << std::endl; getFEEngine().printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + nodals information [" << std::endl; displacement->printself(stream, indent + 2); mass ->printself(stream, indent + 2); velocity ->printself(stream, indent + 2); acceleration->printself(stream, indent + 2); force ->printself(stream, indent + 2); residual ->printself(stream, indent + 2); blocked_dofs->printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + material information [" << std::endl; material_index.printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + materials [" << std::endl; std::vector<Material *>::const_iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { const Material & mat = *(*mat_it); mat.printself(stream, indent + 1); } stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ __END_AKANTU__ diff --git a/src/model/structural_mechanics/structural_mechanics_model.cc b/src/model/structural_mechanics/structural_mechanics_model.cc index e4a0111be..2c41ab2ac 100644 --- a/src/model/structural_mechanics/structural_mechanics_model.cc +++ b/src/model/structural_mechanics/structural_mechanics_model.cc @@ -1,1147 +1,1147 @@ /** * @file structural_mechanics_model.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Damien Spielmann <damien.spielmann@epfl.ch> * @author Sébastien Hartmann <sebastien.hartmann@epfl.ch> * @author Fabian Barras <fabian.barras@epfl.ch> * * @date creation: Fri Jul 15 2011 * @date last modification: Mon Sep 15 2014 * * @brief Model implementation for StucturalMechanics 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 <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "structural_mechanics_model.hh" #include "group_manager_inline_impl.cc" #include "dumpable_inline_impl.hh" #include "aka_math.hh" #include "integration_scheme_2nd_order.hh" #include "static_communicator.hh" #include "sparse_matrix.hh" #include "solver.hh" #ifdef AKANTU_USE_MUMPS #include "solver_mumps.hh" #endif #ifdef AKANTU_USE_IOHELPER # include "dumper_paraview.hh" # include "dumper_elemental_field.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ const StructuralMechanicsModelOptions default_structural_mechanics_model_options(_static); /* -------------------------------------------------------------------------- */ StructuralMechanicsModel::StructuralMechanicsModel(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) : Model(mesh, dim, id, memory_id), time_step(NAN), f_m2a(1.0), stress("stress", id, memory_id), element_material("element_material", id, memory_id), set_ID("beam sets", id, memory_id), stiffness_matrix(NULL), mass_matrix(NULL), velocity_damping_matrix(NULL), jacobian_matrix(NULL), solver(NULL), rotation_matrix("rotation_matices", id, memory_id), increment_flag(false), integrator(NULL) { AKANTU_DEBUG_IN(); registerFEEngineObject<MyFEEngineType>("StructuralMechanicsFEEngine", mesh, spatial_dimension); this->displacement_rotation = NULL; this->mass = NULL; this->velocity = NULL; this->acceleration = NULL; this->force_momentum = NULL; this->residual = NULL; this->blocked_dofs = NULL; this->increment = NULL; this->previous_displacement = NULL; if(spatial_dimension == 2) nb_degree_of_freedom = 3; else if (spatial_dimension == 3) nb_degree_of_freedom = 6; else { AKANTU_DEBUG_TO_IMPLEMENT(); } this->mesh.registerDumper<DumperParaview>("paraview_all", id, true); this->mesh.addDumpMesh(mesh, spatial_dimension, _not_ghost, _ek_structural); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ StructuralMechanicsModel::~StructuralMechanicsModel() { AKANTU_DEBUG_IN(); delete integrator; delete solver; delete stiffness_matrix; delete jacobian_matrix; delete mass_matrix; delete velocity_damping_matrix; AKANTU_DEBUG_OUT(); } void StructuralMechanicsModel::setTimeStep(Real time_step) { this->time_step = time_step; #if defined(AKANTU_USE_IOHELPER) this->mesh.getDumper().setTimeStep(time_step); #endif } /* -------------------------------------------------------------------------- */ /* Initialisation */ /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initFull(const ModelOptions & options) { const StructuralMechanicsModelOptions & stmm_options = dynamic_cast<const StructuralMechanicsModelOptions &>(options); method = stmm_options.analysis_method; initModel(); initArrays(); displacement_rotation->clear(); velocity ->clear(); acceleration ->clear(); force_momentum ->clear(); residual ->clear(); blocked_dofs ->clear(); increment ->clear(); Mesh::type_iterator it = getFEEngine().getMesh().firstType(spatial_dimension, _not_ghost, _ek_structural); Mesh::type_iterator end = getFEEngine().getMesh().lastType(spatial_dimension, _not_ghost, _ek_structural); for (; it != end; ++it) { computeRotationMatrix(*it); } switch(method) { case _implicit_dynamic: initImplicit(); break; case _static: initSolver(); break; default: AKANTU_EXCEPTION("analysis method not recognised by StructuralMechanicsModel"); break; } } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initArrays() { AKANTU_DEBUG_IN(); UInt nb_nodes = getFEEngine().getMesh().getNbNodes(); std::stringstream sstr_disp; sstr_disp << id << ":displacement"; std::stringstream sstr_velo; sstr_velo << id << ":velocity"; std::stringstream sstr_acce; sstr_acce << id << ":acceleration"; std::stringstream sstr_forc; sstr_forc << id << ":force"; std::stringstream sstr_resi; sstr_resi << id << ":residual"; std::stringstream sstr_boun; sstr_boun << id << ":blocked_dofs"; std::stringstream sstr_incr; sstr_incr << id << ":increment"; displacement_rotation = &(alloc<Real>(sstr_disp.str(), nb_nodes, nb_degree_of_freedom, REAL_INIT_VALUE)); velocity = &(alloc<Real>(sstr_velo.str(), nb_nodes, nb_degree_of_freedom, REAL_INIT_VALUE)); acceleration = &(alloc<Real>(sstr_acce.str(), nb_nodes, nb_degree_of_freedom, REAL_INIT_VALUE)); force_momentum = &(alloc<Real>(sstr_forc.str(), nb_nodes, nb_degree_of_freedom, REAL_INIT_VALUE)); residual = &(alloc<Real>(sstr_resi.str(), nb_nodes, nb_degree_of_freedom, REAL_INIT_VALUE)); blocked_dofs = &(alloc<bool>(sstr_boun.str(), nb_nodes, nb_degree_of_freedom, false)); increment = &(alloc<Real>(sstr_incr.str(), nb_nodes, nb_degree_of_freedom, REAL_INIT_VALUE)); Mesh::type_iterator it = getFEEngine().getMesh().firstType(spatial_dimension, _not_ghost, _ek_structural); Mesh::type_iterator end = getFEEngine().getMesh().lastType(spatial_dimension, _not_ghost, _ek_structural); for (; it != end; ++it) { UInt nb_element = getFEEngine().getMesh().getNbElement(*it); UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(*it); element_material.alloc(nb_element, 1, *it, _not_ghost); set_ID.alloc(nb_element, 1, *it, _not_ghost); UInt size = getTangentStiffnessVoigtSize(*it); stress.alloc(nb_element * nb_quadrature_points, size , *it, _not_ghost); } dof_synchronizer = new DOFSynchronizer(getFEEngine().getMesh(), nb_degree_of_freedom); dof_synchronizer->initLocalDOFEquationNumbers(); dof_synchronizer->initGlobalDOFEquationNumbers(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initModel() { getFEEngine().initShapeFunctions(_not_ghost); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initSolver(__attribute__((unused)) SolverOptions & options) { AKANTU_DEBUG_IN(); const Mesh & mesh = getFEEngine().getMesh(); #if !defined(AKANTU_USE_MUMPS) // or other solver in the future \todo add AKANTU_HAS_SOLVER in CMake AKANTU_DEBUG_ERROR("You should at least activate one solver."); #else UInt nb_global_node = mesh.getNbGlobalNodes(); std::stringstream sstr; sstr << id << ":jacobian_matrix"; jacobian_matrix = new SparseMatrix(nb_global_node * nb_degree_of_freedom, _symmetric, sstr.str(), memory_id); jacobian_matrix->buildProfile(mesh, *dof_synchronizer, nb_degree_of_freedom); std::stringstream sstr_sti; sstr_sti << id << ":stiffness_matrix"; stiffness_matrix = new SparseMatrix(*jacobian_matrix, sstr_sti.str(), memory_id); #ifdef AKANTU_USE_MUMPS std::stringstream sstr_solv; sstr_solv << id << ":solver"; solver = new SolverMumps(*jacobian_matrix, sstr_solv.str()); dof_synchronizer->initScatterGatherCommunicationScheme(); #else AKANTU_DEBUG_ERROR("You should at least activate one solver."); #endif //AKANTU_USE_MUMPS solver->initialize(options); #endif //AKANTU_HAS_SOLVER AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::initImplicit(bool dynamic, SolverOptions & solver_options) { AKANTU_DEBUG_IN(); if (!increment) setIncrementFlagOn(); initSolver(solver_options); if(integrator) delete integrator; integrator = new TrapezoidalRule2(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ UInt StructuralMechanicsModel::getTangentStiffnessVoigtSize(const ElementType & type) { UInt size; #define GET_TANGENT_STIFFNESS_VOIGT_SIZE(type) \ size = getTangentStiffnessVoigtSize<type>(); AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(GET_TANGENT_STIFFNESS_VOIGT_SIZE); #undef GET_TANGENT_STIFFNESS_VOIGT_SIZE return size; } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); stiffness_matrix->clear(); Mesh::type_iterator it = getFEEngine().getMesh().firstType(spatial_dimension, _not_ghost, _ek_structural); Mesh::type_iterator end = getFEEngine().getMesh().lastType(spatial_dimension, _not_ghost, _ek_structural); for (; it != end; ++it) { ElementType type = *it; #define ASSEMBLE_STIFFNESS_MATRIX(type) \ assembleStiffnessMatrix<type>(); AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(ASSEMBLE_STIFFNESS_MATRIX); #undef ASSEMBLE_STIFFNESS_MATRIX } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::computeRotationMatrix<_bernoulli_beam_2>(Array<Real> & rotations){ ElementType type = _bernoulli_beam_2; Mesh & mesh = getFEEngine().getMesh(); UInt nb_element = mesh.getNbElement(type); Array<UInt>::iterator< Vector<UInt> > connec_it = mesh.getConnectivity(type).begin(2); Array<Real>::vector_iterator nodes_it = mesh.getNodes().begin(spatial_dimension); Array<Real>::matrix_iterator R_it = rotations.begin(nb_degree_of_freedom, nb_degree_of_freedom); for (UInt e = 0; e < nb_element; ++e, ++R_it, ++connec_it) { Matrix<Real> & R = *R_it; Vector<UInt> & connec = *connec_it; Vector<Real> x2; x2 = nodes_it[connec(1)]; // X2 Vector<Real> x1; x1 = nodes_it[connec(0)]; // X1 Real le = x1.distance(x2); Real c = (x2(0) - x1(0)) / le; Real s = (x2(1) - x1(1)) / le; /// Definition of the rotation matrix R(0,0) = c; R(0,1) = s; R(0,2) = 0.; R(1,0) = -s; R(1,1) = c; R(1,2) = 0.; R(2,0) = 0.; R(2,1) = 0.; R(2,2) = 1.; } } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::computeRotationMatrix<_bernoulli_beam_3>(Array<Real> & rotations){ ElementType type = _bernoulli_beam_3; Mesh & mesh = getFEEngine().getMesh(); UInt nb_element = mesh.getNbElement(type); Array<Real>::vector_iterator n_it = mesh.getNormals(type).begin(spatial_dimension); Array<UInt>::iterator< Vector<UInt> > connec_it = mesh.getConnectivity(type).begin(2); Array<Real>::vector_iterator nodes_it = mesh.getNodes().begin(spatial_dimension); Matrix<Real> Pe (spatial_dimension, spatial_dimension); Matrix<Real> Pg (spatial_dimension, spatial_dimension); Matrix<Real> inv_Pg(spatial_dimension, spatial_dimension); Vector<Real> x_n(spatial_dimension); // x vect n Array<Real>::matrix_iterator R_it = rotations.begin(nb_degree_of_freedom, nb_degree_of_freedom); for (UInt e=0 ; e < nb_element; ++e, ++n_it, ++connec_it, ++R_it) { Vector<Real> & n = *n_it; Matrix<Real> & R = *R_it; Vector<UInt> & connec = *connec_it; Vector<Real> x; x = nodes_it[connec(1)]; // X2 Vector<Real> y; y = nodes_it[connec(0)]; // X1 Real l = x.distance(y); x -= y; // X2 - X1 x_n.crossProduct(x, n); Pe.eye(); Pe(0, 0) *= l; Pe(1, 1) *= -l; Pg(0,0) = x(0); Pg(0,1) = x_n(0); Pg(0,2) = n(0); Pg(1,0) = x(1); Pg(1,1) = x_n(1); Pg(1,2) = n(1); Pg(2,0) = x(2); Pg(2,1) = x_n(2); Pg(2,2) = n(2); inv_Pg.inverse(Pg); Pe *= inv_Pg; for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < spatial_dimension; ++j) { R(i, j) = Pe(i, j); R(i + spatial_dimension,j + spatial_dimension) = Pe(i, j); } } } } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::computeRotationMatrix<_kirchhoff_shell>(Array<Real> & rotations){ ElementType type = _kirchhoff_shell; Mesh & mesh = getFEEngine().getMesh(); UInt nb_element = mesh.getNbElement(type); Array<UInt>::iterator< Vector<UInt> > connec_it = mesh.getConnectivity(type).begin(3); Array<Real>::vector_iterator nodes_it = mesh.getNodes().begin(spatial_dimension); Matrix<Real> Pe (spatial_dimension, spatial_dimension); Matrix<Real> Pg (spatial_dimension, spatial_dimension); Matrix<Real> inv_Pg(spatial_dimension, spatial_dimension); Array<Real>::matrix_iterator R_it = rotations.begin(nb_degree_of_freedom, nb_degree_of_freedom); for (UInt e=0 ; e < nb_element; ++e, ++connec_it, ++R_it) { Pe.eye(); Matrix<Real> & R = *R_it; Vector<UInt> & connec = *connec_it; Vector<Real> x2; x2 = nodes_it[connec(1)]; // X2 Vector<Real> x1; x1 = nodes_it[connec(0)]; // X1 Vector<Real> x3; x3 = nodes_it[connec(2)]; // X3 Vector<Real> Pg_col_1=x2-x1; Vector<Real> Pg_col_2 = x3-x1; Vector<Real> Pg_col_3(spatial_dimension); Pg_col_3.crossProduct(Pg_col_1, Pg_col_2); for (UInt i = 0; i <spatial_dimension; ++i) { Pg(i,0) = Pg_col_1(i); Pg(i,1) = Pg_col_2(i); Pg(i,2) = Pg_col_3(i); } inv_Pg.inverse(Pg); // Pe *= inv_Pg; Pe.eye(); for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < spatial_dimension; ++j) { R(i, j) = Pe(i, j); R(i + spatial_dimension,j + spatial_dimension) = Pe(i, j); } } } } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::computeRotationMatrix(const ElementType & type) { Mesh & mesh = getFEEngine().getMesh(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_element = mesh.getNbElement(type); if(!rotation_matrix.exists(type)) { rotation_matrix.alloc(nb_element, nb_degree_of_freedom*nb_nodes_per_element * nb_degree_of_freedom*nb_nodes_per_element, type); } else { rotation_matrix(type).resize(nb_element); } rotation_matrix(type).clear(); Array<Real>rotations(nb_element, nb_degree_of_freedom * nb_degree_of_freedom); rotations.clear(); #define COMPUTE_ROTATION_MATRIX(type) \ computeRotationMatrix<type>(rotations); AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(COMPUTE_ROTATION_MATRIX); #undef COMPUTE_ROTATION_MATRIX Array<Real>::matrix_iterator R_it = rotations.begin(nb_degree_of_freedom, nb_degree_of_freedom); Array<Real>::matrix_iterator T_it = rotation_matrix(type).begin(nb_degree_of_freedom*nb_nodes_per_element, nb_degree_of_freedom*nb_nodes_per_element); for (UInt el = 0; el < nb_element; ++el, ++R_it, ++T_it) { Matrix<Real> & T = *T_it; Matrix<Real> & R = *R_it; T.clear(); for (UInt k = 0; k < nb_nodes_per_element; ++k){ for (UInt i = 0; i < nb_degree_of_freedom; ++i) for (UInt j = 0; j < nb_degree_of_freedom; ++j) T(k*nb_degree_of_freedom + i, k*nb_degree_of_freedom + j) = R(i, j); } } } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::computeStresses() { AKANTU_DEBUG_IN(); Mesh::type_iterator it = getFEEngine().getMesh().firstType(spatial_dimension, _not_ghost, _ek_structural); Mesh::type_iterator end = getFEEngine().getMesh().lastType(spatial_dimension, _not_ghost, _ek_structural); for (; it != end; ++it) { ElementType type = *it; #define COMPUTE_STRESS_ON_QUAD(type) \ computeStressOnQuad<type>(); AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(COMPUTE_STRESS_ON_QUAD); #undef COMPUTE_STRESS_ON_QUAD } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::updateResidual() { AKANTU_DEBUG_IN(); residual->copy(*force_momentum); Array<Real> ku(*displacement_rotation, true); ku *= *stiffness_matrix; *residual -= ku; this->updateResidualInternal(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::implicitPred() { AKANTU_DEBUG_IN(); if(previous_displacement) previous_displacement->copy(*displacement_rotation); if(method == _implicit_dynamic) integrator->integrationSchemePred(time_step, *displacement_rotation, *velocity, *acceleration, *blocked_dofs); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::implicitCorr() { AKANTU_DEBUG_IN(); Real * incr_val = increment->storage(); bool * boun_val = blocked_dofs->storage(); UInt nb_nodes = displacement_rotation->getSize(); for (UInt j = 0; j < nb_nodes * nb_degree_of_freedom; ++j, ++incr_val, ++boun_val){ *incr_val *= (1. - *boun_val); } if(method == _implicit_dynamic) { integrator->integrationSchemeCorrDispl(time_step, *displacement_rotation, *velocity, *acceleration, *blocked_dofs, *increment); } else { Real * disp_val = displacement_rotation->storage(); incr_val = increment->storage(); - for (UInt j = 0; j < nb_nodes *nb_degree_of_freedom; ++j, ++disp_val){ + for (UInt j = 0; j < nb_nodes *nb_degree_of_freedom; ++j, ++disp_val, ++incr_val){ *disp_val += *incr_val; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::updateResidualInternal() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Update the residual"); // f = f_ext - f_int - Ma - Cv = r - Ma - Cv; if(method != _static) { // f -= Ma if(mass_matrix) { // if full mass_matrix Array<Real> * Ma = new Array<Real>(*acceleration, true, "Ma"); *Ma *= *mass_matrix; /// \todo check unit conversion for implicit dynamics // *Ma /= f_m2a *residual -= *Ma; delete Ma; } else if (mass) { // else lumped mass UInt nb_nodes = acceleration->getSize(); UInt nb_degree_of_freedom = acceleration->getNbComponent(); Real * mass_val = mass->storage(); Real * accel_val = acceleration->storage(); Real * res_val = residual->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes * nb_degree_of_freedom; ++n) { if(!(*blocked_dofs_val)) { *res_val -= *accel_val * *mass_val /f_m2a; } blocked_dofs_val++; res_val++; mass_val++; accel_val++; } } else { AKANTU_DEBUG_ERROR("No function called to assemble the mass matrix."); } // f -= Cv if(velocity_damping_matrix) { Array<Real> * Cv = new Array<Real>(*velocity); *Cv *= *velocity_damping_matrix; *residual -= *Cv; delete Cv; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::setIncrementFlagOn() { AKANTU_DEBUG_IN(); if(!increment) { UInt nb_nodes = mesh.getNbNodes(); std::stringstream sstr_inc; sstr_inc << id << ":increment"; increment = &(alloc<Real>(sstr_inc.str(), nb_nodes, spatial_dimension, 0.)); } increment_flag = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void StructuralMechanicsModel::solve() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Solving an implicit step."); UInt nb_nodes = displacement_rotation->getSize(); /// todo residual = force - Kxr * d_bloq jacobian_matrix->copyContent(*stiffness_matrix); jacobian_matrix->applyBoundary(*blocked_dofs); jacobian_matrix->saveMatrix("Kbound.mtx"); increment->clear(); solver->setRHS(*residual); solver->factorize(); solver->solve(*increment); Real * increment_val = increment->storage(); Real * displacement_val = displacement_rotation->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes * nb_degree_of_freedom; ++n) { if(!(*blocked_dofs_val)) { *displacement_val += *increment_val; } else { *increment_val = 0.0; } displacement_val++; blocked_dofs_val++; increment_val++; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template<> bool StructuralMechanicsModel::testConvergence<_scc_increment>(Real tolerance, Real & error){ AKANTU_DEBUG_IN(); UInt nb_nodes = displacement_rotation->getSize(); UInt nb_degree_of_freedom = displacement_rotation->getNbComponent(); error = 0; Real norm[2] = {0., 0.}; Real * increment_val = increment->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); Real * displacement_val = displacement_rotation->storage(); for (UInt n = 0; n < nb_nodes; ++n) { for (UInt d = 0; d < nb_degree_of_freedom; ++d) { if(!(*blocked_dofs_val)) { norm[0] += *increment_val * *increment_val; norm[1] += *displacement_val * *displacement_val; } blocked_dofs_val++; increment_val++; displacement_val++; } } StaticCommunicator::getStaticCommunicator().allReduce(norm, 2, _so_sum); norm[0] = sqrt(norm[0]); norm[1] = sqrt(norm[1]); AKANTU_DEBUG_ASSERT(!Math::isnan(norm[0]), "Something went wrong in the solve phase"); AKANTU_DEBUG_OUT(); if(norm[1] > Math::getTolerance()) error = norm[0] / norm[1]; else error = norm[0]; //In case the total displacement is zero! return (error < tolerance); } /* -------------------------------------------------------------------------- */ template<> bool StructuralMechanicsModel::testConvergence<_scc_residual>(Real tolerance, Real & norm) { AKANTU_DEBUG_IN(); UInt nb_nodes = residual->getSize(); norm = 0; Real * residual_val = residual->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); if(is_local_node) { - for (UInt d = 0; d < spatial_dimension; ++d) { + for (UInt d = 0; d < nb_degree_of_freedom; ++d) { if(!(*blocked_dofs_val)) { norm += *residual_val * *residual_val; } blocked_dofs_val++; residual_val++; } } else { blocked_dofs_val += spatial_dimension; residual_val += spatial_dimension; } } StaticCommunicator::getStaticCommunicator().allReduce(&norm, 1, _so_sum); norm = sqrt(norm); AKANTU_DEBUG_ASSERT(!Math::isnan(norm), "Something goes wrong in the solve phase"); AKANTU_DEBUG_OUT(); return (norm < tolerance); } /* -------------------------------------------------------------------------- */ bool StructuralMechanicsModel::testConvergenceIncrement(Real tolerance) { Real error; bool tmp = testConvergenceIncrement(tolerance, error); AKANTU_DEBUG_INFO("Norm of increment : " << error); return tmp; } /* -------------------------------------------------------------------------- */ bool StructuralMechanicsModel::testConvergenceIncrement(Real tolerance, Real & error) { AKANTU_DEBUG_IN(); Mesh & mesh= getFEEngine().getMesh(); UInt nb_nodes = displacement_rotation->getSize(); UInt nb_degree_of_freedom = displacement_rotation->getNbComponent(); Real norm = 0; Real * increment_val = increment->storage(); bool * blocked_dofs_val = blocked_dofs->storage(); for (UInt n = 0; n < nb_nodes; ++n) { bool is_local_node = mesh.isLocalOrMasterNode(n); for (UInt d = 0; d < nb_degree_of_freedom; ++d) { if(!(*blocked_dofs_val) && is_local_node) { norm += *increment_val * *increment_val; } blocked_dofs_val++; increment_val++; } } StaticCommunicator::getStaticCommunicator().allReduce(&norm, 1, _so_sum); error = sqrt(norm); AKANTU_DEBUG_ASSERT(!Math::isnan(norm), "Something goes wrong in the solve phase"); AKANTU_DEBUG_OUT(); return (error < tolerance); } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::computeTangentModuli<_bernoulli_beam_2>(Array<Real> & tangent_moduli) { UInt nb_element = getFEEngine().getMesh().getNbElement(_bernoulli_beam_2); UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(_bernoulli_beam_2); UInt tangent_size = 2; Array<Real>::matrix_iterator D_it = tangent_moduli.begin(tangent_size, tangent_size); Array<UInt> & el_mat = element_material(_bernoulli_beam_2, _not_ghost); for (UInt e = 0; e < nb_element; ++e) { UInt mat = el_mat(e); Real E = materials[mat].E; Real A = materials[mat].A; Real I = materials[mat].I; for (UInt q = 0; q < nb_quadrature_points; ++q, ++D_it) { Matrix<Real> & D = *D_it; D(0,0) = E * A; D(1,1) = E * I; } } } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::computeTangentModuli<_bernoulli_beam_3>(Array<Real> & tangent_moduli) { UInt nb_element = getFEEngine().getMesh().getNbElement(_bernoulli_beam_3); UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(_bernoulli_beam_3); UInt tangent_size = 4; Array<Real>::matrix_iterator D_it = tangent_moduli.begin(tangent_size, tangent_size); for (UInt e = 0; e < nb_element; ++e) { UInt mat = element_material(_bernoulli_beam_3, _not_ghost)(e); Real E = materials[mat].E; Real A = materials[mat].A; Real Iz = materials[mat].Iz; Real Iy = materials[mat].Iy; Real GJ = materials[mat].GJ; for (UInt q = 0; q < nb_quadrature_points; ++q, ++D_it) { Matrix<Real> & D = *D_it; D(0,0) = E * A; D(1,1) = E * Iz; D(2,2) = E * Iy; D(3,3) = GJ; } } } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::computeTangentModuli<_kirchhoff_shell>(Array<Real> & tangent_moduli) { UInt nb_element = getFEEngine().getMesh().getNbElement(_kirchhoff_shell); UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(_kirchhoff_shell); UInt tangent_size = 6; Array<Real>::matrix_iterator D_it = tangent_moduli.begin(tangent_size, tangent_size); for (UInt e = 0; e < nb_element; ++e) { UInt mat = element_material(_kirchhoff_shell, _not_ghost)(e); Real E = materials[mat].E; Real nu = materials[mat].nu; Real t = materials[mat].t; Real HH=E*t/(1-nu*nu); Real DD=E*t*t*t/(12*(1-nu*nu)); for (UInt q = 0; q < nb_quadrature_points; ++q, ++D_it) { Matrix<Real> & D = *D_it; D(0,0) = HH; D(0,1) = HH*nu; D(1,0) = HH*nu; D(1,1) = HH; D(2,2) = HH*(1-nu)/2; D(3,3) = DD; D(3,4) = DD*nu; D(4,3) = DD*nu; D(4,4) = DD; D(5,5) = DD*(1-nu)/2; } } } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::transferBMatrixToSymVoigtBMatrix<_bernoulli_beam_2>(Array<Real> & b, bool local) { UInt nb_element = getFEEngine().getMesh().getNbElement(_bernoulli_beam_2); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(_bernoulli_beam_2); UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(_bernoulli_beam_2); MyFEEngineType & fem = getFEEngineClass<MyFEEngineType>(); Array<Real>::const_vector_iterator shape_Np = fem.getShapesDerivatives(_bernoulli_beam_2, _not_ghost, 0).begin(nb_nodes_per_element); Array<Real>::const_vector_iterator shape_Mpp = fem.getShapesDerivatives(_bernoulli_beam_2, _not_ghost, 1).begin(nb_nodes_per_element); Array<Real>::const_vector_iterator shape_Lpp = fem.getShapesDerivatives(_bernoulli_beam_2, _not_ghost, 2).begin(nb_nodes_per_element); UInt tangent_size = getTangentStiffnessVoigtSize<_bernoulli_beam_2>(); UInt bt_d_b_size = nb_nodes_per_element * nb_degree_of_freedom; b.clear(); Array<Real>::matrix_iterator B_it = b.begin(tangent_size, bt_d_b_size); for (UInt e = 0; e < nb_element; ++e) { for (UInt q = 0; q < nb_quadrature_points; ++q) { Matrix<Real> & B = *B_it; const Vector<Real> & Np = *shape_Np; const Vector<Real> & Lpp = *shape_Lpp; const Vector<Real> & Mpp = *shape_Mpp; B(0,0) = Np(0); B(0,3) = Np(1); B(1,1) = Mpp(0); B(1,2) = Lpp(0); B(1,4) = Mpp(1); B(1,5) = Lpp(1); ++B_it; ++shape_Np; ++shape_Mpp; ++shape_Lpp; } // ++R_it; } } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::transferBMatrixToSymVoigtBMatrix<_bernoulli_beam_3>(Array<Real> & b, bool local) { MyFEEngineType & fem = getFEEngineClass<MyFEEngineType>(); UInt nb_element = getFEEngine().getMesh().getNbElement(_bernoulli_beam_3); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(_bernoulli_beam_3); UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(_bernoulli_beam_3); Array<Real>::const_vector_iterator shape_Np = fem.getShapesDerivatives(_bernoulli_beam_3, _not_ghost, 0).begin(nb_nodes_per_element); Array<Real>::const_vector_iterator shape_Mpp = fem.getShapesDerivatives(_bernoulli_beam_3, _not_ghost, 1).begin(nb_nodes_per_element); Array<Real>::const_vector_iterator shape_Lpp = fem.getShapesDerivatives(_bernoulli_beam_3, _not_ghost, 2).begin(nb_nodes_per_element); UInt tangent_size = getTangentStiffnessVoigtSize<_bernoulli_beam_3>(); UInt bt_d_b_size = nb_nodes_per_element * nb_degree_of_freedom; b.clear(); Array<Real>::matrix_iterator B_it = b.begin(tangent_size, bt_d_b_size); for (UInt e = 0; e < nb_element; ++e) { for (UInt q = 0; q < nb_quadrature_points; ++q) { Matrix<Real> & B = *B_it; const Vector<Real> & Np = *shape_Np; const Vector<Real> & Lpp = *shape_Lpp; const Vector<Real> & Mpp = *shape_Mpp; B(0,0) = Np(0); B(0,6) = Np(1); B(1,1) = Mpp(0); B(1,5) = Lpp(0); B(1,7) = Mpp(1); B(1,11) = Lpp(1); B(2,2) = Mpp(0); B(2,4) = -Lpp(0); B(2,8) = Mpp(1); B(2,10) = -Lpp(1); B(3,3) = Np(0); B(3,9) = Np(1); ++B_it; ++shape_Np; ++shape_Mpp; ++shape_Lpp; } } } /* -------------------------------------------------------------------------- */ template<> void StructuralMechanicsModel::transferBMatrixToSymVoigtBMatrix<_kirchhoff_shell>(Array<Real> & b, bool local) { MyFEEngineType & fem = getFEEngineClass<MyFEEngineType>(); UInt nb_element = getFEEngine().getMesh().getNbElement(_kirchhoff_shell); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(_kirchhoff_shell); UInt nb_quadrature_points = getFEEngine().getNbQuadraturePoints(_kirchhoff_shell); Array<Real>::const_matrix_iterator shape_Np = fem.getShapesDerivatives(_kirchhoff_shell, _not_ghost, 0).begin(2,nb_nodes_per_element); Array<Real>::const_matrix_iterator shape_Nx1p = fem.getShapesDerivatives(_kirchhoff_shell, _not_ghost, 1).begin(2,nb_nodes_per_element); Array<Real>::const_matrix_iterator shape_Nx2p = fem.getShapesDerivatives(_kirchhoff_shell, _not_ghost, 2).begin(2,nb_nodes_per_element); Array<Real>::const_matrix_iterator shape_Nx3p = fem.getShapesDerivatives(_kirchhoff_shell, _not_ghost, 3).begin(2,nb_nodes_per_element); Array<Real>::const_matrix_iterator shape_Ny1p = fem.getShapesDerivatives(_kirchhoff_shell, _not_ghost, 4).begin(2,nb_nodes_per_element); Array<Real>::const_matrix_iterator shape_Ny2p = fem.getShapesDerivatives(_kirchhoff_shell, _not_ghost, 5).begin(2,nb_nodes_per_element); Array<Real>::const_matrix_iterator shape_Ny3p = fem.getShapesDerivatives(_kirchhoff_shell, _not_ghost, 6).begin(2,nb_nodes_per_element); UInt tangent_size = getTangentStiffnessVoigtSize<_kirchhoff_shell>(); UInt bt_d_b_size = nb_nodes_per_element * nb_degree_of_freedom; b.clear(); Array<Real>::matrix_iterator B_it = b.begin(tangent_size, bt_d_b_size); for (UInt e = 0; e < nb_element; ++e) { for (UInt q = 0; q < nb_quadrature_points; ++q) { Matrix<Real> & B = *B_it; const Matrix<Real> & Np = *shape_Np; const Matrix<Real> & Nx1p = *shape_Nx1p; const Matrix<Real> & Nx2p = *shape_Nx2p; const Matrix<Real> & Nx3p = *shape_Nx3p; const Matrix<Real> & Ny1p = *shape_Ny1p; const Matrix<Real> & Ny2p = *shape_Ny2p; const Matrix<Real> & Ny3p = *shape_Ny3p; B(0,0) = Np(0,0); B(0,6) = Np(0,1); B(0,12) = Np(0,2); B(1,1) = Np(1,0); B(1,7) = Np(1,1); B(1,13) = Np(1,2); B(2,0) = Np(1,0); B(2,1) = Np(0,0); B(2,6) = Np(1,1); B(2,7) = Np(0,1); B(2,12) = Np(1,2); B(2,13) = Np(0,2); B(3,2) = Nx1p(0,0); B(3,3) = Nx2p(0,0); B(3,4) = Nx3p(0,0); B(3,8) = Nx1p(0,1); B(3,9) = Nx2p(0,1); B(3,10) = Nx3p(0,1); B(3,14) = Nx1p(0,2); B(3,15) = Nx2p(0,2); B(3,16) = Nx3p(0,2); B(4,2) = Ny1p(1,0); B(4,3) = Ny2p(1,0); B(4,4) = Ny3p(1,0); B(4,8) = Ny1p(1,1); B(4,9) = Ny2p(1,1); B(4,10) = Ny3p(1,1); B(4,14) = Ny1p(1,2); B(4,15) = Ny2p(1,2); B(4,16) = Ny3p(1,2); B(5,2) = Nx1p(1,0) + Ny1p(0,0); B(5,3) = Nx2p(1,0) + Ny2p(0,0); B(5,4) = Nx3p(1,0) + Ny3p(0,0); B(5,8) = Nx1p(1,1) + Ny1p(0,1); B(5,9) = Nx2p(1,1) + Ny2p(0,1); B(5,10) = Nx3p(1,1) + Ny3p(0,1); B(5,14) = Nx1p(1,2) + Ny1p(0,2); B(5,15) = Nx2p(1,2) + Ny2p(0,2); B(5,16) = Nx3p(1,2) + Ny3p(0,2); ++B_it; ++shape_Np; ++shape_Nx1p; ++shape_Nx2p; ++shape_Nx3p; ++shape_Ny1p; ++shape_Ny2p; ++shape_Ny3p; } } } /* -------------------------------------------------------------------------- */ dumper::Field * StructuralMechanicsModel ::createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag) { std::map<std::string,Array<bool>* > uint_nodal_fields; uint_nodal_fields["blocked_dofs" ] = blocked_dofs; dumper::Field * field = NULL; field = mesh.createNodalField(uint_nodal_fields[field_name],group_name); return field; } /* -------------------------------------------------------------------------- */ dumper::Field * StructuralMechanicsModel ::createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) { UInt n; if(spatial_dimension == 2) { n = 2; } else n = 3; dumper::Field * field = NULL; if (field_name == "displacement"){ field = mesh.createStridedNodalField(displacement_rotation,group_name,n,0,padding_flag); } if (field_name == "rotation"){ field = mesh.createStridedNodalField(displacement_rotation,group_name, nb_degree_of_freedom-n,n,padding_flag); } if (field_name == "force"){ field = mesh.createStridedNodalField(force_momentum,group_name,n,0,padding_flag); } if (field_name == "momentum"){ field = mesh.createStridedNodalField(force_momentum,group_name, nb_degree_of_freedom-n,n,padding_flag); } if (field_name == "residual"){ field = mesh.createNodalField(residual,group_name,padding_flag); } return field; } /* -------------------------------------------------------------------------- */ dumper::Field * StructuralMechanicsModel ::createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const ElementKind & kind){ dumper::Field * field = NULL; if(field_name == "element_index_by_material") field = mesh.createElementalField<UInt, Vector, dumper::ElementalField >(field_name,group_name,this->spatial_dimension,kind); return field; } /* -------------------------------------------------------------------------- */ __END_AKANTU__