diff --git a/packages/19_parallel_cohesive_element.cmake b/packages/19_parallel_cohesive_element.cmake index 7cbe468e9..da9bc3d41 100644 --- a/packages/19_parallel_cohesive_element.cmake +++ b/packages/19_parallel_cohesive_element.cmake @@ -1,50 +1,52 @@ #=============================================================================== # @file parallel_cohesive_element.cmake # # @author Nicolas Richart # # @date Tue Oct 16 14:05:02 2012 # # @brief package description for parallel cohesive elements # # @section LICENSE # # Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) # Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Akantu. If not, see . # #=============================================================================== option(AKANTU_PARALLEL_COHESIVE_ELEMENT "Use parallel cohesive_element package of Akantu" OFF) add_internal_package_dependencies(parallel_cohesive_element cohesive_element parallel) set(AKANTU_PARALLEL_COHESIVE_ELEMENT_FILES + mesh_utils/cohesive_element_inserter_parallel.cc + mesh_utils/cohesive_element_inserter_inline_impl.cc model/solid_mechanics/solid_mechanics_model_cohesive_parallel.hh model/solid_mechanics/solid_mechanics_model_cohesive_parallel.cc model/solid_mechanics/solid_mechanics_model_cohesive_inline_impl.cc synchronizer/facet_synchronizer.cc synchronizer/facet_synchronizer.hh synchronizer/facet_synchronizer_inline_impl.cc synchronizer/facet_stress_synchronizer.cc synchronizer/facet_stress_synchronizer.hh ) set(AKANTU_PARALLEL_COHESIVE_ELEMENT_TESTS test_cohesive_parallel_intrinsic test_cohesive_parallel_extrinsic test_cohesive_parallel_extrinsic_IG_TG test_cohesive_ghost_element_insertion test_facet_synchronizer ) diff --git a/packages/20_cohesive_element.cmake b/packages/20_cohesive_element.cmake index d5ed67f26..99748db01 100644 --- a/packages/20_cohesive_element.cmake +++ b/packages/20_cohesive_element.cmake @@ -1,77 +1,80 @@ #=============================================================================== # @file cohesive_element.cmake # # @author Nicolas Richart # # @date Tue Oct 16 14:05:02 2012 # # @brief package description for cohesive elements # # @section LICENSE # # Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) # Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) # # Akantu is free software: you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) any # later version. # # Akantu is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # details. # # You should have received a copy of the GNU Lesser General Public License # along with Akantu. If not, see . # #=============================================================================== option(AKANTU_COHESIVE_ELEMENT "Use cohesive_element package of Akantu" OFF) add_external_package_dependencies(cohesive_element lapack) set(AKANTU_COHESIVE_ELEMENT_FILES model/solid_mechanics/materials/material_cohesive_includes.hh + mesh_utils/cohesive_element_inserter.hh + mesh_utils/cohesive_element_inserter.cc + fem/cohesive_element.cc fem/shape_cohesive.hh fem/cohesive_element.hh fem/fem_template_cohesive.cc fem/shape_cohesive_inline_impl.cc model/solid_mechanics/materials/material_cohesive/cohesive_internal_field_tmpl.hh model/solid_mechanics/materials/material_cohesive/cohesive_internal_field.hh model/solid_mechanics/materials/material_cohesive/material_cohesive_inline_impl.cc model/solid_mechanics/solid_mechanics_model_cohesive.cc model/solid_mechanics/materials/material_cohesive/material_cohesive.cc model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.cc model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_bilinear.cc model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_exponential.cc model/solid_mechanics/solid_mechanics_model_cohesive.hh model/solid_mechanics/materials/material_cohesive/material_cohesive.hh model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_bilinear.hh model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.hh model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_exponential.hh io/dumper/dumper_iohelper_tmpl_connectivity_field.hh ) set(AKANTU_COHESIVE_ELEMENT_TESTS test_cohesive_buildfacets_tetrahedron test_cohesive_buildfacets_hexahedron test_cohesive_intrinsic test_cohesive_intrinsic_quadrangle test_cohesive_extrinsic test_cohesive_extrinsic_quadrangle test_cohesive_buildfragments test_cohesive_intrinsic_impl ) set(AKANTU_COHESIVE_ELEMENT_DOC manual/manual-cohesive_element.tex ) \ No newline at end of file diff --git a/src/common/aka_common.hh b/src/common/aka_common.hh index 8bf8df10b..9ec35d843 100644 --- a/src/common/aka_common.hh +++ b/src/common/aka_common.hh @@ -1,540 +1,541 @@ /** * @file aka_common.hh * * @author Nicolas Richart * * @date Mon Jun 14 19:12:20 2010 * * @brief common type descriptions for akantu * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * * @section DESCRIPTION * * All common things to be included in the projects files * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMON_HH__ #define __AKANTU_COMMON_HH__ /* -------------------------------------------------------------------------- */ #include #include /* -------------------------------------------------------------------------- */ #define __BEGIN_AKANTU__ namespace akantu { #define __END_AKANTU__ } /* -------------------------------------------------------------------------- */ #include "aka_config.hh" #include "aka_error.hh" #include "aka_safe_enum.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ /* Common types */ /* -------------------------------------------------------------------------- */ typedef double Real; typedef unsigned int UInt; typedef unsigned long long UInt64; typedef signed int Int; typedef std::string ID; static const Real UINT_INIT_VALUE = 0; #ifdef AKANTU_NDEBUG static const Real REAL_INIT_VALUE = 0; #else static const Real REAL_INIT_VALUE = std::numeric_limits::quiet_NaN(); #endif /* -------------------------------------------------------------------------- */ /* Memory types */ /* -------------------------------------------------------------------------- */ typedef UInt MemoryID; /* -------------------------------------------------------------------------- */ /* Mesh/FEM/Model types */ /* -------------------------------------------------------------------------- */ typedef std::string Surface; typedef std::pair SurfacePair; typedef std::list< SurfacePair > SurfacePairList; /* -------------------------------------------------------------------------- */ extern const UInt _all_dimensions; /// @boost sequence of element to loop on in global tasks #define AKANTU_REGULAR_ELEMENT_TYPE \ (_point_1) \ (_segment_2) \ (_segment_3) \ (_triangle_3) \ (_triangle_6) \ (_quadrangle_4) \ (_quadrangle_8) \ (_tetrahedron_4) \ (_tetrahedron_10) \ (_pentahedron_6) \ (_hexahedron_8) #if defined(AKANTU_STRUCTURAL_MECHANICS) #define AKANTU_STRUCTURAL_ELEMENT_TYPE \ (_bernoulli_beam_2) \ (_bernoulli_beam_3) #else #define AKANTU_STRUCTURAL_ELEMENT_TYPE #endif #if defined(AKANTU_COHESIVE_ELEMENT) # define AKANTU_COHESIVE_ELEMENT_TYPE \ (_cohesive_2d_4) \ (_cohesive_2d_6) \ (_cohesive_1d_2) \ (_cohesive_3d_6) \ (_cohesive_3d_12) #else # define AKANTU_COHESIVE_ELEMENT_TYPE #endif #define AKANTU_ALL_ELEMENT_TYPE \ AKANTU_REGULAR_ELEMENT_TYPE \ AKANTU_COHESIVE_ELEMENT_TYPE \ AKANTU_STRUCTURAL_ELEMENT_TYPE #define AKANTU_NOT_STRUCTURAL_ELEMENT_TYPE \ AKANTU_REGULAR_ELEMENT_TYPE \ AKANTU_COHESIVE_ELEMENT_TYPE /// @enum ElementType type of elements enum ElementType { _not_defined, _point_1, _segment_2, ///< first order segment _segment_3, ///< second order segment _triangle_3, ///< first order triangle _triangle_6, ///< second order triangle _tetrahedron_4, ///< first order tetrahedron _tetrahedron_10, ///< second order tetrahedron _quadrangle_4, ///< first order quadrangle _quadrangle_8, ///< second order quadrangle _hexahedron_8, ///< first order hexahedron _pentahedron_6, ///< first order pentahedron _bernoulli_beam_2, ///< Bernoulli beam 2D _bernoulli_beam_3, ///< Bernoulli beam 3D #if defined(AKANTU_COHESIVE_ELEMENT) _cohesive_2d_4, ///< first order 2D cohesive _cohesive_2d_6, ///< second order 2D cohesive _cohesive_1d_2, ///< first order 1D cohesive _cohesive_3d_6, ///< first order 3D cohesive _cohesive_3d_12, ///< second order 3D cohesive #endif _max_element_type }; /// @enum GeometricalType type of element potentially contained in a Mesh enum GeometricalType { _gt_point, ///< point @remark only for some algorithm to be generic like mesh partitioning */ _gt_segment_2, ///< 2 nodes segment _gt_segment_3, ///< 3 nodes segment _gt_triangle_3, ///< 3 nodes triangle _gt_triangle_6, ///< 6 nodes triangle _gt_quadrangle_4, ///< 4 nodes quadrangle _gt_quadrangle_8, ///< 8 nodes quadrangle _gt_tetrahedron_4, ///< 4 nodes tetrahedron _gt_tetrahedron_10, ///< 10 nodes tetrahedron _gt_hexahedron_8, ///< 8 nodes hexahedron _gt_pentahedron_6, ///< 6 nodes pentahedron #if defined(AKANTU_COHESIVE_ELEMENT) _gt_cohesive_2d_4, ///< 4 nodes 2D cohesive _gt_cohesive_2d_6, ///< 6 nodes 2D cohesive _gt_cohesive_1d_2, ///< 2 nodes 1D cohesive _gt_cohesive_3d_6, ///< 6 nodes 3D cohesive _gt_cohesive_3d_12, ///< 12 nodes 3D cohesive #endif _gt_not_defined }; /// @enum InterpolationType type of elements enum InterpolationType { _itp_lagrange_point_1, ///< zeroth (!) order lagrangian point (for compatibility purposes) _itp_lagrange_segment_2, ///< first order lagrangian segment _itp_lagrange_segment_3, ///< second order lagrangian segment _itp_lagrange_triangle_3, ///< first order lagrangian triangle _itp_lagrange_triangle_6, ///< second order lagrangian triangle _itp_lagrange_quadrangle_4, ///< first order lagrangian quadrangle _itp_serendip_quadrangle_8, /**< second order serendipian quadrangle @remark used insted of the 9 node lagrangian element */ _itp_lagrange_tetrahedron_4, ///< first order lagrangian tetrahedron _itp_lagrange_tetrahedron_10, ///< second order lagrangian tetrahedron _itp_lagrange_hexahedron_8, ///< first order lagrangian hexahedron _itp_lagrange_pentahedron_6, ///< first order lagrangian pentahedron _itp_bernoulli_beam, ///< Bernoulli beam _itp_not_defined }; //! standard output stream operator for ElementType inline std::ostream & operator <<(std::ostream & stream, ElementType type); enum ElementKind { _ek_regular, _ek_cohesive, _ek_structural, _ek_not_defined }; /// enum MeshIOType type of mesh reader/writer enum MeshIOType { _miot_auto, _miot_gmsh, _miot_diana }; /// enum AnalysisMethod type of solving method used to solve the equation of motion enum AnalysisMethod { _static, _implicit_dynamic, _explicit_lumped_mass, _explicit_consistent_mass }; /// enum SolveConvergenceMethod different resolution algorithms enum SolveConvergenceMethod { _scm_newton_raphson_tangent, ///< Newton-Raphson with tangent matrix _scm_newton_raphson_tangent_modified, ///< Newton-Raphson with constant tangent matrix _scm_newton_raphson_tangent_not_computed ///< Newton-Raphson with constant tangent matrix (user has to assemble it) }; /// enum SolveConvergenceCriteria different convergence criteria enum SolveConvergenceCriteria { _scc_residual, ///< Use residual to test the convergence _scc_increment ///< Use increment to test the convergence }; /// enum CohesiveMethod type of insertion of cohesive elements enum CohesiveMethod { _intrinsic, _extrinsic }; /// myfunction(double * position, double * stress/force, double * normal, unsigned int material_id) typedef void (*BoundaryFunction)(double *,double *, double*, unsigned int); /// @enum BoundaryFunctionType type of function passed for boundary conditions enum BoundaryFunctionType { _bft_stress, _bft_traction, _bft_traction_local }; /// @enum SparseMatrixType type of sparse matrix used enum SparseMatrixType { _unsymmetric, _symmetric }; /* -------------------------------------------------------------------------- */ /* Contact */ /* -------------------------------------------------------------------------- */ typedef ID ContactID; typedef ID ContactSearchID; typedef ID ContactNeighborStructureID; enum ContactType { _ct_not_defined = 0, _ct_2d_expli = 1, _ct_3d_expli = 2, _ct_rigid = 3 }; enum ContactSearchType { _cst_not_defined = 0, _cst_2d_expli = 1, _cst_expli = 2 }; enum ContactNeighborStructureType { _cnst_not_defined = 0, _cnst_regular_grid = 1, _cnst_2d_grid = 2 }; /* -------------------------------------------------------------------------- */ /* Friction */ /* -------------------------------------------------------------------------- */ typedef ID FrictionID; /* -------------------------------------------------------------------------- */ /* Ghosts handling */ /* -------------------------------------------------------------------------- */ typedef ID SynchronizerID; /// @enum CommunicatorType type of communication method to use enum CommunicatorType { _communicator_mpi, _communicator_dummy }; /// @enum SynchronizationTag type of synchronizations enum SynchronizationTag { //--- SolidMechanicsModel tags --- _gst_smm_mass, //< synchronization of the SolidMechanicsModel.mass _gst_smm_for_strain, //< synchronization of the SolidMechanicsModel.current_position _gst_smm_boundary, //< synchronization of the boundary, forces, velocities and displacement _gst_smm_uv, //< synchronization of the nodal velocities and displacement _gst_smm_res, //< synchronization of the nodal residual _gst_smm_init_mat, //< synchronization of the data to initialize materials _gst_smm_stress, //< synchronization of the stresses to compute the internal forces _gst_smmc_facets, //< synchronization of facet data to setup facet synch _gst_smmc_facets_conn, //< synchronization of facet global connectivity _gst_smmc_facets_stress, //< synchronization of facets' stress to setup facet synch + _gst_inserter, //< synchronization of global nodes id of newly inserted cohesive elements //--- HeatTransfer tags --- _gst_htm_capacity, //< synchronization of the nodal heat capacity _gst_htm_temperature, //< synchronization of the nodal temperature _gst_htm_gradient_temperature, //< synchronization of the element gradient temperature //--- LevelSet tags --- /// synchronization of the nodal level set value phi _gst_htm_phi, /// synchronization of the element gradient phi _gst_htm_gradient_phi, //--- Material non local --- _gst_mnl_for_average, //< synchronization of data to average in non local material _gst_mnl_weight, //< synchronization of data for the weight computations //--- General tags --- _gst_test, //< Test tag _gst_material_id, //< synchronization of the material ids //--- Contact & Friction --- _gst_cf_nodal, //< synchronization of disp, velo, and current position _gst_cf_incr //< synchronization of increment }; /// standard output stream operator for SynchronizationTag inline std::ostream & operator <<(std::ostream & stream, SynchronizationTag type); /// @enum GhostType type of ghost enum GhostType { _not_ghost, _ghost, _casper // not used but a real cute ghost }; /* -------------------------------------------------------------------------- */ struct GhostType_def { typedef GhostType type; static const type _begin_ = _not_ghost; static const type _end_ = _casper; }; typedef safe_enum ghost_type_t; /// standard output stream operator for GhostType inline std::ostream & operator <<(std::ostream & stream, GhostType type); /// @enum SynchronizerOperation reduce operation that the synchronizer can perform enum SynchronizerOperation { _so_sum, _so_min, _so_max, _so_null }; /* -------------------------------------------------------------------------- */ /* Global defines */ /* -------------------------------------------------------------------------- */ #define AKANTU_MIN_ALLOCATION 2000 #define AKANTU_INDENT " " #define AKANTU_INCLUDE_INLINE_IMPL /* -------------------------------------------------------------------------- */ // int 2 type construct template struct Int2Type { enum { result = d }; }; // type 2 type construct template class Type2Type { typedef T OriginalType; }; /* -------------------------------------------------------------------------- */ template struct is_scalar { enum{ value = false }; }; #define AKANTU_SPECIFY_IS_SCALAR(type) \ template<> \ struct is_scalar { \ enum { value = true }; \ } AKANTU_SPECIFY_IS_SCALAR(Real); AKANTU_SPECIFY_IS_SCALAR(UInt); AKANTU_SPECIFY_IS_SCALAR(Int); AKANTU_SPECIFY_IS_SCALAR(bool); template < typename T1, typename T2 > struct is_same { enum { value = false }; // is_same represents a bool. }; template < typename T > struct is_same { enum { value = true }; }; /* -------------------------------------------------------------------------- */ #define AKANTU_SET_MACRO(name, variable, type) \ inline void set##name (type variable) { \ this->variable = variable; \ } #define AKANTU_GET_MACRO(name, variable, type) \ inline type get##name () const { \ return variable; \ } #define AKANTU_GET_MACRO_NOT_CONST(name, variable, type) \ inline type get##name () { \ return variable; \ } #define AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, \ support, con) \ inline con Array & \ get##name (const support & el_type, \ const GhostType & ghost_type = _not_ghost) con { \ return variable(el_type, ghost_type); \ } #define AKANTU_GET_MACRO_BY_ELEMENT_TYPE(name, variable, type) \ AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, ElementType,) #define AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(name, variable, type) \ AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, ElementType, const) #define AKANTU_GET_MACRO_BY_GEOMETRIE_TYPE(name, variable, type) \ AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, GeometricalType,) #define AKANTU_GET_MACRO_BY_GEOMETRIE_TYPE_CONST(name, variable, type) \ AKANTU_GET_MACRO_BY_SUPPORT_TYPE(name, variable, type, GeometricalType, const) /* -------------------------------------------------------------------------- */ void initialize(int & argc, char ** & argv); /* -------------------------------------------------------------------------- */ void finalize (); /* -------------------------------------------------------------------------- */ /* * For intel compiler annoying remark */ #if defined(__INTEL_COMPILER) /// remark #981: operands are evaluated in unspecified order #pragma warning ( disable : 981 ) /// remark #383: value copied to temporary, reference to temporary used #pragma warning ( disable : 383 ) #endif //defined(__INTEL_COMPILER) /* -------------------------------------------------------------------------- */ /* string manipulation */ /* -------------------------------------------------------------------------- */ inline std::string to_lower(const std::string & str); /* -------------------------------------------------------------------------- */ inline std::string trim(const std::string & to_trim); __END_AKANTU__ /* -------------------------------------------------------------------------- */ // BOOST PART: TOUCH ONLY IF YOU KNOW WHAT YOU ARE DOING #include #define AKANTU_BOOST_CASE_MACRO(r,macro,type) \ case type : { macro(type); break; } #define AKANTU_BOOST_ELEMENT_SWITCH(macro1, list1) \ do { \ switch(type) { \ BOOST_PP_SEQ_FOR_EACH(AKANTU_BOOST_CASE_MACRO, macro1, list1) \ default: { \ AKANTU_DEBUG_ERROR("Type (" << UInt(type) << ") not handled by this function"); \ } \ } \ } while(0) #define AKANTU_BOOST_ALL_ELEMENT_SWITCH(macro) \ AKANTU_BOOST_ELEMENT_SWITCH(macro, \ AKANTU_ALL_ELEMENT_TYPE) #define AKANTU_BOOST_REGULAR_ELEMENT_SWITCH(macro) \ AKANTU_BOOST_ELEMENT_SWITCH(macro, \ AKANTU_REGULAR_ELEMENT_TYPE) #define AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(macro) \ AKANTU_BOOST_ELEMENT_SWITCH(macro, \ AKANTU_COHESIVE_ELEMENT_TYPE) #define AKANTU_BOOST_STRUCTURAL_ELEMENT_SWITCH(macro) \ AKANTU_BOOST_ELEMENT_SWITCH(macro, \ AKANTU_STRUCTURAL_ELEMENT_TYPE) #define AKANTU_BOOST_LIST_MACRO(r,macro,type) \ macro(type) #define AKANTU_BOOST_ELEMENT_LIST(macro, list) \ BOOST_PP_SEQ_FOR_EACH(AKANTU_BOOST_LIST_MACRO,macro,list) #define AKANTU_BOOST_ALL_ELEMENT_LIST(macro) \ AKANTU_BOOST_ELEMENT_LIST(macro, AKANTU_ALL_ELEMENT_TYPE) #define AKANTU_BOOST_REGULAR_ELEMENT_LIST(macro) \ AKANTU_BOOST_ELEMENT_LIST(macro, AKANTU_REGULAR_ELEMENT_TYPE) #define AKANTU_BOOST_STRUCTURAL_ELEMENT_LIST(macro) \ AKANTU_BOOST_ELEMENT_LIST(macro, AKANTU_STRUCTURAL_ELEMENT_TYPE) #define AKANTU_BOOST_COHESIVE_ELEMENT_LIST(macro) \ AKANTU_BOOST_ELEMENT_LIST(macro, AKANTU_COHESIVE_ELEMENT_TYPE) #include "aka_common_inline_impl.cc" #include "aka_fwd.hh" #endif /* __AKANTU_COMMON_HH__ */ diff --git a/src/common/aka_common_inline_impl.cc b/src/common/aka_common_inline_impl.cc index e3f1b7ef7..9407d01f2 100644 --- a/src/common/aka_common_inline_impl.cc +++ b/src/common/aka_common_inline_impl.cc @@ -1,157 +1,158 @@ /** * @file aka_common_inline_impl.cc * * @author Guillaume Anciaux * @author Nicolas Richart * * @date Thu Dec 01 12:54:29 2011 * * @brief inline implementations of common akantu type descriptions * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * * @section DESCRIPTION * * All common things to be included in the projects files * */ #include __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ //! standard output stream operator for ElementType inline std::ostream & operator <<(std::ostream & stream, ElementType type) { #define STRINGIFY(type) \ stream << BOOST_PP_STRINGIZE(type); AKANTU_BOOST_ALL_ELEMENT_SWITCH(STRINGIFY); #undef STRINGIFY return stream; } /* -------------------------------------------------------------------------- */ /// standard output stream operator for InterpolationType inline std::ostream & operator <<(std::ostream & stream, InterpolationType type) { switch(type) { case _itp_lagrange_point_1 : stream << "_itp_lagrange_point_1" ; break; case _itp_lagrange_segment_2 : stream << "_itp_lagrange_segment_2" ; break; case _itp_lagrange_segment_3 : stream << "_itp_lagrange_segment_3" ; break; case _itp_lagrange_triangle_3 : stream << "_itp_lagrange_triangle_3" ; break; case _itp_lagrange_triangle_6 : stream << "_itp_lagrange_triangle_6" ; break; case _itp_lagrange_quadrangle_4 : stream << "_itp_lagrange_quadrangle_4" ; break; case _itp_serendip_quadrangle_8 : stream << "_itp_serendip_quadrangle_8" ; break; case _itp_lagrange_tetrahedron_4 : stream << "_itp_lagrange_tetrahedron_4" ; break; case _itp_lagrange_tetrahedron_10 : stream << "_itp_lagrange_tetrahedron_10"; break; case _itp_lagrange_hexahedron_8 : stream << "_itp_lagrange_hexahedron_8" ; break; case _itp_lagrange_pentahedron_6 : stream << "_itp_lagrange_pentahedron_6" ; break; case _itp_bernoulli_beam : stream << "_itp_bernoulli_beam" ; break; case _itp_not_defined : stream << "_itp_not_defined" ; break; } return stream; } /* -------------------------------------------------------------------------- */ /// standard output stream operator for GhostType inline std::ostream & operator <<(std::ostream & stream, GhostType type) { switch(type) { case _not_ghost : stream << "not_ghost"; break; case _ghost : stream << "ghost" ; break; case _casper : stream << "Casper the friendly ghost"; break; } return stream; } /* -------------------------------------------------------------------------- */ /// standard output stream operator for SynchronizationTag inline std::ostream & operator <<(std::ostream & stream, SynchronizationTag type) { switch(type) { case _gst_smm_mass : stream << "_gst_smm_mass" ; break; case _gst_smm_for_strain : stream << "_gst_smm_for_strain" ; break; case _gst_smm_boundary : stream << "_gst_smm_boundary" ; break; case _gst_smm_uv : stream << "_gst_smm_uv" ; break; case _gst_smm_res : stream << "_gst_smm_res" ; break; case _gst_smm_init_mat : stream << "_gst_smm_init_mat" ; break; case _gst_smm_stress : stream << "_gst_smm_stress" ; break; case _gst_smmc_facets : stream << "_gst_smmc_facets" ; break; case _gst_smmc_facets_conn : stream << "_gst_smmc_facets_conn" ; break; case _gst_smmc_facets_stress : stream << "_gst_smmc_facets_stress" ; break; + case _gst_inserter : stream << "_gst_inserter" ; break; case _gst_htm_capacity : stream << "_gst_htm_capacity" ; break; case _gst_htm_temperature : stream << "_gst_htm_temperature" ; break; case _gst_htm_gradient_temperature : stream << "_gst_htm_gradient_temperature"; break; case _gst_htm_phi : stream << "_gst_htm_phi" ; break; case _gst_htm_gradient_phi : stream << "_gst_htm_gradient_phi" ; break; case _gst_mnl_for_average : stream << "_gst_mnl_for_average" ; break; case _gst_mnl_weight : stream << "_gst_mnl_weight" ; break; case _gst_test : stream << "_gst_test" ; break; case _gst_material_id : stream << "_gst_material_id" ; break; case _gst_cf_nodal : stream << "_gst_cf_nodal" ; break; case _gst_cf_incr : stream << "_gst_cf_incr" ; break; } return stream; } /* -------------------------------------------------------------------------- */ /// standard output stream operator for SolveConvergenceCriteria inline std::ostream & operator <<(std::ostream & stream, SolveConvergenceCriteria criteria) { switch(criteria) { case _scc_residual : stream << "_scc_residual" ; break; case _scc_increment: stream << "_scc_increment"; break; } return stream; } /* -------------------------------------------------------------------------- */ inline std::string to_lower(const std::string & str) { std::string lstr = str; std::transform(lstr.begin(), lstr.end(), lstr.begin(), (int(*)(int))std::tolower); return lstr; } /* -------------------------------------------------------------------------- */ inline std::string trim(const std::string & to_trim) { std::string trimed = to_trim; //left trim trimed.erase(trimed.begin(), std::find_if(trimed.begin(), trimed.end(), std::not1(std::ptr_fun(std::isspace)))); // right trim trimed.erase(std::find_if(trimed.rbegin(), trimed.rend(), std::not1(std::ptr_fun(std::isspace))).base(), trimed.end()); return trimed; } __END_AKANTU__ diff --git a/src/fem/mesh.hh b/src/fem/mesh.hh index aa08b8daa..358728ebf 100644 --- a/src/fem/mesh.hh +++ b/src/fem/mesh.hh @@ -1,659 +1,662 @@ /** * @file mesh.hh * * @author Guillaume Anciaux * @author Marco Vocialta * @author Nicolas Richart * @author Dana Christen * * @date Fri Jun 18 11:47:19 2010 * * @brief the class representing the meshes * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_HH__ #define __AKANTU_MESH_HH__ /* -------------------------------------------------------------------------- */ #include "aka_config.hh" #include "aka_common.hh" #include "aka_memory.hh" #include "aka_vector.hh" #include "element_class.hh" #include "by_element_type.hh" #include "aka_event_handler.hh" #include "group_manager.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ /* Element */ /* -------------------------------------------------------------------------- */ class Element; extern const Element ElementNull; class Element { public: Element(ElementType type = _not_defined, UInt element = 0, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) : type(type), element(element), ghost_type(ghost_type), kind(kind) {}; Element(const Element & element) { this->type = element.type; this->element = element.element; this->ghost_type = element.ghost_type; this->kind = element.kind; } inline bool operator==(const Element & elem) const { return ((element == elem.element) && (type == elem.type) && (ghost_type == elem.ghost_type) && (kind == elem.kind)); } inline bool operator!=(const Element & elem) const { return ((element != elem.element) || (type != elem.type) || (ghost_type != elem.ghost_type) || (kind != elem.kind)); } bool operator<(const Element& rhs) const { bool res = (rhs == ElementNull) || ((this->kind < rhs.kind) || ((this->kind == rhs.kind) && ((this->ghost_type < rhs.ghost_type) || ((this->ghost_type == rhs.ghost_type) && ((this->type < rhs.type) || ((this->type == rhs.type) && (this->element < rhs.element))))))); return res; } virtual ~Element() {}; /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; public: ElementType type; UInt element; GhostType ghost_type; ElementKind kind; }; struct CompElementLess { bool operator() (const Element& lhs, const Element& rhs) const { return lhs < rhs; } }; __END_AKANTU__ #include "mesh_data.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ /* Mesh modifications events */ /* -------------------------------------------------------------------------- */ template class MeshEvent { public: virtual ~MeshEvent() {} const Array & getList() const { return list; } Array & getList() { return list; } protected: Array list; }; class Mesh; class NewNodesEvent : public MeshEvent { public: virtual ~NewNodesEvent() {}; }; class RemovedNodesEvent : public MeshEvent { public: virtual ~RemovedNodesEvent() {}; inline RemovedNodesEvent(const Mesh & mesh); AKANTU_GET_MACRO_NOT_CONST(NewNumbering, new_numbering, Array &); AKANTU_GET_MACRO(NewNumbering, new_numbering, const Array &); private: Array new_numbering; }; class NewElementsEvent : public MeshEvent { public: virtual ~NewElementsEvent() {}; }; class RemovedElementsEvent : public MeshEvent { public: virtual ~RemovedElementsEvent() {}; inline RemovedElementsEvent(const Mesh & mesh); AKANTU_GET_MACRO(NewNumbering, new_numbering, const ByElementTypeUInt &); AKANTU_GET_MACRO_NOT_CONST(NewNumbering, new_numbering, ByElementTypeUInt &); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(NewNumbering, new_numbering, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(NewNumbering, new_numbering, UInt); protected: ByElementTypeUInt new_numbering; }; /* -------------------------------------------------------------------------- */ class MeshEventHandler { public: virtual ~MeshEventHandler() {}; /* ------------------------------------------------------------------------ */ /* Internal code */ /* ------------------------------------------------------------------------ */ protected: inline void sendEvent(const NewNodesEvent & event) { onNodesAdded (event.getList(), event); } inline void sendEvent(const RemovedNodesEvent & event) { onNodesRemoved(event.getList(), event.getNewNumbering(), event); } inline void sendEvent(const NewElementsEvent & event) { onElementsAdded (event.getList(), event); } inline void sendEvent(const RemovedElementsEvent & event) { onElementsRemoved(event.getList(), event.getNewNumbering(), event); } template friend class EventHandlerManager; /* ------------------------------------------------------------------------ */ /* Interface */ /* ------------------------------------------------------------------------ */ public: virtual void onNodesAdded (__attribute__((unused)) const Array & nodes_list, __attribute__((unused)) const NewNodesEvent & event) { } virtual void onNodesRemoved(__attribute__((unused)) const Array & nodes_list, __attribute__((unused)) const Array & new_numbering, __attribute__((unused)) const RemovedNodesEvent & event) { } virtual void onElementsAdded (__attribute__((unused)) const Array & elements_list, __attribute__((unused)) const NewElementsEvent & event) { } virtual void onElementsRemoved(__attribute__((unused)) const Array & elements_list, __attribute__((unused)) const ByElementTypeUInt & new_numbering, __attribute__((unused)) const RemovedElementsEvent & event) { } }; /* -------------------------------------------------------------------------- */ /* Mesh */ /* -------------------------------------------------------------------------- */ /** * @class Mesh this contain the coordinates of the nodes in the Mesh.nodes * Array, and the connectivity. The connectivity are stored in by element * types. * * To know all the element types present in a mesh you can get the * Mesh::ConnectivityTypeList * * In order to loop on all element you have to loop on all types like this : * @code{.cpp} Mesh::type_iterator it = mesh.firstType(dim, ghost_type); Mesh::type_iterator end = mesh.lastType(dim, ghost_type); for(; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it); const Array & conn = mesh.getConnectivity(*it); for(UInt e = 0; e < nb_element; ++e) { ... } } @endcode */ class Mesh : protected Memory, public EventHandlerManager, public GroupManager { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: /// constructor that create nodes coordinates array Mesh(UInt spatial_dimension, const ID id = "mesh", const MemoryID & memory_id = 0); /// constructor that use an existing nodes coordinates array, by knowing its ID Mesh(UInt spatial_dimension, const ID & nodes_id, const ID & id, const MemoryID & memory_id); /** * constructor that use an existing nodes coordinates * array, by getting the vector of coordinates */ Mesh(UInt spatial_dimension, Array & nodes, const ID & id = "mesh", const MemoryID & memory_id = 0); virtual ~Mesh(); /// @typedef ConnectivityTypeList list of the types present in a Mesh typedef std::set ConnectivityTypeList; /// read the mesh from a file void read (const std::string & filename, const MeshIOType & mesh_io_type = _miot_auto); /// write the mesh to a file void write(const std::string & filename, const MeshIOType & mesh_io_type = _miot_auto); private: /// initialize the connectivity to NULL and other stuff void init(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; /// function that computes the bounding box (fills xmin, xmax) void computeBoundingBox(); #ifdef AKANTU_CORE_CXX11 /// translate the mesh by the given amount in x[, y[, z]] directions template void translate(Args... params); #endif /// init a by-element-type real vector with provided ids template void initByElementTypeArray(ByElementTypeArray & v, UInt nb_component, UInt spatial_dimension, const bool & flag_nb_node_per_elem_multiply = false, ElementKind element_kind = _ek_regular, bool size_to_nb_element = false) const; /// @todo: think about nicer way to do it template void initByElementTypeArray(ByElementTypeArray & v, UInt nb_component, UInt spatial_dimension, GhostType ghost_type, const bool & flag_nb_node_per_elem_multiply = false, ElementKind element_kind = _ek_regular, bool size_to_nb_element = false) const; /// @todo: think about nicer way to do it /// extract coordinates of nodes from an element template inline void extractNodalValuesFromElement(const Array & nodal_values, T * elemental_values, UInt * connectivity, UInt n_nodes, UInt nb_degree_of_freedom) const; /// extract coordinates of nodes from a reversed element inline void extractNodalCoordinatesFromPBCElement(Real * local_coords, UInt * connectivity, UInt n_nodes); /// convert a element to a linearized element inline UInt elementToLinearized(const Element & elem) const; /// convert a linearized element to an element inline Element linearizedToElement (UInt linearized_element) const; /// update the types offsets array for the conversions inline void updateTypesOffsets(const GhostType & ghost_type); /// add a Array of connectivity for the type . inline void addConnectivityType(const ElementType & type, const GhostType & ghost_type = _not_ghost); /* ------------------------------------------------------------------------ */ template inline void sendEvent(Event & event) { // if(event.getList().getSize() != 0) EventHandlerManager::sendEvent(event); } /* ------------------------------------------------------------------------ */ template inline void removeNodesFromArray(Array & vect, const Array & new_numbering); /// initialize normals void initNormals(); /// init facets' mesh Mesh & initMeshFacets(const ID & id = "mesh_facets"); /// get global connectivity array void getGlobalConnectivity(Array & global_connectivity, ElementType type, GhostType ghost_type); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the id of the mesh AKANTU_GET_MACRO(ID, Memory::id, const ID &); /// get the spatial dimension of the mesh = number of component of the coordinates AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// get the nodes Array aka coordinates AKANTU_GET_MACRO(Nodes, *nodes, const Array &); AKANTU_GET_MACRO_NOT_CONST(Nodes, *nodes, Array &); /// get the normals for the elements AKANTU_GET_MACRO_BY_ELEMENT_TYPE(Normals, normals, Real); /// get the number of nodes AKANTU_GET_MACRO(NbNodes, nodes->getSize(), UInt); /// get the Array of global ids of the nodes (only used in parallel) AKANTU_GET_MACRO(GlobalNodesIds, *nodes_global_ids, const Array &); /// get the global id of a node inline UInt getNodeGlobalId(UInt local_id) const; /// get the global number of nodes inline UInt getNbGlobalNodes() const; /// get the nodes type Array AKANTU_GET_MACRO(NodesType, *nodes_type, const Array &); inline Int getNodeType(UInt local_id) const; /// say if a node is a pure ghost node inline bool isPureGhostNode(UInt n) const; /// say if a node is pur local or master node inline bool isLocalOrMasterNode(UInt n) const; inline bool isLocalNode(UInt n) const; inline bool isMasterNode(UInt n) const; inline bool isSlaveNode(UInt n) const; AKANTU_GET_MACRO(XMin, lower_bounds[0], Real); AKANTU_GET_MACRO(YMin, lower_bounds[1], Real); AKANTU_GET_MACRO(ZMin, lower_bounds[2], Real); AKANTU_GET_MACRO(XMax, upper_bounds[0], Real); AKANTU_GET_MACRO(YMax, upper_bounds[1], Real); AKANTU_GET_MACRO(ZMax, upper_bounds[2], Real); inline void getLowerBounds(Real * lower) const; inline void getUpperBounds(Real * upper) const; inline void getLocalLowerBounds(Real * lower) const; inline void getLocalUpperBounds(Real * upper) const; /// get the connectivity Array for a given type AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Connectivity, connectivities, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(Connectivity, connectivities, UInt); AKANTU_GET_MACRO(Connectivities, connectivities, const ByElementTypeArray &); /// get the number of element of a type in the mesh inline UInt getNbElement(const ElementType & type, const GhostType & ghost_type = _not_ghost) const; /// get the number of element for a given ghost_type and a given dimension inline UInt getNbElement(const UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost) const; /// get the connectivity list either for the elements or the ghost elements inline const ConnectivityTypeList & getConnectivityTypeList(const GhostType & ghost_type = _not_ghost) const; /// compute the barycenter of a given element inline void getBarycenter(UInt element, const ElementType & type, Real * barycenter, GhostType ghost_type = _not_ghost) const; inline void getBarycenter(const Element & element, Vector & barycenter) const; /// get the element connected to a subelement const Array< std::vector > & getElementToSubelement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get the element connected to a subelement Array< std::vector > & getElementToSubelement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost); /// get the subelement connected to an element const Array & getSubelementToElement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get the subelement connected to an element Array & getSubelementToElement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost); /// get a name field associated to the mesh template inline const Array & getData(const std::string & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get a name field associated to the mesh template inline Array & getData(const std::string & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost); /// get a name field associated to the mesh template inline const ByElementTypeArray & getData(const std::string & data_name) const; /// get a name field associated to the mesh template inline ByElementTypeArray & getData(const std::string & data_name); /// templated getter returning the pointer to data in MeshData (modifiable) template inline Array * getDataPointer(const std::string & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost, UInt nb_component = 1); /// Facets mesh accessor AKANTU_GET_MACRO(MeshFacets, *mesh_facets, const Mesh &); AKANTU_GET_MACRO_NOT_CONST(MeshFacets, *mesh_facets, Mesh &); /// Parent mesh accessor AKANTU_GET_MACRO(MeshParent, *mesh_parent, const Mesh &); AKANTU_GET_MACRO_NOT_CONST(MeshParent, *mesh_parent, Mesh &); inline bool isMeshFacets() const {return is_mesh_facets;} /* ------------------------------------------------------------------------ */ /* Wrappers on ElementClass functions */ /* ------------------------------------------------------------------------ */ public: /// get the number of nodes per element for a given element type static inline UInt getNbNodesPerElement(const ElementType & type); /// get the number of nodes per element for a given element type considered as /// a first order element static inline ElementType getP1ElementType(const ElementType & type); /// get the kind of the element type static inline ElementKind getKind(const ElementType & type); /// get spatial dimension of a type of element static inline UInt getSpatialDimension(const ElementType & type); /// get number of facets of a given element type static inline UInt getNbFacetsPerElement(const ElementType & type); /// get local connectivity of a facet for a given facet type static inline Matrix getFacetLocalConnectivity(const ElementType & type); /// get connectivity of facets for a given element inline Matrix getFacetConnectivity(UInt element, const ElementType & type, const GhostType & ghost_type) const; /// get the type of the surface element associated to a given element static inline ElementType getFacetType(const ElementType & type); /* ------------------------------------------------------------------------ */ /* Element type Iterator */ /* ------------------------------------------------------------------------ */ typedef ByElementTypeArray::type_iterator type_iterator; inline type_iterator firstType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) const { return connectivities.firstType(dim, ghost_type, kind); } inline type_iterator lastType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) const { return connectivities.lastType(dim, ghost_type, kind); } /* ------------------------------------------------------------------------ */ /* Private methods for friends */ /* ------------------------------------------------------------------------ */ private: friend class MeshIOMSH; friend class MeshIOMSHStruct; friend class MeshIODiana; friend class MeshUtils; friend class DistributedSynchronizer; template friend class SpatialGrid; +#if defined(AKANTU_COHESIVE_ELEMENT) + friend class CohesiveElementInserter; +#endif AKANTU_GET_MACRO(NodesPointer, nodes, Array *); /// get a pointer to the nodes_global_ids Array and create it if necessary inline Array * getNodesGlobalIdsPointer(); /// get a pointer to the nodes_type Array and create it if necessary inline Array * getNodesTypePointer(); /// get a pointer to the connectivity Array for the given type and create it if necessary inline Array * getConnectivityPointer(const ElementType & type, const GhostType & ghost_type = _not_ghost); /// get a pointer to the element_to_subelement Array for the given type and create it if necessary inline Array< std::vector > * getElementToSubelementPointer(const ElementType & type, const GhostType & ghost_type = _not_ghost); /// get a pointer to the subelement_to_element Array for the given type and create it if necessary inline Array * getSubelementToElementPointer(const ElementType & type, const GhostType & ghost_type = _not_ghost); AKANTU_GET_MACRO_NOT_CONST(MeshData, mesh_data, MeshData &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// array of the nodes coordinates Array * nodes; /// global node ids Array * nodes_global_ids; /// node type, -3 pure ghost, -2 master for the node, -1 normal node, i in /// [0-N] slave node and master is proc i Array * nodes_type; /// global number of nodes; UInt nb_global_nodes; /// boolean to know if the nodes have to be deleted with the mesh or not bool created_nodes; /// all class of elements present in this mesh (for heterogenous meshes) ByElementTypeUInt connectivities; /// map to normals for all class of elements present in this mesh ByElementTypeReal normals; /// list of all existing types in the mesh ConnectivityTypeList type_set; /// the spatial dimension of this mesh UInt spatial_dimension; /// types offsets Array types_offsets; /// list of all existing types in the mesh ConnectivityTypeList ghost_type_set; /// ghost types offsets Array ghost_types_offsets; /// min of coordinates Real lower_bounds[3]; /// max of coordinates Real upper_bounds[3]; /// size covered by the mesh on each direction Real size[3]; /// local min of coordinates Real local_lower_bounds[3]; /// local max of coordinates Real local_upper_bounds[3]; /// Extra data loaded from the mesh file MeshData mesh_data; /// Group manager for nodes and elements groups in the mesh // GroupManager group_manager; /// facets' mesh Mesh * mesh_facets; /// parent mesh (this is set for mesh_facets meshes) Mesh * mesh_parent; /// defines if current mesh is mesh_facets or not bool is_mesh_facets; }; /* -------------------------------------------------------------------------- */ /* Inline functions */ /* -------------------------------------------------------------------------- */ /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const Element & _this) { _this.printself(stream); return stream; } #include "mesh_inline_impl.cc" #include "by_element_type_tmpl.hh" /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const Mesh & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #endif /* __AKANTU_MESH_HH__ */ diff --git a/src/mesh_utils/cohesive_element_inserter.cc b/src/mesh_utils/cohesive_element_inserter.cc new file mode 100644 index 000000000..6b0b56e2a --- /dev/null +++ b/src/mesh_utils/cohesive_element_inserter.cc @@ -0,0 +1,375 @@ +/** + * @file cohesive_element_inserter.cc + * @author Marco Vocialta + * @date Fri Nov 29 17:16:03 2013 + * + * @brief Cohesive element inserter functions + * + * @section LICENSE + * + * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see . + * + */ + +/* -------------------------------------------------------------------------- */ +#include +#include +#include "cohesive_element_inserter.hh" + +/* -------------------------------------------------------------------------- */ + +__BEGIN_AKANTU__ + +CohesiveElementInserter::CohesiveElementInserter(Mesh & mesh, + Mesh & mesh_facets, + const ID & id) : + id(id), + mesh(mesh), + mesh_facets(&mesh_facets), + insertion_facets("insertion_facets", id), + is_extrinsic(true), + insertion_limits(mesh.getSpatialDimension(), 2), + check_facets("check_facets", id) { } + +/* -------------------------------------------------------------------------- */ +CohesiveElementInserter::CohesiveElementInserter(Mesh & mesh, + const ID & id) : + id(id), + mesh(mesh), + insertion_facets("insertion_facets", id), + is_extrinsic(false), + insertion_limits(mesh.getSpatialDimension(), 2), + check_facets("check_facets", id) { + + mesh_facets = new Mesh(mesh.initMeshFacets()); + MeshUtils::buildAllFacets(mesh, *mesh_facets); + + init(); +} + +/* -------------------------------------------------------------------------- */ +CohesiveElementInserter::~CohesiveElementInserter() { + if (!is_extrinsic) delete mesh_facets; + +#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) + delete distributed_synchronizer; + delete synch_registry; +#endif +} + +/* -------------------------------------------------------------------------- */ +void CohesiveElementInserter::init() { + AKANTU_DEBUG_IN(); + + UInt spatial_dimension = mesh.getSpatialDimension(); + + MeshUtils::resetFacetToDouble(*mesh_facets); + + /// initialize facet insertion array + mesh_facets->initByElementTypeArray(insertion_facets, 1, + spatial_dimension - 1, + false, + _ek_regular, + true); + + /// init insertion limits + for (UInt dim = 0; dim < spatial_dimension; ++dim) { + insertion_limits(dim, 0) = std::numeric_limits::max() * (-1.); + insertion_limits(dim, 1) = std::numeric_limits::max(); + } + + if (is_extrinsic) { + mesh_facets->initByElementTypeArray(check_facets, 1, spatial_dimension - 1); + initFacetsCheck(); + } + +#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) + synch_registry = NULL; + facet_synchronizer = NULL; + distributed_synchronizer = NULL; +#endif + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +void CohesiveElementInserter::initFacetsCheck() { + AKANTU_DEBUG_IN(); + + UInt spatial_dimension = mesh.getSpatialDimension(); + + for (ghost_type_t::iterator gt = ghost_type_t::begin(); + gt != ghost_type_t::end(); ++gt) { + + GhostType facet_gt = *gt; + Mesh::type_iterator it = mesh_facets->firstType(spatial_dimension - 1, facet_gt); + Mesh::type_iterator last = mesh_facets->lastType(spatial_dimension - 1, facet_gt); + + for (; it != last; ++it) { + ElementType facet_type = *it; + + Array & f_check = check_facets(facet_type, facet_gt); + + const Array< std::vector > & element_to_facet + = mesh_facets->getElementToSubelement(facet_type, facet_gt); + + UInt nb_facet = element_to_facet.getSize(); + f_check.resize(nb_facet); + + for (UInt f = 0; f < nb_facet; ++f) { + if (element_to_facet(f)[1] == ElementNull || + (element_to_facet(f)[0].ghost_type == _ghost && + element_to_facet(f)[1].ghost_type == _ghost)) { + f_check(f) = false; + } + else f_check(f) = true; + } + } + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +void CohesiveElementInserter::limitCheckFacets() { + AKANTU_DEBUG_IN(); + + UInt spatial_dimension = mesh.getSpatialDimension(); + Vector bary_facet(spatial_dimension); + + for (ghost_type_t::iterator gt = ghost_type_t::begin(); + gt != ghost_type_t::end(); + ++gt) { + GhostType ghost_type = *gt; + + Mesh::type_iterator it = mesh_facets->firstType(spatial_dimension - 1, ghost_type); + Mesh::type_iterator end = mesh_facets->lastType(spatial_dimension - 1, ghost_type); + for(; it != end; ++it) { + ElementType type = *it; + Array & f_check = check_facets(type, ghost_type); + UInt nb_facet = mesh_facets->getNbElement(type, ghost_type); + + for (UInt f = 0; f < nb_facet; ++f) { + if (f_check(f)) { + + mesh_facets->getBarycenter(f, type, bary_facet.storage(), ghost_type); + + UInt coord_in_limit = 0; + + while (coord_in_limit < spatial_dimension && + bary_facet(coord_in_limit) > insertion_limits(coord_in_limit, 0) && + bary_facet(coord_in_limit) < insertion_limits(coord_in_limit, 1)) + ++coord_in_limit; + + if (coord_in_limit != spatial_dimension) + f_check(f) = false; + + } + } + } + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +void CohesiveElementInserter::setLimit(char direction, + Real first_limit, + Real second_limit) { + UInt direction_index; + + switch(direction) { + case 'x': + direction_index = 0; break; + case 'y': + direction_index = 1; break; + case 'z': + direction_index = 2; break; + default: + /// assign dummy value + direction_index = 10; + } + + AKANTU_DEBUG_ASSERT(direction_index < mesh.getSpatialDimension(), + "Specify the direction as 'x', 'y' or 'z' according to the mesh spatial dimension"); + + insertion_limits(direction_index, 0) = std::min(first_limit, second_limit); + insertion_limits(direction_index, 1) = std::max(first_limit, second_limit); +} + +/* -------------------------------------------------------------------------- */ +void CohesiveElementInserter::insertIntrinsicElements() { + AKANTU_DEBUG_IN(); + + UInt spatial_dimension = mesh.getSpatialDimension(); + + Vector bary_facet(spatial_dimension); + + Mesh::type_iterator it = mesh_facets->firstType(spatial_dimension - 1); + Mesh::type_iterator end = mesh_facets->lastType(spatial_dimension - 1); + + for(; it != end; ++it) { + const ElementType type_facet = *it; + Array & f_insertion = insertion_facets(type_facet); + Array > & element_to_facet + = mesh_facets->getElementToSubelement(type_facet); + + UInt nb_facet = mesh_facets->getNbElement(type_facet); + + for (UInt f = 0; f < nb_facet; ++f) { + + if (element_to_facet(f)[1] == ElementNull) continue; + + mesh_facets->getBarycenter(f, type_facet, bary_facet.storage()); + + UInt coord_in_limit = 0; + + while (coord_in_limit < spatial_dimension && + bary_facet(coord_in_limit) > insertion_limits(coord_in_limit, 0) && + bary_facet(coord_in_limit) < insertion_limits(coord_in_limit, 1)) + ++coord_in_limit; + + if (coord_in_limit == spatial_dimension) + f_insertion(f) = true; + } + } + + NewNodesEvent node_event; + node_event.getList().extendComponentsInterlaced(2, 1); + NewElementsEvent element_event; + + MeshUtils::insertCohesiveElements(mesh, + *mesh_facets, + insertion_facets, + node_event.getList(), + element_event.getList()); + + UInt nb_new_nodes = node_event.getList().getSize(); + + mesh.nb_global_nodes += nb_new_nodes; + mesh_facets->nb_global_nodes += nb_new_nodes; + + mesh.sendEvent(node_event); + mesh.updateTypesOffsets(_not_ghost); + mesh.sendEvent(element_event); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +void CohesiveElementInserter::insertExtrinsicElements() { + AKANTU_DEBUG_IN(); + + NewNodesEvent node_event; + node_event.getList().extendComponentsInterlaced(2, 1); + NewElementsEvent element_event; + + MeshUtils::insertCohesiveElements(mesh, + *mesh_facets, + insertion_facets, + node_event.getList(), + element_event.getList()); + + UInt nb_new_nodes = node_event.getList().getSize(); + UInt nb_new_elements = element_event.getList().getSize(); + +#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) + if (mesh.nodes_type) { + /// update global ids + nb_new_nodes = updateGlobalIDs(node_event); + + /// compute total number of new elements + StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + comm.allReduce(&nb_new_elements, 1, _so_sum); + } +#endif + + if (nb_new_nodes > 0) { + mesh.nb_global_nodes += nb_new_nodes; + mesh_facets->nb_global_nodes += nb_new_nodes; + mesh.sendEvent(node_event); + } + + if (nb_new_elements > 0) { + updateInsertionFacets(); + mesh.updateTypesOffsets(_not_ghost); + mesh.sendEvent(element_event); + MeshUtils::resetFacetToDouble(*mesh_facets); + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +void CohesiveElementInserter::updateInsertionFacets() { + AKANTU_DEBUG_IN(); + + UInt spatial_dimension = mesh.getSpatialDimension(); + + for (ghost_type_t::iterator gt = ghost_type_t::begin(); + gt != ghost_type_t::end(); ++gt) { + + GhostType facet_gt = *gt; + Mesh::type_iterator it = mesh_facets->firstType(spatial_dimension - 1, facet_gt); + Mesh::type_iterator last = mesh_facets->lastType(spatial_dimension - 1, facet_gt); + + for (; it != last; ++it) { + ElementType facet_type = *it; + + Array & f_check = check_facets(facet_type, facet_gt); + Array & ins_facets = insertion_facets(facet_type, facet_gt); + + UInt nb_facets = f_check.getSize(); + + for (UInt f = 0; f < ins_facets.getSize(); ++f) { + if (ins_facets(f)) { + ++nb_facets; + ins_facets(f) = false; + f_check(f) = false; + } + } + + f_check.resize(nb_facets); + } + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +void CohesiveElementInserter::printself(std::ostream & stream, int indent) const { + std::string space; + for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); + + stream << space << "CohesiveElementInserter [" << std::endl; + + stream << space << " + mesh [" << std::endl; + mesh.printself(stream, indent + 2); + stream << space << AKANTU_INDENT << "]" << std::endl; + + stream << space << " + mesh_facets [" << std::endl; + mesh_facets->printself(stream, indent + 2); + stream << space << AKANTU_INDENT << "]" << std::endl; + + stream << space << " + is_extrinsic : " << is_extrinsic << std::endl; + + stream << space << "]" << std::endl; +} + + + +__END_AKANTU__ diff --git a/src/mesh_utils/cohesive_element_inserter.hh b/src/mesh_utils/cohesive_element_inserter.hh new file mode 100644 index 000000000..33c2a93bc --- /dev/null +++ b/src/mesh_utils/cohesive_element_inserter.hh @@ -0,0 +1,195 @@ +/** + * @file cohesive_element_inserter.hh + * @author Marco Vocialta + * @date Fri Nov 29 17:03:59 2013 + * + * @brief Cohesive element inserter + * + * @section LICENSE + * + * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see . + * + */ + +/* -------------------------------------------------------------------------- */ +#ifndef __AKANTU_COHESIVE_ELEMENT_INSERTER_HH__ +#define __AKANTU_COHESIVE_ELEMENT_INSERTER_HH__ + +/* -------------------------------------------------------------------------- */ +#include +#include "data_accessor.hh" +#include "mesh_utils.hh" + +#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) +# include "synchronizer_registry.hh" +# include "facet_synchronizer.hh" +#endif + +/* -------------------------------------------------------------------------- */ +__BEGIN_AKANTU__ + +class CohesiveElementInserter : public DataAccessor { + /* ------------------------------------------------------------------------ */ + /* Constructors/Destructors */ + /* ------------------------------------------------------------------------ */ +public: + + /// constructor for extrinsic + CohesiveElementInserter(Mesh & mesh, + Mesh & mesh_facets, + const ID & id = "cohesive_element_inserter"); + + /// constructor for intrinsic + CohesiveElementInserter(Mesh & mesh, + const ID & id = "cohesive_element_inserter"); + + virtual ~CohesiveElementInserter(); + + /* ------------------------------------------------------------------------ */ + /* Methods */ + /* ------------------------------------------------------------------------ */ +public: + + /// init function + void init(); + + /// set range limitation for intrinsic cohesive element insertion + void setLimit(char direction, Real first_limit, Real second_limit); + + /// insert intrinsic cohesive elements in a predefined range + void insertIntrinsicElements(); + + /// insert extrinsic cohesive elements + void insertExtrinsicElements(); + + /// function to print the contain of the class + virtual void printself(std::ostream & stream, int indent = 0) const; + + /// limit check facets to match given insertion limits + void limitCheckFacets(); + +#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) + /// init parallel variables + void initParallel(FacetSynchronizer * facet_synchronizer); +#endif + +protected: + + /// init facets check + void initFacetsCheck(); + + /// update facet insertion arrays after facets doubling + void updateInsertionFacets(); + +#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) + /// update nodes type and global ids for parallel simulations + UInt updateGlobalIDs(NewNodesEvent & node_event); + + /// functions for parallel communications + inline UInt getNbDataForElements(const Array & elements, + SynchronizationTag tag) const; + + inline void packElementData(CommunicationBuffer & buffer, + const Array & elements, + SynchronizationTag tag) const; + + inline void unpackElementData(CommunicationBuffer & buffer, + const Array & elements, + SynchronizationTag tag); + + template + inline void packUnpackGlobalConnectivity(CommunicationBuffer & buffer, + const Array & elements) const; +#endif + + /* ------------------------------------------------------------------------ */ + /* Accessors */ + /* ------------------------------------------------------------------------ */ +public: + + AKANTU_GET_MACRO_NOT_CONST(InsertionFacetsByElement, + insertion_facets, + ByElementTypeArray &); + + AKANTU_GET_MACRO(InsertionFacetsByElement, + insertion_facets, + const ByElementTypeArray &); + + AKANTU_GET_MACRO_BY_ELEMENT_TYPE(InsertionFacets, insertion_facets, bool); + + AKANTU_GET_MACRO_BY_ELEMENT_TYPE(CheckFacets, check_facets, bool); + AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(CheckFacets, check_facets, bool); + + /* ------------------------------------------------------------------------ */ + /* Class Members */ + /* ------------------------------------------------------------------------ */ +private: + + /// object id + ID id; + + /// main mesh where to insert cohesive elements + Mesh & mesh; + + /// mesh containing facets + Mesh * mesh_facets; + + /// list of facets where to insert elements + ByElementTypeArray insertion_facets; + + /// tag to distinguish extrinsic simulations (true by default) + bool is_extrinsic; + + /// limits for element insertion + Array insertion_limits; + + /// vector containing facets in which extrinsic cohesive elements can be inserted + ByElementTypeArray check_facets; + +#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) + /// synchronizer registry + SynchronizerRegistry * synch_registry; + + /// facet synchronizer + FacetSynchronizer * facet_synchronizer; + + /// distributed synchronizer + DistributedSynchronizer * distributed_synchronizer; +#endif +}; + + +/* -------------------------------------------------------------------------- */ +/* inline functions */ +/* -------------------------------------------------------------------------- */ + +#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) +# include "cohesive_element_inserter_inline_impl.cc" +#endif + +/// standard output stream operator +inline std::ostream & operator <<(std::ostream & stream, const CohesiveElementInserter & _this) +{ + _this.printself(stream); + return stream; +} + + +__END_AKANTU__ + + +#endif /* __AKANTU_COHESIVE_ELEMENT_INSERTER_HH__ */ diff --git a/src/mesh_utils/cohesive_element_inserter_inline_impl.cc b/src/mesh_utils/cohesive_element_inserter_inline_impl.cc new file mode 100644 index 000000000..d468e0d83 --- /dev/null +++ b/src/mesh_utils/cohesive_element_inserter_inline_impl.cc @@ -0,0 +1,135 @@ +/** + * @file cohesive_element_inserter_inline_impl.cc + * @author Marco Vocialta + * @date Tue Dec 3 15:20:53 2013 + * + * @brief Cohesive element inserter inline functions + * + * @section LICENSE + * + * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see . + * + */ + +/* -------------------------------------------------------------------------- */ +#include "cohesive_element_inserter.hh" + +/* -------------------------------------------------------------------------- */ +inline UInt CohesiveElementInserter::getNbDataForElements(const Array & elements, + SynchronizationTag tag) const { + AKANTU_DEBUG_IN(); + + UInt size = 0; + + if (tag == _gst_inserter) { + UInt nb_nodes = 0; + + Array::const_iterator it = elements.begin(); + Array::const_iterator end = elements.end(); + for (; it != end; ++it) { + const Element & el = *it; + nb_nodes += Mesh::getNbNodesPerElement(el.type); + } + + size += nb_nodes * sizeof(UInt); + } + + AKANTU_DEBUG_OUT(); + return size; +} + +/* -------------------------------------------------------------------------- */ +inline void CohesiveElementInserter::packElementData(CommunicationBuffer & buffer, + const Array & elements, + SynchronizationTag tag) const { + AKANTU_DEBUG_IN(); + + if (tag == _gst_inserter) + packUnpackGlobalConnectivity(buffer, elements); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +inline void CohesiveElementInserter::unpackElementData(CommunicationBuffer & buffer, + const Array & elements, + SynchronizationTag tag) { + AKANTU_DEBUG_IN(); + + if (tag == _gst_inserter) + packUnpackGlobalConnectivity(buffer, elements); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +template +inline void CohesiveElementInserter::packUnpackGlobalConnectivity(CommunicationBuffer & buffer, + const Array & elements) const { + AKANTU_DEBUG_IN(); + + ElementType current_element_type = _not_defined; + GhostType current_ghost_type = _casper; + + Array::iterator > conn_begin; + UInt nb_nodes_per_elem = 0; + UInt index; + + Array::const_iterator it = elements.begin(); + Array::const_iterator end = elements.end(); + for (; it != end; ++it) { + const Element & el = *it; + + if (el.type != current_element_type || el.ghost_type != current_ghost_type) { + current_element_type = el.type; + current_ghost_type = el.ghost_type; + + nb_nodes_per_elem = Mesh::getNbNodesPerElement(current_element_type); + + conn_begin = mesh.connectivities(current_element_type, + current_ghost_type).begin(nb_nodes_per_elem); + } + + /// get element connectivity + Vector & current_conn = conn_begin[el.element]; + + /// loop on all connectivity nodes + for (UInt n = 0; n < nb_nodes_per_elem; ++n) { + UInt node = current_conn(n); + + if (pack_mode) { + /// if node is local or master pack its global id, otherwise + /// dummy data + if (mesh.isLocalOrMasterNode(node)) + index = mesh.getNodeGlobalId(node); + else + index = UInt(-1); + + buffer << index; + } + else { + buffer >> index; + + /// update slave nodes' index + if (index != UInt(-1) && mesh.isSlaveNode(node)) + (*mesh.nodes_global_ids)(node) = index; + } + } + } + + AKANTU_DEBUG_OUT(); +} diff --git a/src/mesh_utils/cohesive_element_inserter_parallel.cc b/src/mesh_utils/cohesive_element_inserter_parallel.cc new file mode 100644 index 000000000..4d0eb2bf4 --- /dev/null +++ b/src/mesh_utils/cohesive_element_inserter_parallel.cc @@ -0,0 +1,118 @@ +/** + * @file cohesive_element_inserter_parallel.cc + * @author Marco Vocialta + * @date Tue Dec 3 14:35:38 2013 + * + * @brief Parallel functions for the cohesive element inserter + * + * @section LICENSE + * + * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) + * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) + * + * Akantu is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Akantu. If not, see . + * + */ + +/* -------------------------------------------------------------------------- */ +#include "cohesive_element_inserter.hh" + +__BEGIN_AKANTU__ + +/* -------------------------------------------------------------------------- */ +void CohesiveElementInserter::initParallel(FacetSynchronizer * facet_synchronizer) { + AKANTU_DEBUG_IN(); + + synch_registry = new SynchronizerRegistry(*this); + this->facet_synchronizer = facet_synchronizer; + + distributed_synchronizer + = new DistributedSynchronizer(mesh, "inserter_synchronizer"); + + synch_registry->registerSynchronizer(*distributed_synchronizer, + _gst_inserter); + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +UInt CohesiveElementInserter::updateGlobalIDs(NewNodesEvent & node_event) { + AKANTU_DEBUG_IN(); + + Array & doubled_nodes = node_event.getList(); + UInt local_nb_new_nodes = doubled_nodes.getSize(); + + StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); + Int rank = comm.whoAmI(); + Int nb_proc = comm.getNbProc(); + + /// update nodes' type + Array & nodes_type = *mesh.nodes_type; + UInt nb_old_nodes = nodes_type.getSize(); + nodes_type.resize(nb_old_nodes + local_nb_new_nodes); + + for (UInt n = 0; n < local_nb_new_nodes; ++n) { + UInt old_node = doubled_nodes(n, 0); + UInt new_node = doubled_nodes(n, 1); + nodes_type(new_node) = nodes_type(old_node); + } + + /// resize global ids array + Array & nodes_global_ids = *mesh.nodes_global_ids; + nodes_global_ids.resize(nb_old_nodes + local_nb_new_nodes); + + /// compute amount of local or master doubled nodes + Vector local_master_nodes(nb_proc); + + for (UInt n = 0; n < local_nb_new_nodes; ++n) { + UInt old_node = doubled_nodes(n, 0); + if (mesh.isLocalOrMasterNode(old_node)) ++local_master_nodes(rank); + } + + comm.allGather(local_master_nodes.storage(), 1); + + /// update global number of nodes + UInt total_nb_new_nodes = std::accumulate(local_master_nodes.storage(), + local_master_nodes.storage() + nb_proc, + 0); + + if (total_nb_new_nodes == 0) return 0; + + /// set global ids of local and master nodes + UInt starting_index = std::accumulate(local_master_nodes.storage(), + local_master_nodes.storage() + rank, + mesh.nb_global_nodes); + + for (UInt n = 0; n < local_nb_new_nodes; ++n) { + UInt new_node = doubled_nodes(n, 1); + if (mesh.isLocalOrMasterNode(new_node)) { + nodes_global_ids(new_node) = starting_index; + ++starting_index; + } + } + + /// update distributed synchronizer + distributed_synchronizer->reset(); + facet_synchronizer->updateDistributedSynchronizer(*distributed_synchronizer, + *this, mesh); + + /// communicate global ids + synch_registry->synchronize(_gst_inserter); + + AKANTU_DEBUG_OUT(); + return total_nb_new_nodes; +} + + +__END_AKANTU__ diff --git a/src/mesh_utils/mesh_utils.cc b/src/mesh_utils/mesh_utils.cc index 013ac4d06..25a231aac 100644 --- a/src/mesh_utils/mesh_utils.cc +++ b/src/mesh_utils/mesh_utils.cc @@ -1,2449 +1,2104 @@ /** * @file mesh_utils.cc * * @author Guillaume Anciaux * @author David Simon Kammer * @author Leonardo Snozzi * @author Nicolas Richart * @author Marco Vocialta * * @date Fri Aug 20 12:19:44 2010 * * @brief All mesh utils necessary for various tasks * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #include "mesh_utils.hh" #include "aka_safe_enum.hh" #include "fem.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ void MeshUtils::buildNode2Elements(const Mesh & mesh, CSR & node_to_elem, UInt spatial_dimension) { AKANTU_DEBUG_IN(); if (spatial_dimension == _all_dimensions) spatial_dimension = mesh.getSpatialDimension(); /// count number of occurrence of each node UInt nb_nodes = mesh.getNbNodes(); /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); AKANTU_DEBUG_ASSERT(mesh.firstType(spatial_dimension) != mesh.lastType(spatial_dimension), "Some elements must be found in right dimension to compute facets!"); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator first = mesh.firstType(spatial_dimension, *gt); Mesh::type_iterator last = mesh.lastType(spatial_dimension, *gt); for (; first != last; ++first) { ElementType type = *first; UInt nb_element = mesh.getNbElement(type, *gt); Array::const_iterator< Vector > conn_it = mesh.getConnectivity(type, *gt).begin(Mesh::getNbNodesPerElement(type)); for (UInt el = 0; el < nb_element; ++el, ++conn_it) for (UInt n = 0; n < conn_it->size(); ++n) ++node_to_elem.rowOffset((*conn_it)(n)); } } node_to_elem.countToCSR(); node_to_elem.resizeCols(); /// rearrange element to get the node-element list Element e; node_to_elem.beginInsertions(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator first = mesh.firstType(spatial_dimension, *gt); Mesh::type_iterator last = mesh.lastType(spatial_dimension, *gt); e.ghost_type = *gt; for (; first != last; ++first) { ElementType type = *first; e.type = type; UInt nb_element = mesh.getNbElement(type, *gt); Array::const_iterator< Vector > conn_it = mesh.getConnectivity(type, *gt).begin(Mesh::getNbNodesPerElement(type)); for (UInt el = 0; el < nb_element; ++el, ++conn_it) { e.element = el; for (UInt n = 0; n < conn_it->size(); ++n) node_to_elem.insertInRow((*conn_it)(n), e); } } } node_to_elem.endInsertions(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * This function should disappear in the future */ void MeshUtils::buildNode2Elements(const Mesh & mesh, CSR & node_to_elem, UInt spatial_dimension) { AKANTU_DEBUG_IN(); if (spatial_dimension == _all_dimensions) spatial_dimension = mesh.getSpatialDimension(); UInt nb_nodes = mesh.getNbNodes(); const Mesh::ConnectivityTypeList & type_list = mesh.getConnectivityTypeList(); Mesh::ConnectivityTypeList::const_iterator it; UInt nb_types = type_list.size(); UInt nb_good_types = 0; UInt nb_nodes_per_element[nb_types]; UInt * conn_val[nb_types]; UInt nb_element[nb_types]; for(it = type_list.begin(); it != type_list.end(); ++it) { ElementType type = *it; if(Mesh::getSpatialDimension(type) != spatial_dimension) continue; nb_nodes_per_element[nb_good_types] = Mesh::getNbNodesPerElement(type); conn_val[nb_good_types] = mesh.getConnectivity(type, _not_ghost).values; nb_element[nb_good_types] = mesh.getConnectivity(type, _not_ghost).getSize(); nb_good_types++; } AKANTU_DEBUG_ASSERT(nb_good_types != 0, "Some elements must be found in right dimension to compute facets!"); /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); /// count number of occurrence of each node for (UInt t = 0; t < nb_good_types; ++t) { for (UInt el = 0; el < nb_element[t]; ++el) { UInt el_offset = el*nb_nodes_per_element[t]; for (UInt n = 0; n < nb_nodes_per_element[t]; ++n) { ++node_to_elem.rowOffset(conn_val[t][el_offset + n]); } } } node_to_elem.countToCSR(); node_to_elem.resizeCols(); node_to_elem.beginInsertions(); /// rearrange element to get the node-element list for (UInt t = 0, linearized_el = 0; t < nb_good_types; ++t) for (UInt el = 0; el < nb_element[t]; ++el, ++linearized_el) { UInt el_offset = el*nb_nodes_per_element[t]; for (UInt n = 0; n < nb_nodes_per_element[t]; ++n) node_to_elem.insertInRow(conn_val[t][el_offset + n], linearized_el); } node_to_elem.endInsertions(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildNode2ElementsByElementType(const Mesh & mesh, CSR & node_to_elem, const ElementType & type, const GhostType & ghost_type) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_elements = mesh.getConnectivity(type, ghost_type).getSize(); UInt * conn_val = mesh.getConnectivity(type, ghost_type).storage(); /// array for the node-element list node_to_elem.resizeRows(nb_nodes); node_to_elem.clearRows(); /// count number of occurrence of each node for (UInt el = 0; el < nb_elements; ++el) { UInt el_offset = el*nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) ++node_to_elem.rowOffset(conn_val[el_offset + n]); } /// convert the occurrence array in a csr one node_to_elem.countToCSR(); node_to_elem.resizeCols(); node_to_elem.beginInsertions(); /// save the element index in the node-element list for (UInt el = 0; el < nb_elements; ++el) { UInt el_offset = el*nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) { node_to_elem.insertInRow(conn_val[el_offset + n], el); } } node_to_elem.endInsertions(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildFacets(Mesh & mesh){ AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); ByElementTypeUInt prank_to_element("prank_to_elem", mesh.getID()); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh.lastType(spatial_dimension - 1, gt_facet); for(; it != end; ++it) { mesh.getConnectivity(*it, *gt).resize(0); // \todo inform the mesh event handler } } buildFacetsDimension(mesh, mesh, true, spatial_dimension, prank_to_element); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildAllFacets(Mesh & mesh, Mesh & mesh_facets) { AKANTU_DEBUG_IN(); ByElementTypeUInt prank_to_element("prank_to_elem", mesh.getID()); buildAllFacetsParallel(mesh, mesh_facets, prank_to_element); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildAllFacetsParallel(Mesh & mesh, Mesh & mesh_facets, ByElementTypeUInt & prank_to_element) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); /// generate facets buildFacetsDimension(mesh, mesh_facets, false, spatial_dimension, prank_to_element); /// copy nodes type pointer mesh_facets.nodes_type = mesh.nodes_type; /// sort facets and generate subfacets for (UInt i = spatial_dimension - 1; i > 0; --i) { buildFacetsDimension(mesh_facets, mesh_facets, false, i, prank_to_element); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildFacetsDimension(Mesh & mesh, Mesh & mesh_facets, bool boundary_only, UInt dimension, ByElementTypeUInt & prank_to_element){ AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); const Array & mesh_facets_nodes = mesh_facets.getNodes(); const Array::const_iterator< Vector > mesh_facets_nodes_it = mesh_facets_nodes.begin(spatial_dimension); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator first = mesh.firstType(dimension, ghost_type); Mesh::type_iterator last = mesh.lastType(dimension, ghost_type); for(; first != last; ++first) { ElementType type = *first; if(mesh.getSpatialDimension(type) != dimension) continue; ElementType facet_type = mesh.getFacetType(type); UInt nb_element = mesh.getNbElement(type, ghost_type); // getting connectivity of boundary facets Array * connectivity_facets = mesh_facets.getConnectivityPointer(facet_type, ghost_type); connectivity_facets->resize(0); Array< std::vector > * element_to_subelement = mesh_facets.getElementToSubelementPointer(facet_type, ghost_type); element_to_subelement->resize(0); Array * subelement_to_element = mesh_facets.getSubelementToElementPointer(type, ghost_type); subelement_to_element->resize(nb_element); } } CSR node_to_elem; buildNode2Elements(mesh, node_to_elem, dimension); Array counter; Element current_element; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; GhostType facet_ghost_type = ghost_type; current_element.ghost_type = ghost_type; Mesh::type_iterator first = mesh.firstType(dimension, ghost_type); Mesh::type_iterator last = mesh.lastType(dimension, ghost_type); for(; first != last; ++first) { ElementType type = *first; ElementType facet_type = mesh.getFacetType(type); current_element.type = type; UInt nb_element = mesh.getNbElement(type, ghost_type); Array< std::vector > * element_to_subelement = &mesh_facets.getElementToSubelement(facet_type, ghost_type); Array * connectivity_facets = &mesh_facets.getConnectivity(facet_type, ghost_type); for (UInt el = 0; el < nb_element; ++el) { current_element.element = el; Matrix facets = mesh.getFacetConnectivity(el, type, ghost_type); UInt nb_nodes_per_facet = facets.cols(); for (UInt f = 0; f < facets.rows(); ++f) { Vector facet(nb_nodes_per_facet); for (UInt n = 0; n < nb_nodes_per_facet; ++n) facet(n) = facets(f, n); UInt first_node_nb_elements = node_to_elem.getNbCols(facets(f, 0)); counter.resize(first_node_nb_elements); counter.clear(); //loop over the other nodes to search intersecting elements, //which are the elements that share another node with the //starting element after first_node CSR::iterator first_node_elements = node_to_elem.begin(facet(0)); CSR::iterator first_node_elements_end = node_to_elem.end(facet(0)); UInt local_el = 0; for (; first_node_elements != first_node_elements_end; ++first_node_elements, ++local_el) { for (UInt n = 1; n < nb_nodes_per_facet; ++n) { CSR::iterator node_elements_begin = node_to_elem.begin(facet(n)); CSR::iterator node_elements_end = node_to_elem.end (facet(n)); counter(local_el) += std::count(node_elements_begin, node_elements_end, *first_node_elements); } } // counting the number of elements connected to the facets and // taking the minimum element number, because the facet should // be inserted just once UInt nb_element_connected_to_facet = 0; Element minimum_el = ElementNull; Array connected_elements; for (UInt el_f = 0; el_f < first_node_nb_elements; el_f++) { Element real_el = node_to_elem(facet(0), el_f); if (counter(el_f) == nb_nodes_per_facet - 1) { ++nb_element_connected_to_facet; minimum_el = std::min(minimum_el, real_el); connected_elements.push_back(real_el); } } if (minimum_el == current_element) { bool full_ghost_facet = false; UInt n = 0; while (n < nb_nodes_per_facet && mesh.isPureGhostNode(facet(n))) ++n; if (n == nb_nodes_per_facet) full_ghost_facet = true; if (!full_ghost_facet) { if (!boundary_only || (boundary_only && nb_element_connected_to_facet == 1)) { std::vector elements; // build elements_on_facets: linearized_el must come first // in order to store the facet in the correct direction // and avoid to invert the sign in the normal computation elements.push_back(current_element); /// boundary facet if (nb_element_connected_to_facet == 1) elements.push_back(ElementNull); /// internal facet else if (nb_element_connected_to_facet == 2) { elements.push_back(connected_elements(1)); /// check if facet is in between ghost and normal /// elements: if it's the case, the facet is either /// ghost or not ghost. The criterion to decide this /// is arbitrary. It was chosen to check the processor /// id (prank) of the two neighboring elements. If /// prank of the ghost element is lower than prank of /// the normal one, the facet is not ghost, otherwise /// it's ghost GhostType gt[2]; for (UInt el = 0; el < connected_elements.getSize(); ++el) gt[el] = connected_elements(el).ghost_type; if (gt[0] + gt[1] == 1) { try { UInt prank[2]; for (UInt el = 0; el < 2; ++el) { UInt current_el = connected_elements(el).element; ElementType current_type = connected_elements(el).type; GhostType current_gt = connected_elements(el).ghost_type; Array & prank_to_el = prank_to_element(current_type, current_gt); prank[el] = prank_to_el(current_el); } bool ghost_one = (gt[0] != _ghost); if (prank[ghost_one] > prank[!ghost_one]) facet_ghost_type = _not_ghost; else facet_ghost_type = _ghost; connectivity_facets = &mesh_facets.getConnectivity(facet_type, facet_ghost_type); element_to_subelement = &mesh_facets.getElementToSubelement(facet_type, facet_ghost_type); } catch (...) { } } } /// facet of facet else { for (UInt i = 1; i < nb_element_connected_to_facet; ++i) { elements.push_back(connected_elements(i)); } } element_to_subelement->push_back(elements); connectivity_facets->push_back(facet); /// current facet index UInt current_facet = connectivity_facets->getSize() - 1; /// loop on every element connected to current facet and /// insert current facet in the first free spot of the /// subelement_to_element vector for (UInt elem = 0; elem < elements.size(); ++elem) { Element loc_el = elements[elem]; if (loc_el.type != _not_defined) { Array & subelement_to_element = mesh_facets.getSubelementToElement(type, loc_el.ghost_type); for (UInt f_in = 0; f_in < facets.rows(); ++f_in) { if (subelement_to_element(loc_el.element, f_in).type == _not_defined) { subelement_to_element(loc_el.element, f_in).type = facet_type; subelement_to_element(loc_el.element, f_in).element = current_facet; subelement_to_element(loc_el.element, f_in).ghost_type = facet_ghost_type; break; } } } } /// reset connectivity in case a facet was found in /// between ghost and normal elements if (facet_ghost_type != ghost_type) { facet_ghost_type = ghost_type; connectivity_facets = &mesh_facets.getConnectivity(facet_type, facet_ghost_type); element_to_subelement = &mesh_facets.getElementToSubelement(facet_type, facet_ghost_type); } } } } } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::renumberMeshNodes(Mesh & mesh, UInt * local_connectivities, UInt nb_local_element, UInt nb_ghost_element, ElementType type, Array & old_nodes_numbers) { AKANTU_DEBUG_IN(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); std::map renumbering_map; for (UInt i = 0; i < old_nodes_numbers.getSize(); ++i) { renumbering_map[old_nodes_numbers(i)] = i; } /// renumber the nodes renumberNodesInConnectivity(local_connectivities, (nb_local_element + nb_ghost_element)*nb_nodes_per_element, renumbering_map); std::map::iterator it = renumbering_map.begin(); std::map::iterator end = renumbering_map.end(); old_nodes_numbers.resize(renumbering_map.size()); for (;it != end; ++it) { old_nodes_numbers(it->second) = it->first; } renumbering_map.clear(); /// copy the renumbered connectivity to the right place Array * local_conn = mesh.getConnectivityPointer(type); local_conn->resize(nb_local_element); memcpy(local_conn->values, local_connectivities, nb_local_element * nb_nodes_per_element * sizeof(UInt)); Array * ghost_conn = mesh.getConnectivityPointer(type, _ghost); ghost_conn->resize(nb_ghost_element); memcpy(ghost_conn->values, local_connectivities + nb_local_element * nb_nodes_per_element, nb_ghost_element * nb_nodes_per_element * sizeof(UInt)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::renumberNodesInConnectivity(UInt * list_nodes, UInt nb_nodes, std::map & renumbering_map) { AKANTU_DEBUG_IN(); UInt * connectivity = list_nodes; UInt new_node_num = renumbering_map.size(); for (UInt n = 0; n < nb_nodes; ++n, ++connectivity) { UInt & node = *connectivity; std::map::iterator it = renumbering_map.find(node); if(it == renumbering_map.end()) { UInt old_node = node; renumbering_map[old_node] = new_node_num; node = new_node_num; ++new_node_num; } else { node = it->second; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::purifyMesh(Mesh & mesh) { AKANTU_DEBUG_IN(); std::map renumbering_map; RemovedNodesEvent remove_nodes(mesh); Array & nodes_removed = remove_nodes.getList(); for (UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type = (GhostType) gt; Mesh::type_iterator it = mesh.firstType(_all_dimensions, ghost_type, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(_all_dimensions, ghost_type, _ek_not_defined); for(; it != end; ++it) { ElementType type(*it); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const Array & connectivity_vect = mesh.getConnectivity(type, ghost_type); UInt nb_element(connectivity_vect.getSize()); UInt * connectivity = connectivity_vect.storage(); renumberNodesInConnectivity (connectivity, nb_element*nb_nodes_per_element, renumbering_map); } } Array & new_numbering = remove_nodes.getNewNumbering(); std::fill(new_numbering.begin(), new_numbering.end(), UInt(-1)); std::map::iterator it = renumbering_map.begin(); std::map::iterator end = renumbering_map.end(); for (; it != end; ++it) { new_numbering(it->first) = it->second; } for (UInt i = 0; i < new_numbering.getSize(); ++i) { if(new_numbering(i) == UInt(-1)) nodes_removed.push_back(i); } mesh.sendEvent(remove_nodes); AKANTU_DEBUG_OUT(); } -/* -------------------------------------------------------------------------- */ -void MeshUtils::insertIntrinsicCohesiveElementsInArea(Mesh & mesh, - const Array & limits) { - AKANTU_DEBUG_IN(); - - AKANTU_DEBUG_ASSERT(limits.getNbComponent() == 2, - "Number of components for limits array must be 2"); - - UInt spatial_dimension = mesh.getSpatialDimension(); - - AKANTU_DEBUG_ASSERT(limits.getSize() == spatial_dimension, - "Limits array size must be equal to spatial dimension"); - - Real * bary_facet = new Real[spatial_dimension]; - - Mesh mesh_facets(spatial_dimension, mesh.getNodes(), "mesh_facets"); - buildAllFacets(mesh, mesh_facets); - - resetFacetToDouble(mesh_facets); - - ByElementTypeArray facet_insertion("facet_insertion", ""); - for (UInt sp = 0; sp < spatial_dimension - 1; ++sp) - mesh_facets.initByElementTypeArray(facet_insertion, 1, sp - 1, - false, _ek_regular, true); - - Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1); - Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1); - - for(; it != end; ++it) { - const ElementType type_facet = *it; - Array & f_insertion = facet_insertion(type_facet); - Array > & element_to_facet - = mesh_facets.getElementToSubelement(type_facet); - - UInt nb_facet = mesh_facets.getNbElement(type_facet); - - for (UInt f = 0; f < nb_facet; ++f) { - - if (element_to_facet(f)[1] == ElementNull) continue; - - mesh_facets.getBarycenter(f, type_facet, bary_facet); - - UInt coord_in_limit = 0; - - while (coord_in_limit < spatial_dimension && - bary_facet[coord_in_limit] > limits(coord_in_limit, 0) && - bary_facet[coord_in_limit] < limits(coord_in_limit, 1)) - ++coord_in_limit; - - if (coord_in_limit == spatial_dimension) - f_insertion(f) = true; - } - } - - delete [] bary_facet; - - insertCohesiveElements(mesh, - mesh_facets, - facet_insertion, - false); - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ -void MeshUtils::insertIntrinsicCohesiveElements(Mesh & mesh, - Mesh & mesh_facets, - ElementType type_facet, - const Array & facet_insertion) { - AKANTU_DEBUG_IN(); - - UInt spatial_dimension = mesh.getSpatialDimension(); - - resetFacetToDouble(mesh_facets); - - /// add cohesive connectivity type - ElementType type_cohesive = FEM::getCohesiveElementType(type_facet); - mesh.addConnectivityType(type_cohesive); - - /// setup byelementtype insertion data - ByElementTypeArray facet_ins("facet_ins", ""); - for (UInt sp = 0; sp < spatial_dimension - 1; ++sp) - mesh_facets.initByElementTypeArray(facet_ins, 1, sp - 1, - false, _ek_regular, true); - - Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1); - Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1); - - for(; it != end; ++it) { - - if (*it != type_facet) continue; - - Array & f_ins = facet_ins(type_facet); - f_ins.copy(facet_insertion); - } - - /// insert cohesive elements - insertCohesiveElements(mesh, - mesh_facets, - facet_ins, - false); - - AKANTU_DEBUG_OUT(); -} - /* -------------------------------------------------------------------------- */ void MeshUtils::insertCohesiveElements(Mesh & mesh, Mesh & mesh_facets, - ByElementTypeArray & facet_insertion, - const bool extrinsic) { + const ByElementTypeArray & facet_insertion, + Array & doubled_nodes, + Array & new_elements) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); - NewNodesEvent node_event; - Array & doubled_nodes = node_event.getList(); - doubled_nodes.extendComponentsInterlaced(2, 1); - - UInt total_nb_new_elements = 0; - NewElementsEvent element_event; - if (updateFacetToDouble(mesh_facets, facet_insertion)) { if (spatial_dimension == 1) { doublePointFacet(mesh, mesh_facets, doubled_nodes); } else { doubleFacet(mesh, mesh_facets, spatial_dimension - 1, doubled_nodes, true); findSubfacetToDouble(mesh, mesh_facets); if (spatial_dimension == 2) { doubleSubfacet<2>(mesh, mesh_facets, doubled_nodes); } else if (spatial_dimension == 3) { doubleFacet(mesh, mesh_facets, 1, doubled_nodes, false); findSubfacetToDouble(mesh, mesh_facets); doubleSubfacet<3>(mesh, mesh_facets, doubled_nodes); } } - updateCohesiveData(mesh, mesh_facets, element_event); - - for (ghost_type_t::iterator gt = ghost_type_t::begin(); - gt != ghost_type_t::end(); ++gt) { - - GhostType gt_facet = *gt; - - Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, - gt_facet); - Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, - gt_facet); - - for(; it != end; ++it) { - ElementType type_facet = *it; - - Array & f_to_double = mesh_facets.getData("facet_to_double", - type_facet, - gt_facet); - total_nb_new_elements += f_to_double.getSize(); - - /// reset facet insertion - facet_insertion(type_facet, gt_facet).clear(); - } - } - - resetFacetToDouble(mesh_facets); + updateCohesiveData(mesh, mesh_facets, new_elements); } - /// update global IDs - /// @todo this function doesn't work - UInt total_nb_new_nodes = updateGlobalIDs(mesh, mesh_facets, doubled_nodes); - if (total_nb_new_nodes > 0) - mesh.sendEvent(node_event); - - if (mesh.nodes_type) { - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); - comm.allReduce(&total_nb_new_elements, 1, _so_sum); - } - - if (total_nb_new_elements > 0 || !extrinsic) { - mesh.updateTypesOffsets(_not_ghost); - mesh.sendEvent(element_event); - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ -UInt MeshUtils::updateGlobalIDs(Mesh & mesh, - Mesh & mesh_facets, - const Array & doubled_nodes) { - AKANTU_DEBUG_IN(); - - UInt local_nb_new_nodes = doubled_nodes.getSize(); - - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); - Int rank = comm.whoAmI(); - Int nb_proc = comm.getNbProc(); - - if (nb_proc == 1 || !mesh.nodes_type) { - mesh.nb_global_nodes += local_nb_new_nodes; - mesh_facets.nb_global_nodes += local_nb_new_nodes; - return local_nb_new_nodes; - } - - /// update nodes' type - Array & nodes_type = *mesh.nodes_type; - UInt nb_old_nodes = nodes_type.getSize(); - nodes_type.resize(nb_old_nodes + local_nb_new_nodes); - - for (UInt n = 0; n < local_nb_new_nodes; ++n) { - UInt old_node = doubled_nodes(n, 0); - UInt new_node = doubled_nodes(n, 1); - nodes_type(new_node) = nodes_type(old_node); - } - - /// resize global ids array - Array & nodes_global_ids = *mesh.nodes_global_ids; - nodes_global_ids.resize(nb_old_nodes + local_nb_new_nodes); - - /// compute amount of local or master doubled nodes - Vector local_master_nodes(nb_proc); - - for (UInt n = 0; n < local_nb_new_nodes; ++n) { - UInt old_node = doubled_nodes(n, 0); - if (mesh.isLocalOrMasterNode(old_node)) ++local_master_nodes(rank); - } - - comm.allGather(local_master_nodes.storage(), 1); - - /// update global number of nodes - UInt total_nb_new_nodes = std::accumulate(local_master_nodes.storage(), - local_master_nodes.storage() + nb_proc, - 0); - - if (total_nb_new_nodes == 0) return 0; - - // /// set global ids of local and master nodes - // UInt starting_index = std::accumulate(local_master_nodes.storage(), - // local_master_nodes.storage() + rank, - // mesh.nb_global_nodes); - - // for (UInt n = 0; n < local_master_nodes(rank); ++n, ++starting_index) { - // UInt current_node = nb_old_nodes + n; - // nodes_global_ids(current_node) = starting_index; - // } - - // /// create list of slave global ids for old nodes - // Array< Array > slave_global_ids_send(nb_proc); - - // for (UInt n = 0; n < local_nb_new_nodes; ++n) { - // UInt old_node = doubled_nodes(n, 0); - // Int p = nodes_type(old_node); - // if (p >= 0) { - // UInt global_id = nodes_global_ids(old_node); - // slave_global_ids_send(p).push_back(global_id); - // } - // } - - // /// add dummy variable at the end to avoid void communications - // for (Int p = 0; p < nb_proc; ++p) { - // if (p != rank) - // slave_global_ids_send(p).push_back(UInt(-1)); - // } - - // /// send slave nodes global ids - // std::vector requests; - - // for (Int p = 0; p < nb_proc; ++p) { - // if (p == rank) continue; - - // requests.push_back(comm.asyncSend(slave_global_ids_send(p).storage(), - // slave_global_ids_send(p).getSize(), - // p, rank)); - // } - - // /// allocate memory and receive slave global ids from other processors - // Array< Array > slave_global_ids_recv(nb_proc); - - // for (Int p = 0; p < nb_proc; ++p) { - // if (p == rank) continue; - - // CommunicationStatus status; - // comm.probe(p, p, status); - - // slave_global_ids_recv(p).resize(status.getSize()); - - // comm.receive(slave_global_ids_recv(p).storage(), - // slave_global_ids_recv(p).getSize(), - // p, p); - // } - - // /// create master nodes global ids - // Array old_master_nodes_global_ids; - // Array old_master_nodes_index; - - // for (UInt n = 0; n < mesh.getNbNodes(); ++n) { - // if (mesh.isMasterNode(n)) { - // old_master_nodes_global_ids.push_back(nodes_global_ids(n)); - // old_master_nodes_index.push_back(n); - // } - // } - - // // for (UInt n = 0; n < local_nb_new_nodes; ++n) { - // // UInt old_node = doubled_nodes(n, 0); - // // if (mesh.isMasterNode(old_node)) { - // // old_master_nodes_global_ids.push_back(nodes_global_ids(old_node)); - // // old_master_nodes_index.push_back(n); - // // } - // // } - - // /// substitute the obtained slaved ids for old nodes with those of new nodes - // Array::iterator glob_old_begin = old_master_nodes_global_ids.begin(); - // Array::iterator glob_old_end = old_master_nodes_global_ids.end(); - - // for (Int p = 0; p < nb_proc; ++p) { - // if (p == rank) continue; - - // /// last value is dummy - // UInt nb_nodes_to_find = slave_global_ids_recv(p).getSize() - 1; - - // for (UInt n = 0; n < nb_nodes_to_find; ++n) { - // UInt & id_to_find = slave_global_ids_recv(p)(n); - // UInt n_position - // = std::find(glob_old_begin, glob_old_end, id_to_find) - glob_old_begin; - - // AKANTU_DEBUG_ASSERT(n_position < old_master_nodes_index.getSize(), - // "Node global id not found"); - - // UInt index = old_master_nodes_index(n_position); - // id_to_find = nodes_global_ids(doubled_nodes(index, 1)); - // } - // } - - // /// wait for all communications and reset requests - // comm.waitAll(requests); - // comm.freeCommunicationRequest(requests); - // requests.resize(0); - - // /// communicate back the substituted global ids - // for (Int p = 0; p < nb_proc; ++p) { - // if (p == rank) continue; - - // requests.push_back(comm.asyncSend(slave_global_ids_recv(p).storage(), - // slave_global_ids_recv(p).getSize(), - // p, rank)); - // } - - // for (Int p = 0; p < nb_proc; ++p) { - // if (p == rank) continue; - // comm.receive(slave_global_ids_send(p).storage(), - // slave_global_ids_send(p).getSize(), - // p, p); - // } - - // /// set global ids for slave nodes - // Vector node_index(nb_proc); - - // for (UInt n = 0; n < local_nb_new_nodes; ++n) { - // UInt new_node = doubled_nodes(n, 1); - // Int p = nodes_type(new_node); - // if (p >= 0) { - // nodes_global_ids(new_node) = slave_global_ids_send(p)(node_index(p)); - // ++node_index(p); - // } - // } - - // /// wait for all communications and free requests - // comm.waitAll(requests); - // comm.freeCommunicationRequest(requests); - - - mesh.nb_global_nodes += total_nb_new_nodes; - mesh_facets.nb_global_nodes += total_nb_new_nodes; - AKANTU_DEBUG_OUT(); - return total_nb_new_nodes; } /* -------------------------------------------------------------------------- */ void MeshUtils::doubleNodes(Mesh & mesh, const Array & old_nodes, Array & doubled_nodes) { AKANTU_DEBUG_IN(); Array & position = mesh.getNodes(); UInt spatial_dimension = mesh.getSpatialDimension(); UInt old_nb_nodes = position.getSize(); UInt new_nb_nodes = old_nb_nodes + old_nodes.getSize(); UInt old_nb_doubled_nodes = doubled_nodes.getSize(); UInt new_nb_doubled_nodes = old_nb_doubled_nodes + old_nodes.getSize(); position.resize(new_nb_nodes); doubled_nodes.resize(new_nb_doubled_nodes); Array::iterator > position_begin = position.begin(spatial_dimension); for (UInt n = 0; n < old_nodes.getSize(); ++n) { UInt new_node = old_nb_nodes + n; /// store doubled nodes doubled_nodes(old_nb_doubled_nodes + n, 0) = old_nodes(n); doubled_nodes(old_nb_doubled_nodes + n, 1) = new_node; /// update position std::copy(position_begin + old_nodes(n), position_begin + old_nodes(n) + 1, position_begin + new_node); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::doubleFacet(Mesh & mesh, Mesh & mesh_facets, UInt facet_dimension, Array & doubled_nodes, bool facet_mode) { AKANTU_DEBUG_IN(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(facet_dimension, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(facet_dimension, gt_facet); for(; it != end; ++it) { ElementType type_facet = *it; Array & f_to_double = mesh_facets.getData("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.getSize(); if (nb_facet_to_double == 0) continue; ElementType type_subfacet = Mesh::getFacetType(type_facet); const UInt nb_subfacet_per_facet = Mesh::getNbFacetsPerElement(type_facet); GhostType gt_subfacet = _casper; Array > * f_to_subfacet = NULL; Array & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); Array & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); UInt nb_nodes_per_facet = conn_facet.getNbComponent(); UInt old_nb_facet = conn_facet.getSize(); UInt new_nb_facet = old_nb_facet + nb_facet_to_double; conn_facet.resize(new_nb_facet); subfacet_to_facet.resize(new_nb_facet); UInt new_facet = old_nb_facet - 1; Element new_facet_el(type_facet, 0, gt_facet); Array::iterator > subfacet_to_facet_begin = subfacet_to_facet.begin(nb_subfacet_per_facet); Array::iterator > conn_facet_begin = conn_facet.begin(nb_nodes_per_facet); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); ++new_facet; /// adding a new facet by copying original one /// copy connectivity in new facet std::copy(conn_facet_begin + old_facet, conn_facet_begin + old_facet + 1, conn_facet_begin + new_facet); /// update subfacet_to_facet std::copy(subfacet_to_facet_begin + old_facet, subfacet_to_facet_begin + old_facet + 1, subfacet_to_facet_begin + new_facet); new_facet_el.element = new_facet; /// loop on every subfacet for (UInt sf = 0; sf < nb_subfacet_per_facet; ++sf) { Element & subfacet = subfacet_to_facet(old_facet, sf); if (subfacet == ElementNull) continue; if (gt_subfacet != subfacet.ghost_type) { gt_subfacet = subfacet.ghost_type; f_to_subfacet = & mesh_facets.getElementToSubelement(type_subfacet, subfacet.ghost_type); } /// update facet_to_subfacet array (*f_to_subfacet)(subfacet.element).push_back(new_facet_el); } } /// update facet_to_subfacet and _segment_3 facets if any if (!facet_mode) { updateSubfacetToFacet(mesh_facets, type_facet, gt_facet, true); updateFacetToSubfacet(mesh_facets, type_facet, gt_facet, true); updateQuadraticSegments(mesh, mesh_facets, type_facet, gt_facet, doubled_nodes); } else updateQuadraticSegments(mesh, mesh_facets, type_facet, gt_facet, doubled_nodes); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ bool MeshUtils::updateFacetToDouble(Mesh & mesh_facets, const ByElementTypeArray & facet_insertion) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); bool facets_to_double = false; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for(; it != end; ++it) { ElementType type_facet = *it; const Array & f_insertion = facet_insertion(type_facet, gt_facet); Array & f_to_double = mesh_facets.getData("facet_to_double", type_facet, gt_facet); Array< std::vector > & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); ElementType el_type = _not_defined; GhostType el_gt = _casper; UInt nb_facet_per_element = 0; Element old_facet_el(type_facet, 0, gt_facet); Array * facet_to_element = NULL; for (UInt f = 0; f < f_insertion.getSize(); ++f) { if (f_insertion(f) == false) continue; facets_to_double = true; if (element_to_facet(f)[1].type == _not_defined || element_to_facet(f)[1].kind == _ek_cohesive) { AKANTU_DEBUG_WARNING("attempt to double a facet on the boundary"); continue; } f_to_double.push_back(f); UInt new_facet = mesh_facets.getNbElement(type_facet, gt_facet) + f_to_double.getSize() - 1; old_facet_el.element = f; /// update facet_to_element vector Element & elem_to_update = element_to_facet(f)[1]; UInt el = elem_to_update.element; if (elem_to_update.ghost_type != el_gt || elem_to_update.type != el_type) { el_type = elem_to_update.type; el_gt = elem_to_update.ghost_type; facet_to_element = & mesh_facets.getSubelementToElement(el_type, el_gt); nb_facet_per_element = facet_to_element->getNbComponent(); } Element * f_update = std::find(facet_to_element->storage() + el * nb_facet_per_element, facet_to_element->storage() + el * nb_facet_per_element + nb_facet_per_element, old_facet_el); AKANTU_DEBUG_ASSERT(facet_to_element->storage() + el * nb_facet_per_element != facet_to_element->storage() + el * nb_facet_per_element + nb_facet_per_element, "Facet not found"); f_update->element = new_facet; /// update elements connected to facet std::vector first_facet_list = element_to_facet(f); element_to_facet.push_back(first_facet_list); /// set new and original facets as boundary facets element_to_facet(new_facet)[0] = element_to_facet(new_facet)[1]; element_to_facet(f)[1] = ElementNull; element_to_facet(new_facet)[1] = ElementNull; } } } AKANTU_DEBUG_OUT(); return facets_to_double; } /* -------------------------------------------------------------------------- */ void MeshUtils::resetFacetToDouble(Mesh & mesh_facets) { AKANTU_DEBUG_IN(); for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; Mesh::type_iterator it = mesh_facets.firstType(_all_dimensions, gt); Mesh::type_iterator end = mesh_facets.lastType(_all_dimensions, gt); for(; it != end; ++it) { ElementType type = *it; mesh_facets.getDataPointer("facet_to_double", type, gt, 1)->resize(0); mesh_facets.getDataPointer > ("facets_to_subfacet_double", type, gt, 1)->resize(0); mesh_facets.getDataPointer > ("elements_to_subfacet_double", type, gt, 1)->resize(0); mesh_facets.getDataPointer > ("subfacets_to_subsubfacet_double", type, gt, 1)->resize(0); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MeshUtils::findSubfacetToDouble(Mesh & mesh, Mesh & mesh_facets) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); if (spatial_dimension == 1) return; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for(; it != end; ++it) { ElementType type_facet = *it; Array & f_to_double = mesh_facets.getData("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.getSize(); if (nb_facet_to_double == 0) continue; ElementType type_subfacet = Mesh::getFacetType(type_facet); GhostType gt_subfacet = _casper; ElementType type_subsubfacet = Mesh::getFacetType(type_subfacet); GhostType gt_subsubfacet = _casper; Array * conn_subfacet = NULL; Array * sf_to_double = NULL; Array > * sf_to_subfacet_double = NULL; Array > * f_to_subfacet_double = NULL; Array > * el_to_subfacet_double = NULL; UInt nb_subfacet = Mesh::getNbFacetsPerElement(type_facet); UInt nb_subsubfacet; UInt nb_nodes_per_sf_el; if (subsubfacet_mode) { nb_nodes_per_sf_el = Mesh::getNbNodesPerElement(type_subsubfacet); nb_subsubfacet = Mesh::getNbFacetsPerElement(type_subfacet); } else nb_nodes_per_sf_el = Mesh::getNbNodesPerElement(type_subfacet); Array & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); Array< std::vector > & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); Array * subsubfacet_to_subfacet = NULL; UInt old_nb_facet = subfacet_to_facet.getSize() - nb_facet_to_double; Element current_facet(type_facet, 0, gt_facet); std::vector element_list; std::vector facet_list; std::vector * subfacet_list; if (subsubfacet_mode) subfacet_list = new std::vector; /// map to filter subfacets Array< std::vector > * facet_to_subfacet = NULL; /// this is used to make sure that both new and old facets are /// checked UInt facets[2]; /// loop on every facet for (UInt f_index = 0; f_index < 2; ++f_index) { for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { facets[bool(f_index)] = f_to_double(facet); facets[!bool(f_index)] = old_nb_facet + facet; UInt old_facet = facets[0]; UInt new_facet = facets[1]; Element & starting_element = element_to_facet(new_facet)[0]; current_facet.element = old_facet; /// loop on every subfacet for (UInt sf = 0; sf < nb_subfacet; ++sf) { Element & subfacet = subfacet_to_facet(old_facet, sf); if (subfacet == ElementNull) continue; if (gt_subfacet != subfacet.ghost_type) { gt_subfacet = subfacet.ghost_type; if (subsubfacet_mode) { subsubfacet_to_subfacet = & mesh_facets.getSubelementToElement(type_subfacet, gt_subfacet); } else { conn_subfacet = & mesh_facets.getConnectivity(type_subfacet, gt_subfacet); sf_to_double = & mesh_facets.getData("facet_to_double", type_subfacet, gt_subfacet); f_to_subfacet_double = & mesh_facets.getData >("facets_to_subfacet_double", type_subfacet, gt_subfacet); el_to_subfacet_double = & mesh_facets.getData >("elements_to_subfacet_double", type_subfacet, gt_subfacet); facet_to_subfacet = & mesh_facets.getElementToSubelement(type_subfacet, gt_subfacet); } } if (subsubfacet_mode) { /// loop on every subsubfacet for (UInt ssf = 0; ssf < nb_subsubfacet; ++ssf) { Element & subsubfacet = (*subsubfacet_to_subfacet)(subfacet.element, ssf); if (subsubfacet == ElementNull) continue; if (gt_subsubfacet != subsubfacet.ghost_type) { gt_subsubfacet = subsubfacet.ghost_type; conn_subfacet = & mesh_facets.getConnectivity(type_subsubfacet, gt_subsubfacet); sf_to_double = & mesh_facets.getData("facet_to_double", type_subsubfacet, gt_subsubfacet); sf_to_subfacet_double = & mesh_facets.getData >("subfacets_to_subsubfacet_double", type_subsubfacet, gt_subsubfacet); f_to_subfacet_double = & mesh_facets.getData >("facets_to_subfacet_double", type_subsubfacet, gt_subsubfacet); el_to_subfacet_double = & mesh_facets.getData >("elements_to_subfacet_double", type_subsubfacet, gt_subsubfacet); facet_to_subfacet = & mesh_facets.getElementToSubelement(type_subsubfacet, gt_subsubfacet); } UInt global_ssf = subsubfacet.element; Vector subsubfacet_connectivity(conn_subfacet->storage() + global_ssf * nb_nodes_per_sf_el, nb_nodes_per_sf_el); /// check if subsubfacet is to be doubled if (findElementsAroundSubfacet(mesh, mesh_facets, starting_element, current_facet, subsubfacet_connectivity, element_list, facet_list, subfacet_list) == false && removeElementsInVector(*subfacet_list, (*facet_to_subfacet)(global_ssf)) == false) { sf_to_double->push_back(global_ssf); sf_to_subfacet_double->push_back(*subfacet_list); f_to_subfacet_double->push_back(facet_list); el_to_subfacet_double->push_back(element_list); } } } else { const UInt global_sf = subfacet.element; Vector subfacet_connectivity(conn_subfacet->storage() + global_sf * nb_nodes_per_sf_el, nb_nodes_per_sf_el); /// check if subfacet is to be doubled if (findElementsAroundSubfacet(mesh, mesh_facets, starting_element, current_facet, subfacet_connectivity, element_list, facet_list) == false && removeElementsInVector(facet_list, (*facet_to_subfacet)(global_sf)) == false) { sf_to_double->push_back(global_sf); f_to_subfacet_double->push_back(facet_list); el_to_subfacet_double->push_back(element_list); } } } } } if (subsubfacet_mode) delete subfacet_list; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::updateCohesiveData(Mesh & mesh, Mesh & mesh_facets, - NewElementsEvent & element_event) { + Array & new_elements) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); bool third_dimension = spatial_dimension == 3; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for(; it != end; ++it) { ElementType type_facet = *it; Array & f_to_double = mesh_facets.getData("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.getSize(); if (nb_facet_to_double == 0) continue; ElementType type_cohesive = FEM::getCohesiveElementType(type_facet); Array * facet_to_coh_element = mesh.getSubelementToElementPointer(type_cohesive, gt_facet); Array & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); Array * conn_cohesive = mesh.getConnectivityPointer(type_cohesive, gt_facet); UInt nb_nodes_per_facet = Mesh::getNbNodesPerElement(type_facet); Array< std::vector > & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); UInt old_nb_cohesive_elements = conn_cohesive->getSize(); UInt new_nb_cohesive_elements = conn_cohesive->getSize() + nb_facet_to_double; UInt old_nb_facet = element_to_facet.getSize() - nb_facet_to_double; facet_to_coh_element->resize(new_nb_cohesive_elements); conn_cohesive->resize(new_nb_cohesive_elements); - Array & event_list = element_event.getList(); - UInt event_list_old_size = event_list.getSize(); - event_list.resize(event_list_old_size + nb_facet_to_double); + UInt new_elements_old_size = new_elements.getSize(); + new_elements.resize(new_elements_old_size + nb_facet_to_double); Element c_element(type_cohesive, 0, gt_facet, _ek_cohesive); Element f_element(type_facet, 0, gt_facet); UInt facets[2]; for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { /// (in 3D cohesive elements connectivity is inverted) facets[third_dimension] = f_to_double(facet); facets[!third_dimension] = old_nb_facet + facet; UInt cohesive_element = old_nb_cohesive_elements + facet; /// store doubled facets f_element.element = facets[0]; (*facet_to_coh_element)(cohesive_element, 0) = f_element; f_element.element = facets[1]; (*facet_to_coh_element)(cohesive_element, 1) = f_element; /// modify cohesive elements' connectivity for (UInt n = 0; n < nb_nodes_per_facet; ++n) { (*conn_cohesive)(cohesive_element, n) = conn_facet(facets[0], n); (*conn_cohesive)(cohesive_element, n + nb_nodes_per_facet) = conn_facet(facets[1], n); } /// update element_to_facet vectors c_element.element = cohesive_element; element_to_facet(facets[0])[1] = c_element; element_to_facet(facets[1])[1] = c_element; /// add cohesive element to the element event list - event_list(event_list_old_size + facet) = c_element; + new_elements(new_elements_old_size + facet) = c_element; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::doublePointFacet(Mesh & mesh, Mesh & mesh_facets, Array & doubled_nodes) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); if (spatial_dimension != 1) return; Array & position = mesh.getNodes(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_facet = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); for(; it != end; ++it) { ElementType type_facet = *it; Array & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); Array< std::vector > & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); const Array & f_to_double = mesh_facets.getData("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.getSize(); UInt old_nb_facet = element_to_facet.getSize() - nb_facet_to_double; UInt new_nb_facet = element_to_facet.getSize(); UInt old_nb_nodes = position.getSize(); UInt new_nb_nodes = old_nb_nodes + nb_facet_to_double; position.resize(new_nb_nodes); conn_facet.resize(new_nb_facet); UInt old_nb_doubled_nodes = doubled_nodes.getSize(); doubled_nodes.resize(old_nb_doubled_nodes + nb_facet_to_double); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt new_facet = old_nb_facet + facet; ElementType type = element_to_facet(new_facet)[0].type; UInt el = element_to_facet(new_facet)[0].element; GhostType gt = element_to_facet(new_facet)[0].ghost_type; UInt old_node = conn_facet(old_facet); UInt new_node = old_nb_nodes + facet; /// update position position(new_node) = position(old_node); conn_facet(new_facet) = new_node; Array & conn_segment = mesh.getConnectivity(type, gt); UInt nb_nodes_per_segment = conn_segment.getNbComponent(); /// update facet connectivity UInt i; for (i = 0; conn_segment(el, i) != old_node && i <= nb_nodes_per_segment; ++i); conn_segment(el, i) = new_node; doubled_nodes(old_nb_doubled_nodes + facet, 0) = old_node; doubled_nodes(old_nb_doubled_nodes + facet, 1) = new_node; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MeshUtils::updateQuadraticSegments(Mesh & mesh, Mesh & mesh_facets, ElementType type_facet, GhostType gt_facet, Array & doubled_nodes) { AKANTU_DEBUG_IN(); if (type_facet != _segment_3) return; Array & f_to_double = mesh_facets.getData("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.getSize(); UInt old_nb_facet = mesh_facets.getNbElement(type_facet, gt_facet) - nb_facet_to_double; Array & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); Array< std::vector > & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); /// this ones matter only for segments in 3D Array< std::vector > * el_to_subfacet_double = NULL; Array< std::vector > * f_to_subfacet_double = NULL; if (third_dim_segments) { el_to_subfacet_double = & mesh_facets.getData >("elements_to_subfacet_double", type_facet, gt_facet); f_to_subfacet_double = & mesh_facets.getData >("facets_to_subfacet_double", type_facet, gt_facet); } Array middle_nodes; Array subfacets; for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt node = conn_facet(old_facet, 2); if (!mesh.isPureGhostNode(node)) { middle_nodes.push_back(node); subfacets.push_back(facet); } } UInt old_nb_doubled_nodes = doubled_nodes.getSize(); doubleNodes(mesh, middle_nodes, doubled_nodes); for (UInt n = old_nb_doubled_nodes; n < doubled_nodes.getSize(); ++n) { UInt old_node = doubled_nodes(n, 0); UInt new_node = doubled_nodes(n, 1); UInt sf = subfacets(n - old_nb_doubled_nodes); UInt new_facet = old_nb_facet + sf; conn_facet(new_facet, 2) = new_node; if (third_dim_segments) { updateElementalConnectivity(mesh_facets, old_node, new_node, element_to_facet(new_facet)); updateElementalConnectivity(mesh, old_node, new_node, (*el_to_subfacet_double)(sf), &(*f_to_subfacet_double)(sf)); } else { updateElementalConnectivity(mesh, old_node, new_node, element_to_facet(new_facet)); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::updateSubfacetToFacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode) { AKANTU_DEBUG_IN(); Array & sf_to_double = mesh_facets.getData("facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.getSize(); /// update subfacet_to_facet vector ElementType type_facet = _not_defined; GhostType gt_facet = _casper; Array * subfacet_to_facet = NULL; UInt nb_subfacet_per_facet = 0; UInt old_nb_subfacet = mesh_facets.getNbElement(type_subfacet, gt_subfacet) - nb_subfacet_to_double; Array > * facet_list = NULL; if (facet_mode) facet_list = & mesh_facets.getData >("facets_to_subfacet_double", type_subfacet, gt_subfacet); else facet_list = & mesh_facets.getData >("subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); Element old_subfacet_el(type_subfacet, 0, gt_subfacet); Element new_subfacet_el(type_subfacet, 0, gt_subfacet); for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { old_subfacet_el.element = sf_to_double(sf); new_subfacet_el.element = old_nb_subfacet + sf; for (UInt f = 0; f < (*facet_list)(sf).size(); ++f) { Element & facet = (*facet_list)(sf)[f]; if (facet.type != type_facet || facet.ghost_type != gt_facet) { type_facet = facet.type; gt_facet = facet.ghost_type; subfacet_to_facet = & mesh_facets.getSubelementToElement(type_facet, gt_facet); nb_subfacet_per_facet = subfacet_to_facet->getNbComponent(); } Element * sf_update = std::find(subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet, subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet + nb_subfacet_per_facet, old_subfacet_el); AKANTU_DEBUG_ASSERT(subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet != subfacet_to_facet->storage() + facet.element * nb_subfacet_per_facet + nb_subfacet_per_facet, "Subfacet not found"); *sf_update = new_subfacet_el; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::updateFacetToSubfacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode) { AKANTU_DEBUG_IN(); Array & sf_to_double = mesh_facets.getData("facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.getSize(); Array< std::vector > & facet_to_subfacet = mesh_facets.getElementToSubelement(type_subfacet, gt_subfacet); Array< std::vector > * facet_to_subfacet_double = NULL; if (facet_mode) { facet_to_subfacet_double = & mesh_facets.getData >("facets_to_subfacet_double", type_subfacet, gt_subfacet); } else { facet_to_subfacet_double = & mesh_facets.getData >("subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); } for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) facet_to_subfacet.push_back((*facet_to_subfacet_double)(sf)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MeshUtils::doubleSubfacet(Mesh & mesh, Mesh & mesh_facets, Array & doubled_nodes) { AKANTU_DEBUG_IN(); if (spatial_dimension == 1) return; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType gt_subfacet = *gt; Mesh::type_iterator it = mesh_facets.firstType(0, gt_subfacet); Mesh::type_iterator end = mesh_facets.lastType(0, gt_subfacet); for(; it != end; ++it) { ElementType type_subfacet = *it; Array & sf_to_double = mesh_facets.getData("facet_to_double", type_subfacet, gt_subfacet); UInt nb_subfacet_to_double = sf_to_double.getSize(); if (nb_subfacet_to_double == 0) continue; AKANTU_DEBUG_ASSERT(type_subfacet == _point_1, "Only _point_1 subfacet doubling is supported at the moment"); Array & conn_subfacet = mesh_facets.getConnectivity(type_subfacet, gt_subfacet); UInt old_nb_subfacet = conn_subfacet.getSize(); UInt new_nb_subfacet = old_nb_subfacet + nb_subfacet_to_double; conn_subfacet.resize(new_nb_subfacet); Array nodes_to_double; UInt old_nb_doubled_nodes = doubled_nodes.getSize(); /// double nodes for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt old_subfacet = sf_to_double(sf); nodes_to_double.push_back(conn_subfacet(old_subfacet)); } doubleNodes(mesh, nodes_to_double, doubled_nodes); /// add new nodes in connectivity for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt new_subfacet = old_nb_subfacet + sf; UInt new_node = doubled_nodes(old_nb_doubled_nodes + sf, 1); conn_subfacet(new_subfacet) = new_node; } /// update facet and element connectivity Array > & f_to_subfacet_double = mesh_facets.getData >("facets_to_subfacet_double", type_subfacet, gt_subfacet); Array > & el_to_subfacet_double = mesh_facets.getData >("elements_to_subfacet_double", type_subfacet, gt_subfacet); Array > * sf_to_subfacet_double = NULL; if (spatial_dimension == 3) sf_to_subfacet_double = & mesh_facets.getData >("subfacets_to_subsubfacet_double", type_subfacet, gt_subfacet); for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) { UInt old_node = doubled_nodes(old_nb_doubled_nodes + sf, 0); UInt new_node = doubled_nodes(old_nb_doubled_nodes + sf, 1); updateElementalConnectivity(mesh, old_node, new_node, el_to_subfacet_double(sf), &f_to_subfacet_double(sf)); updateElementalConnectivity(mesh_facets, old_node, new_node, f_to_subfacet_double(sf)); if (spatial_dimension == 3) updateElementalConnectivity(mesh_facets, old_node, new_node, (*sf_to_subfacet_double)(sf)); } if (spatial_dimension == 2) { updateSubfacetToFacet(mesh_facets, type_subfacet, gt_subfacet, true); updateFacetToSubfacet(mesh_facets, type_subfacet, gt_subfacet, true); } else if (spatial_dimension == 3) { updateSubfacetToFacet(mesh_facets, type_subfacet, gt_subfacet, false); updateFacetToSubfacet(mesh_facets, type_subfacet, gt_subfacet, false); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::flipFacets(Mesh & mesh_facets, const ByElementTypeUInt & global_connectivity, GhostType gt_facet) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); /// loop on every ghost facet for(; it != end; ++it) { ElementType type_facet = *it; Array & connectivity = mesh_facets.getConnectivity(type_facet, gt_facet); const Array & g_connectivity = global_connectivity(type_facet, gt_facet); Array > & el_to_f = mesh_facets.getElementToSubelement(type_facet, gt_facet); Array & subfacet_to_facet = mesh_facets.getSubelementToElement(type_facet, gt_facet); UInt nb_subfacet_per_facet = subfacet_to_facet.getNbComponent(); UInt nb_nodes_per_facet = connectivity.getNbComponent(); UInt nb_facet = connectivity.getSize(); UInt nb_nodes_per_P1_facet = Mesh::getNbNodesPerElement(Mesh::getP1ElementType(type_facet)); /// get global connectivity for local mesh Array global_conn_tmp(nb_facet, nb_nodes_per_facet); mesh_facets.getGlobalConnectivity(global_conn_tmp, type_facet, gt_facet); Array::iterator > conn_it = connectivity.begin(nb_nodes_per_facet); Array::iterator > gconn_tmp_it = global_conn_tmp.begin(nb_nodes_per_facet); Array::const_iterator > conn_glob_it = g_connectivity.begin(nb_nodes_per_facet); Array::iterator > subf_to_f = subfacet_to_facet.begin(nb_subfacet_per_facet); UInt * conn_tmp_pointer = new UInt[nb_nodes_per_facet]; Vector conn_tmp(conn_tmp_pointer, nb_nodes_per_facet); Element el_tmp; Element * subf_tmp_pointer = new Element[nb_subfacet_per_facet]; Vector subf_tmp(subf_tmp_pointer, nb_subfacet_per_facet); for (UInt f = 0; f < nb_facet; ++f, ++conn_it, ++gconn_tmp_it, ++subf_to_f, ++conn_glob_it) { Vector & gconn_tmp = *gconn_tmp_it; const Vector & conn_glob = *conn_glob_it; Vector & conn_local = *conn_it; /// skip facet if connectivities are the same if (gconn_tmp == conn_glob) continue; /// re-arrange connectivity conn_tmp = conn_local; UInt * begin = conn_glob.storage(); UInt * end = conn_glob.storage() + nb_nodes_per_facet; for (UInt n = 0; n < nb_nodes_per_facet; ++n) { UInt * new_node = std::find(begin, end, gconn_tmp(n)); AKANTU_DEBUG_ASSERT(new_node != end, "Node not found"); UInt new_position = new_node - begin; conn_local(new_position) = conn_tmp(n); } /// if 3D, check if facets are just rotated if (spatial_dimension == 3) { /// find first node UInt * new_node = std::find(begin, end, gconn_tmp(0)); AKANTU_DEBUG_ASSERT(new_node != end, "Node not found"); UInt new_position = new_node - begin; UInt n = 1; /// count how many nodes in the received connectivity follow /// the same order of those in the local connectivity for (; n < nb_nodes_per_P1_facet && gconn_tmp(n) == conn_glob((new_position + n) % nb_nodes_per_P1_facet); ++n); /// skip the facet inversion if facet is just rotated if (n == nb_nodes_per_P1_facet) continue; } /// update data to invert facet el_tmp = el_to_f(f)[0]; el_to_f(f)[0] = el_to_f(f)[1]; el_to_f(f)[1] = el_tmp; subf_tmp = (*subf_to_f); (*subf_to_f)(0) = subf_tmp(1); (*subf_to_f)(1) = subf_tmp(0); } delete [] subf_tmp_pointer; delete [] conn_tmp_pointer; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::fillElementToSubElementsData(Mesh & mesh) { AKANTU_DEBUG_IN(); if(mesh.getNbElement(mesh.getSpatialDimension() - 1) == 0) { AKANTU_DEBUG_WARNING("There are not facets, add them in the mesh file or call the buildFacet method."); return; } UInt spatial_dimension = mesh.getSpatialDimension(); ByElementTypeReal barycenters("barycenter_tmp", mesh.getID()); mesh.initByElementTypeArray(barycenters, spatial_dimension, _all_dimensions); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator it = mesh.firstType(_all_dimensions, *gt); Mesh::type_iterator end = mesh.lastType(_all_dimensions, *gt); for(; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it, *gt); Array & barycenters_arr = barycenters(*it, *gt); barycenters_arr.resize(nb_element); Array::iterator< Vector > bary = barycenters_arr.begin(spatial_dimension); Array::iterator< Vector > bary_end = barycenters_arr.end(spatial_dimension); for (UInt el = 0; bary != bary_end; ++bary, ++el) { mesh.getBarycenter(el, *it, bary->storage(), *gt); } } } for(Int sp(spatial_dimension); sp >= 1; --sp) { if(mesh.getNbElement(sp) == 0) continue; for (ghost_type_t::iterator git = ghost_type_t::begin(); git != ghost_type_t::end(); ++git) { Mesh::type_iterator tit = mesh.firstType(sp, *git); Mesh::type_iterator tend = mesh.lastType(sp, *git); for (;tit != tend; ++tit) { mesh.getSubelementToElementPointer(*tit, *git)->resize(mesh.getNbElement(*tit, *git)); mesh.getSubelementToElement(*tit, *git).clear(); } tit = mesh.firstType(sp - 1, *git); tend = mesh.lastType(sp - 1, *git); for (;tit != tend; ++tit) { mesh.getElementToSubelementPointer(*tit, *git)->resize(mesh.getNbElement(*tit, *git)); mesh.getElementToSubelement(*tit, *git).clear(); } } CSR nodes_to_elements; buildNode2Elements(mesh, nodes_to_elements, sp); Element facet_element; for (ghost_type_t::iterator git = ghost_type_t::begin(); git != ghost_type_t::end(); ++git) { Mesh::type_iterator tit = mesh.firstType(sp - 1, *git); Mesh::type_iterator tend = mesh.lastType(sp - 1, *git); facet_element.ghost_type = *git; for (;tit != tend; ++tit) { facet_element.type = *tit; Array< std::vector > & element_to_subelement = mesh.getElementToSubelement(*tit, *git); const Array & connectivity = mesh.getConnectivity(*tit, *git); Array::const_iterator< Vector > fit = connectivity.begin(mesh.getNbNodesPerElement(*tit)); Array::const_iterator< Vector > fend = connectivity.end(mesh.getNbNodesPerElement(*tit)); UInt fid = 0; for (;fit != fend; ++fit, ++fid) { const Vector & facet = *fit; facet_element.element = fid; std::map element_seen_counter; UInt nb_nodes_per_facet = mesh.getNbNodesPerElement(Mesh::getP1ElementType(*tit)); for (UInt n(0); n < nb_nodes_per_facet; ++n) { CSR::iterator eit = nodes_to_elements.begin(facet(n)); CSR::iterator eend = nodes_to_elements.end(facet(n)); for(;eit != eend; ++eit) { Element & elem = *eit; std::map::iterator cit = element_seen_counter.find(elem); if(cit != element_seen_counter.end()) { cit->second++; } else { element_seen_counter[elem] = 1; } } } std::vector connected_elements; std::map::iterator cit = element_seen_counter.begin(); std::map::iterator cend = element_seen_counter.end(); for(;cit != cend; ++cit) { if(cit->second == nb_nodes_per_facet) connected_elements.push_back(cit->first); } std::vector::iterator ceit = connected_elements.begin(); std::vector::iterator ceend = connected_elements.end(); for(;ceit != ceend; ++ceit) element_to_subelement(fid).push_back(*ceit); for (UInt ce = 0; ce < connected_elements.size(); ++ce) { Element & elem = connected_elements[ce]; Array & subelement_to_element = *(mesh.getSubelementToElementPointer(elem.type, elem.ghost_type)); UInt f(0); for(; f < mesh.getNbFacetsPerElement(elem.type) && subelement_to_element(elem.element, f) != ElementNull; ++f); AKANTU_DEBUG_ASSERT(f < mesh.getNbFacetsPerElement(elem.type), "The element "<< elem << " seems to have too many facets!!"); subelement_to_element(elem.element, f) = facet_element; } } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template bool MeshUtils::findElementsAroundSubfacet(const Mesh & mesh, const Mesh & mesh_facets, const Element & starting_element, const Element & end_facet, const Vector & subfacet_connectivity, std::vector & elem_list, std::vector & facet_list, std::vector * subfacet_list) { AKANTU_DEBUG_IN(); /// preallocated stuff before starting bool facet_matched = false; elem_list.resize(0); facet_list.resize(0); if (third_dim_points) subfacet_list->resize(0); elem_list.push_back(starting_element); const Array * facet_connectivity = NULL; const Array * sf_connectivity = NULL; const Array * facet_to_element = NULL; const Array * subfacet_to_facet = NULL; ElementType current_type = _not_defined; GhostType current_ghost_type = _casper; ElementType current_facet_type = _not_defined; GhostType current_facet_ghost_type = _casper; ElementType current_subfacet_type = _not_defined; GhostType current_subfacet_ghost_type = _casper; const Array< std::vector > * element_to_facet = NULL; const Element * opposing_el = NULL; Array elements_to_check; elements_to_check.resize(0); elements_to_check.push_back(starting_element); /// keep going until there are elements to check while (elements_to_check.getSize() != 0) { /// loop over each element to check for (UInt el = 0; el < elements_to_check.getSize(); ++el) { Element & current_el = elements_to_check(el); if (current_el.type != current_type || current_el.ghost_type != current_ghost_type) { current_type = current_el.type; current_ghost_type = current_el.ghost_type; facet_to_element = & mesh_facets.getSubelementToElement(current_type, current_ghost_type); } /// loop over each facet of the element for (UInt f = 0; f < facet_to_element->getNbComponent(); ++f) { const Element & current_facet = (*facet_to_element)(current_el.element, f); if (current_facet == ElementNull) continue; if (current_facet_type != current_facet.type || current_facet_ghost_type != current_facet.ghost_type) { current_facet_type = current_facet.type; current_facet_ghost_type = current_facet.ghost_type; element_to_facet = & mesh_facets.getElementToSubelement(current_facet_type, current_facet_ghost_type); facet_connectivity = & mesh_facets.getConnectivity(current_facet_type, current_facet_ghost_type); if (third_dim_points) subfacet_to_facet = & mesh_facets.getSubelementToElement(current_facet_type, current_facet_ghost_type); } /// check if end facet is reached if (current_facet == end_facet) facet_matched = true; /// add this facet if not already passed if (std::find(facet_list.begin(), facet_list.end(), current_facet) == facet_list.end() && hasElement(*facet_connectivity, current_facet, subfacet_connectivity)) { facet_list.push_back(current_facet); if (third_dim_points) { /// check subfacets for (UInt sf = 0; sf < subfacet_to_facet->getNbComponent(); ++sf) { const Element & current_subfacet = (*subfacet_to_facet)(current_facet.element, sf); if (current_subfacet == ElementNull) continue; if (current_subfacet_type != current_subfacet.type || current_subfacet_ghost_type != current_subfacet.ghost_type) { current_subfacet_type = current_subfacet.type; current_subfacet_ghost_type = current_subfacet.ghost_type; sf_connectivity = & mesh_facets.getConnectivity(current_subfacet_type, current_subfacet_ghost_type); } if (std::find(subfacet_list->begin(), subfacet_list->end(), current_subfacet) == subfacet_list->end() && hasElement(*sf_connectivity, current_subfacet, subfacet_connectivity)) subfacet_list->push_back(current_subfacet); } } } else continue; /// consider opposing element if ( (*element_to_facet)(current_facet.element)[0] == current_el) opposing_el = & (*element_to_facet)(current_facet.element)[1]; else opposing_el = & (*element_to_facet)(current_facet.element)[0]; /// skip null elements since they are on a boundary if (*opposing_el == ElementNull) continue; /// skip this element if already added if ( std::find(elem_list.begin(), elem_list.end(), *opposing_el) != elem_list.end() ) continue; /// only regular elements have to be checked if (opposing_el->kind == _ek_regular) elements_to_check.push_back(*opposing_el); elem_list.push_back(*opposing_el); #ifndef AKANTU_NDEBUG const Array & conn_elem = mesh.getConnectivity(opposing_el->type, opposing_el->ghost_type); AKANTU_DEBUG_ASSERT(hasElement(conn_elem, *opposing_el, subfacet_connectivity), "Subfacet doesn't belong to this element"); #endif } /// erased checked element from the list elements_to_check.erase(el); } } AKANTU_DEBUG_OUT(); return facet_matched; } /* -------------------------------------------------------------------------- */ /* Internal functions */ /* -------------------------------------------------------------------------- */ void MeshUtils::sortElements(std::vector & elements, const Vector facet, const Mesh & mesh, const Mesh & mesh_facets, const ByElementTypeReal & barycenters) { UInt spatial_dimension = mesh.getSpatialDimension(); UInt nb_element_connected_to_facet = elements.size(); const Array & mesh_facets_nodes = mesh_facets.getNodes(); const Array::const_iterator< Vector > mesh_facets_nodes_it = mesh_facets_nodes.begin(spatial_dimension); /// node around which the sorting is carried out is /// the first node of the current facet const Vector & first_node_coord = mesh_facets_nodes_it[facet(0)]; /// associate to each element a real value based on /// atan2 function (check wikipedia) std::map atan2; if (spatial_dimension == 3) { const Vector & second_node_coord = mesh_facets_nodes_it[facet(1)]; /// vector connecting facet first node to second Vector tangent(spatial_dimension); tangent = second_node_coord; tangent -= first_node_coord; tangent.normalize(); const Array::const_iterator< Vector > bar = barycenters(elements[0].type, elements[0].ghost_type).begin(spatial_dimension); /// vector connecting facet first node and /// barycenter of elements(0) Vector bary_coord(spatial_dimension); bary_coord.copy(bar[elements[0].element]); bary_coord -= first_node_coord; /// two normals to the segment facet to define the /// reference system Vector normal1(spatial_dimension); Vector normal2(spatial_dimension); /// get normal1 and normal2 normal1.crossProduct(tangent, bary_coord); normal1.normalize(); normal2.crossProduct(tangent, normal1); /// project the barycenter coordinates on the two /// normals to have them on the same plane atan2[elements[0]] = std::atan2(bary_coord.dot(normal2), bary_coord.dot(normal1)); for (UInt n = 1; n < nb_element_connected_to_facet; ++n) { const Array::const_iterator< Vector > bar_it = barycenters(elements[n].type, elements[n].ghost_type).begin(spatial_dimension); bary_coord.copy(bar_it[elements[n].element]); bary_coord -= first_node_coord; /// project the barycenter coordinates on the two /// normals to have them on the same plane atan2[elements[n]] = std::atan2(bary_coord.dot(normal2), bary_coord.dot(normal1)); } } else if (spatial_dimension == 2) { for (UInt n = 0; n < nb_element_connected_to_facet; ++n) { const Array::const_iterator< Vector > bar_it = barycenters(elements[n].type, elements[n].ghost_type).begin(spatial_dimension); Vector bary_coord(spatial_dimension); bary_coord.copy(bar_it[elements[n].element]); bary_coord -= first_node_coord; atan2[elements[n]] = std::atan2(bary_coord(1), bary_coord(0)); } } /// sort elements according to their atan2 values ElementSorter sorter(atan2); std::sort(elements.begin(), elements.end(), sorter); } __END_AKANTU__ // LocalWords: ElementType diff --git a/src/mesh_utils/mesh_utils.hh b/src/mesh_utils/mesh_utils.hh index 6f1dea896..e3875c54c 100644 --- a/src/mesh_utils/mesh_utils.hh +++ b/src/mesh_utils/mesh_utils.hh @@ -1,322 +1,306 @@ /** * @file mesh_utils.hh * * @author Guillaume Anciaux * @author David Simon Kammer * @author Leonardo Snozzi * @author Nicolas Richart * @author Marco Vocialta * * @date Fri Aug 20 12:19:44 2010 * * @brief All mesh utils necessary for various tasks * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" #include "aka_csr.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_UTILS_HH__ #define __AKANTU_MESH_UTILS_HH__ /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class MeshUtils { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MeshUtils(); virtual ~MeshUtils(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// build map from nodes to elements static void buildNode2Elements(const Mesh & mesh, CSR & node_to_elem, UInt spatial_dimension = _all_dimensions); static void buildNode2Elements(const Mesh & mesh, CSR & node_to_elem, UInt spatial_dimension = _all_dimensions); /// build map from nodes to elements for a specific element type static void buildNode2ElementsByElementType(const Mesh & mesh, CSR & node_to_elem, const ElementType & type, const GhostType & ghost_type = _not_ghost); /// build facets elements on boundary static void buildFacets(Mesh & mesh); /// build facets elements : boundary and internals (for serial simulations) static void buildAllFacets(Mesh & mesh, Mesh & mesh_facets); /// build facets elements : boundary and internals (for parallel simulations) static void buildAllFacetsParallel(Mesh & mesh, Mesh & mesh_facets, ByElementTypeUInt & prank_to_element); /// build facets for a given spatial dimension static void buildFacetsDimension(Mesh & mesh, Mesh & mesh_facets, bool boundary_only, UInt dimension, ByElementTypeUInt & prank_to_element); /// build normal to some elements // static void buildNormals(Mesh & mesh, UInt spatial_dimension=0); /// take the local_connectivity array as the array of local and ghost /// connectivity, renumber the nodes and set the connectivity of the mesh static void renumberMeshNodes(Mesh & mesh, UInt * local_connectivities, UInt nb_local_element, UInt nb_ghost_element, ElementType type, Array & old_nodes); // static void setUIntData(Mesh & mesh, UInt * data, UInt nb_tags, const ElementType & type); /// Detect closed surfaces of the mesh and save the surface id /// of the surface elements in the array surface_id static void buildSurfaceID(Mesh & mesh); /// compute pbc pair for on given direction static void computePBCMap(const Mesh & mymesh,const UInt dir, std::map & pbc_pair); /// compute pbc pair for a surface pair static void computePBCMap(const Mesh & mymesh, const std::pair & surface_pair, const ElementType type, std::map & pbc_pair); // /// tweak mesh connectivity to activate pbc // static void tweakConnectivityForPBC(Mesh & mesh, // bool flag_x, // bool flag_y = false, // bool flag_z = false); /// create a multimap of nodes per surfaces static void buildNodesPerSurface(const Mesh & mesh, CSR & nodes_per_surface); /// function to print the contain of the class // virtual void printself(std::ostream & stream, int indent = 0) const; /// remove not connected nodes /!\ this functions renumbers the nodes. static void purifyMesh(Mesh & mesh); - /// function to insert intrinsic cohesive elements in a zone - /// delimited by provided limits - static void insertIntrinsicCohesiveElementsInArea(Mesh & mesh, - const Array & limits); - - /// function to insert intrinsic cohesive elements on the selected - /// facets - static void insertIntrinsicCohesiveElements(Mesh & mesh, - Mesh & mesh_facets, - ElementType type_facet, - const Array & facet_insertion); - /// function to insert cohesive elements on the selected facets static void insertCohesiveElements(Mesh & mesh, Mesh & mesh_facets, - ByElementTypeArray & facet_insertion, - const bool extrinsic); + const ByElementTypeArray & facet_insertion, + Array & doubled_nodes, + Array & new_elements); /// fill the subelement to element and the elements to subelements data static void fillElementToSubElementsData(Mesh & mesh); /// flip facets based on global connectivity static void flipFacets(Mesh & mesh_facets, const ByElementTypeUInt & global_connectivity, GhostType gt_facet); /// provide list of elements around a node and check if a given /// facet is reached template static bool findElementsAroundSubfacet(const Mesh & mesh, const Mesh & mesh_facets, const Element & starting_element, const Element & end_facet, const Vector & subfacet_connectivity, std::vector & elem_list, std::vector & facet_list, std::vector * subfacet_list = NULL); /// function to check if a node belongs to a given element static inline bool hasElement(const Array & connectivity, const Element & el, const Vector & nodes); /// reset facet to double arrays static void resetFacetToDouble(Mesh & mesh_facets); private: /// match pairs that are on the associated pbc's static void matchPBCPairs(const Mesh & mymesh, const UInt dir, std::vector & selected_left, std::vector & selected_right, std::map & pbc_pair); /// function used by all the renumbering functions static void renumberNodesInConnectivity(UInt * list_nodes, UInt nb_nodes, std::map & renumbering_map); /// update facet_to_subfacet static void updateFacetToSubfacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode); /// update subfacet_to_facet static void updateSubfacetToFacet(Mesh & mesh_facets, ElementType type_subfacet, GhostType gt_subfacet, bool facet_mode); /// function to double a given facet and update the list of doubled /// nodes static void doubleFacet(Mesh & mesh, Mesh & mesh_facets, UInt facet_dimension, Array & doubled_nodes, bool facet_mode); /// function to double a subfacet given start and end index for /// local facet_to_subfacet vector, and update the list of doubled /// nodes template static void doubleSubfacet(Mesh & mesh, Mesh & mesh_facets, Array & doubled_nodes); /// double a node static void doubleNodes(Mesh & mesh, const Array & old_nodes, Array & doubled_nodes); /// fill facet_to_double array in the mesh static bool updateFacetToDouble(Mesh & mesh_facets, const ByElementTypeArray & facet_insertion); /// find subfacets to be doubled template static void findSubfacetToDouble(Mesh & mesh, Mesh & mesh_facets); /// double facets (points) in 1D static void doublePointFacet(Mesh & mesh, Mesh & mesh_facets, Array & doubled_nodes); /// update cohesive element data static void updateCohesiveData(Mesh & mesh, Mesh & mesh_facets, - NewElementsEvent & element_event); + Array & new_elements); /// update elemental connectivity after doubling a node inline static void updateElementalConnectivity(Mesh & mesh, UInt old_node, UInt new_node, const std::vector & element_list, const std::vector * facet_list = NULL); /// double middle nodes if facets are _segment_3 template static void updateQuadraticSegments(Mesh & mesh, Mesh & mesh_facets, ElementType type_facet, GhostType gt_facet, Array & doubled_nodes); - /// update nodes type and global ids for parallel simulations - static UInt updateGlobalIDs(Mesh & mesh, - Mesh & mesh_facets, - const Array & doubled_nodes); - /// remove elements on a vector inline static bool removeElementsInVector(const std::vector & elem_to_remove, std::vector & elem_list); static void sortElements(std::vector & elements, const Vector facet, const Mesh & mesh, const Mesh & mesh_facets, const ByElementTypeReal & barycenters); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; class ElementSorter { public: ElementSorter(const ElementSorter & e) : atan2(e.atan2) {} ElementSorter(std::map & atan2) : atan2(atan2) {} inline bool operator()(const Element & first, const Element & second); private: std::map & atan2; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #if defined (AKANTU_INCLUDE_INLINE_IMPL) # include "mesh_utils_inline_impl.cc" #endif /// standard output stream operator // inline std::ostream & operator <<(std::ostream & stream, const MeshUtils & _this) // { // _this.printself(stream); // return stream; // } __END_AKANTU__ #endif /* __AKANTU_MESH_UTILS_HH__ */ 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 e940ca56c..169cb5e4a 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,429 +1,428 @@ /** * @file material_cohesive_linear_extrinsic.cc * * @author Marco Vocialta * * @date Tue May 08 13:01:18 2012 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #include "material_cohesive_linear.hh" #include "solid_mechanics_model_cohesive.hh" #include "sparse_matrix.hh" #include "dof_synchronizer.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template MaterialCohesiveLinear::MaterialCohesiveLinear(SolidMechanicsModel & model, const ID & id) : MaterialCohesive(model,id), sigma_c_eff("sigma_c_eff", *this), delta_c("delta_c", *this), insertion_stress("insertion_stress", *this) { AKANTU_DEBUG_IN(); this->registerParam("beta" , beta , 0. , _pat_parsable | _pat_readable, "Beta parameter" ); this->registerParam("G_cI" , G_cI , 0. , _pat_parsable | _pat_readable, "Mode I fracture energy" ); this->registerParam("G_cII" , G_cII , 0. , _pat_parsable | _pat_readable, "Mode II fracture energy"); this->registerParam("penalty", penalty, 0. , _pat_parsable | _pat_readable, "Penalty coefficient" ); this->registerParam("kappa" , kappa , 1. , _pat_readable, "Kappa parameter"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialCohesiveLinear::initMaterial() { AKANTU_DEBUG_IN(); MaterialCohesive::initMaterial(); if (G_cII != 0) kappa = G_cII / G_cI; /// compute scalars beta2_kappa2 = beta * beta/kappa/kappa; beta2_kappa = beta * beta/kappa; if (beta == 0) beta2_inv = 0; else beta2_inv = 1./beta/beta; sigma_c_eff .initialize( 1); delta_c .initialize( 1); insertion_stress.initialize(spatial_dimension); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template -void MaterialCohesiveLinear::checkInsertion(const ByElementTypeReal & facet_stress, - ByElementTypeArray & facet_insertion) { +void MaterialCohesiveLinear::checkInsertion() { AKANTU_DEBUG_IN(); const Mesh & mesh_facets = model->getMeshFacets(); + CohesiveElementInserter & inserter = model->getElementInserter(); 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 = FEM::getCohesiveElementType(type_facet); - Array & facets_check = model->getFacetsCheck(type_facet); - Array & f_insertion = facet_insertion(type_facet); + const Array & facets_check = inserter.getCheckFacets(type_facet); + Array & f_insertion = inserter.getInsertionFacets(type_facet); Array & f_filter = facet_filter(type_facet); Array & sig_c_eff = sigma_c_eff(type_cohesive); Array & del_c = delta_c(type_cohesive); Array & ins_stress = insertion_stress(type_cohesive); Array & trac_old = tractions_old(type_cohesive); - const Array & f_stress = facet_stress(type_facet); + const Array & f_stress = model->getStressOnFacets(type_facet); const Array & sigma_lim = sigma_c(type_facet); UInt nb_quad_facet = model->getFEM("FacetsFEM").getNbQuadraturePoints(type_facet); UInt nb_facet = f_filter.getSize(); if (nb_facet == 0) continue; UInt tot_nb_quad = nb_facet * nb_quad_facet; Array stress_check (tot_nb_quad); Array normal_stress(tot_nb_quad, spatial_dimension); computeStressNorms(f_stress, stress_check, normal_stress, type_facet); Array::iterator > stress_check_it = stress_check.begin_reinterpret(nb_quad_facet, nb_facet); Array::iterator > normal_stress_it = normal_stress.begin_reinterpret(nb_quad_facet, spatial_dimension, nb_facet); Array::const_iterator sigma_lim_it = sigma_lim.begin(); for (UInt f = 0; f < nb_facet; ++f, ++sigma_lim_it, ++stress_check_it, ++normal_stress_it) { UInt facet = f_filter(f); if (!facets_check(facet)) continue; Real mean_stress = std::accumulate(stress_check_it->storage(), stress_check_it->storage() + nb_quad_facet, 0.); mean_stress /= nb_quad_facet; if (mean_stress > *sigma_lim_it) { + f_insertion(facet) = true; + for (UInt q = 0; q < nb_quad_facet; ++q) { Real new_sigma = (*stress_check_it)(q); Real new_delta = 2 * G_cI / new_sigma; Vector ins_s(normal_stress_it->storage() + q * spatial_dimension, spatial_dimension); if (spatial_dimension != 3) ins_s *= -1.; sig_c_eff.push_back(new_sigma); del_c.push_back(new_delta); ins_stress.push_back(ins_s); trac_old.push_back(ins_s); } #if defined (AKANTU_DEBUG_TOOLS) && defined(AKANTU_CORE_CXX11) debug::element_manager.print(debug::_dm_material_cohesive, [facet, type_facet, nb_quad_facet, &f_stress](const Element & el)->std::string { std::stringstream sout; Element facet_el(type_facet, facet, _not_ghost); if(facet_el == el) { Array::const_iterator< Vector > stress = f_stress.begin(f_stress.getNbComponent()); stress += nb_quad_facet * facet; for (UInt qs = 0; qs < nb_quad_facet; ++qs, ++stress) { sout << *stress; } } return sout.str(); }); #endif - - f_insertion(facet) = true; - facets_check(facet) = false; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template inline void MaterialCohesiveLinear::computeEffectiveNorm(const Matrix & stress, const Vector & normal, const Vector & tangent, Vector & normal_stress, Real & effective_norm) { AKANTU_DEBUG_IN(); normal_stress.mul(stress, normal); Real normal_contrib = normal_stress.dot(normal); /// in 3D tangential components must be summed Real tangent_contrib = 0; if (spatial_dimension == 2) { Real tangent_contrib_tmp = normal_stress.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 tangent_v(tangent.storage() + s * spatial_dimension, spatial_dimension); Real tangent_contrib_tmp = normal_stress.dot(tangent_v); tangent_contrib += tangent_contrib_tmp * tangent_contrib_tmp; } } tangent_contrib = std::sqrt(tangent_contrib); normal_contrib = std::max(0., normal_contrib); effective_norm = std::sqrt(normal_contrib * normal_contrib + tangent_contrib * tangent_contrib * beta2_inv); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialCohesiveLinear::computeStressNorms(const Array & facet_stress, Array & stress_check, Array & normal_stress, ElementType type_facet) { AKANTU_DEBUG_IN(); - Array & facets_check = model->getFacetsCheck(type_facet); + Array & facets_check = model->getElementInserter().getCheckFacets(type_facet); Array & f_filter = facet_filter(type_facet); UInt nb_quad_facet = model->getFEM("FacetsFEM").getNbQuadraturePoints(type_facet); const Array & tangents = model->getTangents(type_facet); const Array & normals = model->getFEM("FacetsFEM").getNormalsOnQuadPoints(type_facet); Real * stress_check_it = stress_check.storage(); Array::const_iterator< Vector > normal_begin = normals.begin(spatial_dimension); Array::const_iterator< Vector > tangent_begin = tangents.begin(tangents.getNbComponent()); Array::const_iterator< Matrix > facet_stress_begin = facet_stress.begin(spatial_dimension, spatial_dimension * 2); Array::iterator > normal_stress_it = normal_stress.begin(spatial_dimension); Matrix stress_tmp(spatial_dimension, spatial_dimension); UInt nb_facet = f_filter.getSize(); UInt sp2 = spatial_dimension * spatial_dimension; UInt * current_facet = f_filter.storage(); for (UInt f = 0; f < nb_facet; ++f, ++current_facet) { if (!facets_check(*current_facet)) { stress_check_it += nb_quad_facet; normal_stress_it += nb_quad_facet; continue; } UInt current_quad = *current_facet * nb_quad_facet; for (UInt q = 0; q < nb_quad_facet; ++q, ++stress_check_it, ++normal_stress_it, ++current_quad) { const Vector & normal = normal_begin[current_quad]; const Vector & tangent = tangent_begin[current_quad]; const Matrix & facet_stress_it = facet_stress_begin[current_quad]; /// compute average stress Matrix stress_1(facet_stress_it.storage(), spatial_dimension, spatial_dimension); Matrix stress_2(facet_stress_it.storage() + sp2, spatial_dimension, spatial_dimension); stress_tmp.copy(stress_1); stress_tmp += stress_2; stress_tmp /= 2.; /// compute normal, tangential and effective stress computeEffectiveNorm(stress_tmp, normal, tangent, *normal_stress_it, *stress_check_it); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MaterialCohesiveLinear::computeTraction(const Array & normal, ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); /// define iterators Array::iterator< Vector > traction_it = tractions(el_type, ghost_type).begin(spatial_dimension); Array::iterator< Vector > opening_it = opening(el_type, ghost_type).begin(spatial_dimension); Array::iterator< Vector > contact_traction_it = contact_tractions(el_type, ghost_type).begin(spatial_dimension); Array::iterator< Vector > contact_opening_it = contact_opening(el_type, ghost_type).begin(spatial_dimension); Array::const_iterator< Vector > normal_it = normal.begin(spatial_dimension); Array::iterator< Vector >traction_end = tractions(el_type, ghost_type).end(spatial_dimension); Array::iteratorsigma_c_it = sigma_c_eff(el_type, ghost_type).begin(); Array::iteratordelta_max_it = delta_max(el_type, ghost_type).begin(); Array::iteratordelta_c_it = delta_c(el_type, ghost_type).begin(); Array::iteratordamage_it = damage(el_type, ghost_type).begin(); Array::iterator > insertion_stress_it = insertion_stress(el_type, ghost_type).begin(spatial_dimension); Real * memory_space = new Real[2*spatial_dimension]; Vector normal_opening(memory_space, spatial_dimension); Vector 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) { /// 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; /// don't consider penetration contribution for delta if (normal_opening_norm > 0) { delta += normal_opening_norm * normal_opening_norm; contact_traction_it->clear(); contact_opening_it->clear(); } else { /// use penalty coefficient in case of penetration *contact_traction_it = normal_opening; *contact_traction_it *= penalty; *contact_opening_it = normal_opening; *opening_it = tangential_opening; normal_opening.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(*delta_max_it, 0.)) { if (normal_opening_norm > 0.) *traction_it = *insertion_stress_it; else traction_it->clear(); } 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(); } /* -------------------------------------------------------------------------- */ INSTANSIATE_MATERIAL(MaterialCohesiveLinear); __END_AKANTU__ diff --git a/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.hh b/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.hh index 459da582e..7b197601f 100644 --- a/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.hh +++ b/src/model/solid_mechanics/materials/material_cohesive/constitutive_laws/material_cohesive_linear.hh @@ -1,150 +1,149 @@ /** * @file material_cohesive_linear_extrinsic.hh * * @author Marco Vocialta * * @date Tue May 08 13:01:18 2012 * * @brief Linear irreversible cohesive law of mixed mode loading with * random stress definition for extrinsic type * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "material_cohesive.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_COHESIVE_LINEAR_HH__ #define __AKANTU_MATERIAL_COHESIVE_LINEAR_HH__ /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /** * Cohesive material linear damage for extrinsic case * * parameters in the material files : * - sigma_c : critical stress sigma_c (default: 0) * - beta : weighting parameter for sliding and normal opening (default: 0) * - G_cI : fracture energy for mode I (default: 0) * - G_cII : fracture energy for mode II (default: 0) * - penalty : stiffness in compression to prevent penetration */ template class MaterialCohesiveLinear : public MaterialCohesive { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MaterialCohesiveLinear(SolidMechanicsModel & model, const ID & id = ""); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material computed parameter virtual void initMaterial(); /// check stress for cohesive elements' insertion - virtual void checkInsertion(const ByElementTypeReal & facet_stress, - ByElementTypeArray & facet_insertion); + virtual void checkInsertion(); protected: /// constitutive law void computeTraction(const Array & normal, ElementType el_type, GhostType ghost_type = _not_ghost); /// compute stress norms on quadrature points for each facet for stress check virtual void computeStressNorms(const Array & facet_stress, Array & stress_check, Array & normal_stress, ElementType type_facet); /// compute effective stress norm for insertion check inline void computeEffectiveNorm(const Matrix & stress, const Vector & normal, const Vector & tangent, Vector & normal_stress, Real & effective_norm); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get sigma_c_eff AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(InsertionTraction, sigma_c_eff, Real); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// beta parameter Real beta; /// beta square inverse to compute effective norm Real beta2_inv; /// mode I fracture energy Real G_cI; /// mode II fracture energy Real G_cII; /// kappa parameter Real kappa; /// constitutive law scalar to compute delta Real beta2_kappa2; /// constitutive law scalar to compute traction Real beta2_kappa; /// penalty coefficient Real penalty; /// critical effective stress CohesiveInternalField sigma_c_eff; /// critical displacement CohesiveInternalField delta_c; /// stress at insertion CohesiveInternalField insertion_stress; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ //#include "material_cohesive_linear_inline_impl.cc" __END_AKANTU__ #endif /* __AKANTU_MATERIAL_COHESIVE_LINEAR_HH__ */ diff --git a/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.hh b/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.hh index 2b43f1622..43f1e24fe 100644 --- a/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.hh +++ b/src/model/solid_mechanics/materials/material_cohesive/material_cohesive.hh @@ -1,244 +1,244 @@ /** * @file material_cohesive.hh * * @author Seyedeh Mohadeseh Taheri Mousavi * @author Marco Vocialta * * @date Wed Feb 22 16:31:20 2012 * * @brief Specialization of the material class for cohesive elements * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "material.hh" #include "fem_template.hh" #include "aka_common.hh" #include "cohesive_internal_field.hh" +#include "cohesive_element_inserter.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_COHESIVE_HH__ #define __AKANTU_MATERIAL_COHESIVE_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class SolidMechanicsModelCohesive; } __BEGIN_AKANTU__ class MaterialCohesive : public Material { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: typedef FEMTemplate MyFEMCohesiveType; + ShapeLagrange, _ek_cohesive> MyFEMCohesiveType; public: MaterialCohesive(SolidMechanicsModel& model, const ID & id = ""); virtual ~MaterialCohesive(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material computed parameter virtual void initMaterial(); /// resize vectors for new cohesive elements virtual void resizeCohesiveArrays(); /// init arrays for automatic element insertion virtual void initInsertionArrays(const Mesh & mesh_facets); /// compute tractions (including normals and openings) void computeTraction(GhostType ghost_type = _not_ghost); /// assemble residual void assembleResidual(GhostType ghost_type = _not_ghost); /// compute reversible and total energies by element void computeEnergies(); /// check stress for cohesive elements' insertion - virtual void checkInsertion(const ByElementTypeReal & facet_stress, - ByElementTypeArray & facet_insertion) { + virtual void checkInsertion() { AKANTU_DEBUG_TO_IMPLEMENT(); } /// interpolate stress on given positions for each element (empty /// implemantation to avoid the generic call to be done on cohesive elements) virtual void interpolateStress(__attribute__((unused)) const ElementType type, __attribute__((unused)) Array & result) { }; virtual void computeAllStresses(__attribute__((unused)) GhostType ghost_type = _not_ghost) { }; // add the facet to be handled by the material UInt addFacet(const Element & element); protected: virtual void computeTangentTraction(__attribute__((unused)) const ElementType & el_type, __attribute__((unused)) Array & tangent_matrix, __attribute__((unused)) const Array & normal, __attribute__((unused)) GhostType ghost_type = _not_ghost) { AKANTU_DEBUG_TO_IMPLEMENT(); } void computeNormal(const Array & position, Array & normal, ElementType type, GhostType ghost_type); void computeOpening(const Array & displacement, Array & normal, ElementType type, GhostType ghost_type); template void computeNormal(const Array & position, Array & normal, GhostType ghost_type); /// assemble stiffness void assembleStiffnessMatrix(GhostType ghost_type); /// constitutive law virtual void computeTraction(const Array & normal, ElementType el_type, GhostType ghost_type = _not_ghost) = 0; /// parallelism functions inline UInt getNbDataForElements(const Array & elements, SynchronizationTag tag) const; inline void packElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) const; inline void unpackElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the opening AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Opening, opening, Real); /// get the traction AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Traction, tractions, Real); /// get damage AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Damage, damage, Real); /// get facet filter AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(FacetFilter, facet_filter, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(FacetFilter, facet_filter, UInt); AKANTU_GET_MACRO(FacetFilter, facet_filter, const ByElementTypeUInt &); // AKANTU_GET_MACRO(ElementFilter, element_filter, const ByElementTypeUInt &); /// compute reversible energy Real getReversibleEnergy(); /// compute dissipated energy Real getDissipatedEnergy(); /// compute contact energy Real getContactEnergy(); /// get energy virtual Real getEnergy(std::string type); /// return the energy (identified by id) for the provided element virtual Real getEnergy(std::string energy_id, ElementType type, UInt index) { return Material::getEnergy(energy_id, type, index); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// list of facets assigned to this material ByElementTypeUInt facet_filter; /// Link to the cohesive fem object in the model MyFEMCohesiveType * fem_cohesive; private: /// reversible energy by quadrature point CohesiveInternalField reversible_energy; /// total energy by quadrature point CohesiveInternalField total_energy; protected: /// opening in all elements and quadrature points CohesiveInternalField opening; /// opening in all elements and quadrature points (previous time step) CohesiveInternalField opening_old; /// traction in all elements and quadrature points CohesiveInternalField tractions; /// traction in all elements and quadrature points (previous time step) CohesiveInternalField tractions_old; /// traction due to contact CohesiveInternalField contact_tractions; /// normal openings for contact tractions CohesiveInternalField contact_opening; /// maximum displacement CohesiveInternalField delta_max; /// damage CohesiveInternalField damage; /// pointer to the solid mechanics model for cohesive elements SolidMechanicsModelCohesive * model; /// critical stress RandomInternalField sigma_c; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "material_cohesive_inline_impl.cc" __END_AKANTU__ #include "cohesive_internal_field_tmpl.hh" #endif /* __AKANTU_MATERIAL_COHESIVE_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model.hh b/src/model/solid_mechanics/solid_mechanics_model.hh index 97be2e14c..206b193af 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.hh +++ b/src/model/solid_mechanics/solid_mechanics_model.hh @@ -1,675 +1,665 @@ /** * @file solid_mechanics_model.hh * * @author Guillaume Anciaux * @author Nicolas Richart * * @date Tue Jul 27 18:15:37 2010 * * @brief Model of Solid Mechanics * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLID_MECHANICS_MODEL_HH__ #define __AKANTU_SOLID_MECHANICS_MODEL_HH__ /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_types.hh" #include "model.hh" #include "data_accessor.hh" #include "mesh.hh" #include "dumpable.hh" #include "boundary_condition.hh" #include "integrator_gauss.hh" #include "shape_lagrange.hh" #include "integration_scheme_2nd_order.hh" #include "solver.hh" #include "material_selector.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class Material; class IntegrationScheme2ndOrder; class Contact; class SparseMatrix; } __BEGIN_AKANTU__ struct SolidMechanicsModelOptions : public ModelOptions { SolidMechanicsModelOptions(AnalysisMethod analysis_method = _explicit_lumped_mass, bool no_init_materials = false) : analysis_method(analysis_method), no_init_materials(no_init_materials) {} AnalysisMethod analysis_method; bool no_init_materials; }; extern const SolidMechanicsModelOptions default_solid_mechanics_model_options; class SolidMechanicsModel : public Model, public DataAccessor, public MeshEventHandler, public Dumpable, public BoundaryCondition { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: class NewMaterialElementsEvent : public NewElementsEvent { public: AKANTU_GET_MACRO_NOT_CONST(MaterialList, material, Array &); AKANTU_GET_MACRO(MaterialList, material, const Array &); protected: Array material; }; typedef FEMTemplate MyFEMType; SolidMechanicsModel(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "solid_mechanics_model", const MemoryID & memory_id = 0); virtual ~SolidMechanicsModel(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize completely the model virtual void initFull(std::string material_file, const ModelOptions & options = default_solid_mechanics_model_options); /// initialize the fem object needed for boundary conditions void initFEMBoundary(); /// register the tags associated with the parallel synchronizer void initParallel(MeshPartition * partition, DataAccessor * data_accessor=NULL); /// allocate all vectors void initArrays(); /// allocate all vectors void initArraysPreviousDisplacment(); /// initialize all internal arrays for materials virtual void initMaterials(); /// initialize the model virtual void initModel(); /// init PBC synchronizer void initPBC(); /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; /* ------------------------------------------------------------------------ */ /* PBC */ /* ------------------------------------------------------------------------ */ public: /// change the equation number for proper assembly when using PBC void changeEquationNumberforPBC(std::map & pbc_pair); /// synchronize Residual for output void synchronizeResidual(); protected: /// register PBC synchronizer void registerPBCSynchronizer(); /* ------------------------------------------------------------------------ */ /* Explicit */ /* ------------------------------------------------------------------------ */ public: /// initialize the stuff for the explicit scheme void initExplicit(AnalysisMethod analysis_method = _explicit_lumped_mass); bool isExplicit() { return method == _explicit_lumped_mass || method == _explicit_consistent_mass; } /// initialize the array needed by updateResidual (residual, current_position) void initializeUpdateResidualData(); /// update the current position vector void updateCurrentPosition(); /// assemble the residual for the explicit scheme virtual void updateResidual(bool need_initialize = true); /** * \brief compute the acceleration from the residual * this function is the explicit equivalent to solveDynamic in implicit * In the case of lumped mass just divide the residual by the mass * In the case of not lumped mass call solveDynamic<_acceleration_corrector> */ void updateAcceleration(); void updateIncrement(); void updatePreviousDisplacement(); /// Solve the system @f[ A x = \alpha b @f] with A a lumped matrix void solveLumped(Array & x, const Array & A, const Array & b, const Array & boundary, Real alpha); /// explicit integration predictor void explicitPred(); /// explicit integration corrector void explicitCorr(); public: void solveStep(); /* ------------------------------------------------------------------------ */ /* Implicit */ /* ------------------------------------------------------------------------ */ public: /// initialize the solver and the jacobian_matrix (called by initImplicit) void initSolver(SolverOptions & options = _solver_no_options); /// initialize the stuff for the implicit solver void initImplicit(bool dynamic = false, SolverOptions & solver_options = _solver_no_options); /// solve Ma = f to get the initial acceleration void initialAcceleration(); /// assemble the stiffness matrix void assembleStiffnessMatrix(); public: template bool solveStep(Real tolerance, UInt max_iteration = 100); public: /// solve @f[ A\delta u = f_ext - f_int @f] in displacement void solveDynamic(); /// solve Ku = f void solveStatic(); /// solve Ku = f void solveStatic(Array & boundary_normal, Array & EulerAngles); /// test if the system is converged template bool testConvergence(Real tolerance, Real & error); /// test the convergence (norm of increment) bool testConvergenceIncrement(Real tolerance) __attribute__((deprecated)); bool testConvergenceIncrement(Real tolerance, Real & error) __attribute__((deprecated)); /// test the convergence (norm of residual) bool testConvergenceResidual(Real tolerance) __attribute__((deprecated)); bool testConvergenceResidual(Real tolerance, Real & error) __attribute__((deprecated)); /// create and return the velocity damping matrix SparseMatrix & initVelocityDampingMatrix(); /// implicit time integration predictor void implicitPred(); /// implicit time integration corrector void implicitCorr(); protected: /// finish the computation of residual to solve in increment void updateResidualInternal(); /// compute the support reaction and store it in force void updateSupportReaction(); public: //protected: Daniel changed it just for a test /// compute A and solve @f[ A\delta u = f_ext - f_int @f] template void solve(Array & increment); /* ------------------------------------------------------------------------ */ /* Explicit/Implicit */ /* ------------------------------------------------------------------------ */ public: /// Update the stresses for the computation of the residual of the Stiffness /// matrix in the case of finite deformation void computeStresses(); /// synchronize the ghost element boundaries values void synchronizeBoundaries(); /* ------------------------------------------------------------------------ */ /* Materials (solid_mechanics_model_material.cc) */ /* ------------------------------------------------------------------------ */ public: /// registers all the custom materials of a given type present in the input file template void registerNewCustomMaterials(const ID & mat_type); /// register an empty material of a given type template Material & registerNewEmptyMaterial(const std::string & name); // /// Use a UIntData in the mesh to specify the material to use per element // void setMaterialIDsFromIntData(const std::string & data_name); protected: /// register a material in the dynamic database template Material & registerNewMaterial(const ParserSection & mat_section); /// read the material files to instantiate all the materials void instantiateMaterials(); /* ------------------------------------------------------------------------ */ /* Mass (solid_mechanics_model_mass.cc) */ /* ------------------------------------------------------------------------ */ public: /// assemble the lumped mass matrix void assembleMassLumped(); /// assemble the mass matrix for consistent mass resolutions void assembleMass(); protected: /// assemble the lumped mass matrix for local and ghost elements void assembleMassLumped(GhostType ghost_type); /// assemble the mass matrix for either _ghost or _not_ghost elements void assembleMass(GhostType ghost_type); /// fill a vector of rho void computeRho(Array & rho, ElementType type, GhostType ghost_type); /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ public: inline virtual UInt getNbDataForElements(const Array & elements, SynchronizationTag tag) const; inline virtual void packElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) const; inline virtual void unpackElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag); inline virtual UInt getNbDataToPack(SynchronizationTag tag) const; inline virtual UInt getNbDataToUnpack(SynchronizationTag tag) const; inline virtual void packData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag) const; inline virtual void unpackData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag); protected: inline void splitElementByMaterial(const Array & elements, Array * elements_per_mat) const; - inline virtual void packBarycenter(const Mesh & mesh, - CommunicationBuffer & buffer, - const Array & elements, - SynchronizationTag tag) const; - - inline virtual void unpackBarycenter(const Mesh & mesh, - CommunicationBuffer & buffer, - const Array & elements, - SynchronizationTag tag); - /* ------------------------------------------------------------------------ */ /* Mesh Event Handler inherited members */ /* ------------------------------------------------------------------------ */ protected: virtual void onNodesAdded (const Array & nodes_list, const NewNodesEvent & event); virtual void onNodesRemoved(const Array & element_list, const Array & new_numbering, const RemovedNodesEvent & event); virtual void onElementsAdded (const Array & nodes_list, const NewElementsEvent & event); virtual void onElementsRemoved(const Array & element_list, const ByElementTypeUInt & new_numbering, const RemovedElementsEvent & event); /* ------------------------------------------------------------------------ */ /* Dumpable interface */ /* ------------------------------------------------------------------------ */ public: virtual void addDumpFieldToDumper(const std::string & dumper_name, const std::string & field_id); virtual void addDumpGroupField(const std::string & field_id, const std::string & group_name); virtual void addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name); virtual void removeDumpGroupField(const std::string & field_id, const std::string & group_name); virtual void removeDumpGroupFieldFromDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name); virtual void addDumpFieldVectorToDumper(const std::string & dumper_name, const std::string & field_id); virtual void addDumpGroupFieldVector(const std::string & field_id, const std::string & group_name); virtual void addDumpGroupFieldVectorToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name); virtual void addDumpFieldTensorToDumper(const std::string & dumper_name, const std::string & field_id); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// return the dimension of the system space AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// get the current value of the time step AKANTU_GET_MACRO(TimeStep, time_step, Real); /// set the value of the time step void setTimeStep(Real time_step); /// get the value of the conversion from forces/ mass to acceleration AKANTU_GET_MACRO(F_M2A, f_m2a, Real); /// set the value of the conversion from forces/ mass to acceleration AKANTU_SET_MACRO(F_M2A, f_m2a, Real); /// get the SolidMechanicsModel::displacement vector AKANTU_GET_MACRO(Displacement, *displacement, Array &); /// get the SolidMechanicsModel::previous_displacement vector AKANTU_GET_MACRO(PreviousDisplacement, *previous_displacement, Array &); /// get the SolidMechanicsModel::current_position vector \warn only consistent /// after a call to SolidMechanicsModel::updateCurrentPosition AKANTU_GET_MACRO(CurrentPosition, *current_position, const Array &); /// get the SolidMechanicsModel::increment vector \warn only consistent if /// SolidMechanicsModel::setIncrementFlagOn has been called before AKANTU_GET_MACRO(Increment, *increment, Array &); /// get the lumped SolidMechanicsModel::mass vector AKANTU_GET_MACRO(Mass, *mass, Array &); /// get the SolidMechanicsModel::velocity vector AKANTU_GET_MACRO(Velocity, *velocity, Array &); /// get the SolidMechanicsModel::acceleration vector, updated by /// SolidMechanicsModel::updateAcceleration AKANTU_GET_MACRO(Acceleration, *acceleration, Array &); /// get the SolidMechanicsModel::force vector (boundary forces) AKANTU_GET_MACRO(Force, *force, Array &); /// get the SolidMechanicsModel::residual vector, computed by /// SolidMechanicsModel::updateResidual AKANTU_GET_MACRO(Residual, *residual, Array &); /// get the SolidMechanicsModel::boundary vector AKANTU_GET_MACRO(Boundary, *boundary, Array &); /// get the SolidMechnicsModel::incrementAcceleration vector AKANTU_GET_MACRO(IncrementAcceleration, *increment_acceleration, Array &); /// get the value of the SolidMechanicsModel::increment_flag AKANTU_GET_MACRO(IncrementFlag, increment_flag, bool); /// get a particular material (by material index) inline Material & getMaterial(UInt mat_index); /// get a particular material (by material index) inline const Material & getMaterial(UInt mat_index) const; /// get a particular material (by material name) inline Material & getMaterial(const std::string & name); /// get a particular material (by material name) inline const Material & getMaterial(const std::string & name) const; /// get a particular material id from is name inline UInt getMaterialIndex(const std::string & name) const; /// give the number of materials inline UInt getNbMaterials() const { return materials.size(); }; inline void setMaterialSelector(MaterialSelector & selector); /// give the material internal index from its id Int getInternalIndexFromID(const ID & id) const; /// compute the stable time step Real getStableTimeStep(); /// compute the potential energy Real getPotentialEnergy(); /// compute the kinetic energy Real getKineticEnergy(); Real getKineticEnergy(const ElementType & type, UInt index); /// compute the external work (for impose displacement, the velocity should be given too) Real getExternalWork(); /// get the energies Real getEnergy(const std::string & energy_id); /// compute the energy for energy Real getEnergy(const std::string & energy_id, const ElementType & type, UInt index); /// set the Contact object AKANTU_SET_MACRO(Contact, contact, Contact *); /** * @brief set the SolidMechanicsModel::increment_flag to on, the activate the * update of the SolidMechanicsModel::increment vector */ void setIncrementFlagOn(); /// get the stiffness matrix AKANTU_GET_MACRO(StiffnessMatrix, *stiffness_matrix, SparseMatrix &); /// get the mass matrix AKANTU_GET_MACRO(MassMatrix, *mass_matrix, SparseMatrix &); /// get the velocity damping matrix AKANTU_GET_MACRO(VelocityDampingMatrix, *velocity_damping_matrix, SparseMatrix &); /// get the FEM object to integrate or interpolate on the boundary inline FEM & getFEMBoundary(const ID & name = ""); /// get integrator AKANTU_GET_MACRO(Integrator, *integrator, const IntegrationScheme2ndOrder &); /// get access to the internal solver AKANTU_GET_MACRO(Solver, *solver, Solver &); /// get synchronizer AKANTU_GET_MACRO(Synchronizer, *synch_parallel, const DistributedSynchronizer &); AKANTU_GET_MACRO(ElementIndexByMaterial, element_index_by_material, const ByElementTypeArray &); /// vectors containing local material element index for each global element index AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ElementIndexByMaterial, element_index_by_material, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(ElementIndexByMaterial, element_index_by_material, UInt); protected: friend class Material; template class WeightFunction> friend class MaterialNonLocal; protected: /// compute the stable time step Real getStableTimeStep(const GhostType & ghost_type); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// time step Real time_step; /// conversion coefficient form force/mass to acceleration Real f_m2a; /// displacements array Array * displacement; /// displacements array at the previous time step (used in finite deformation) Array * previous_displacement; /// lumped mass array Array * mass; /// velocities array Array * velocity; /// accelerations array Array * acceleration; /// accelerations array Array * increment_acceleration; /// forces array Array * force; /// residuals array Array * residual; /// boundaries array Array * boundary; /// array of current position used during update residual Array * current_position; /// mass matrix SparseMatrix * mass_matrix; /// velocity damping matrix SparseMatrix * velocity_damping_matrix; /// stiffness matrix SparseMatrix * stiffness_matrix; /// jacobian matrix @f[A = cM + dD + K@f] with @f[c = \frac{1}{\beta \Delta /// t^2}, d = \frac{\gamma}{\beta \Delta t} @f] SparseMatrix * jacobian_matrix; /// vectors containing local material element index for each global element index ByElementTypeUInt element_index_by_material; /// list of used materials std::vector materials; /// mapping between material name and material internal id std::map materials_names_to_id; /// class defining of to choose a material MaterialSelector * material_selector; /// define if it is the default selector or not bool is_default_material_selector; /// integration scheme of second order used IntegrationScheme2ndOrder * integrator; /// increment of displacement Array * increment; /// flag defining if the increment must be computed or not bool increment_flag; /// solver for implicit Solver * solver; /// object to resolve the contact Contact * contact; /// analysis method check the list in akantu::AnalysisMethod AnalysisMethod method; /// internal synchronizer for parallel computations DistributedSynchronizer * synch_parallel; /// tells if the material are instantiated bool are_materials_instantiated; }; __END_AKANTU__ /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "parser.hh" #include "material.hh" __BEGIN_AKANTU__ #include "solid_mechanics_model_tmpl.hh" #if defined (AKANTU_INCLUDE_INLINE_IMPL) # include "solid_mechanics_model_inline_impl.cc" #endif /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const SolidMechanicsModel & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #include "material_selector_tmpl.hh" #endif /* __AKANTU_SOLID_MECHANICS_MODEL_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive.cc index 7576db631..dcd6f3979 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive.cc @@ -1,1224 +1,998 @@ /** * @file solid_mechanics_model_cohesive.cc * * @author Marco Vocialta * * @date Tue May 08 13:01:18 2012 * * @brief Solid mechanics model for cohesive elements * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "shape_cohesive.hh" #include "solid_mechanics_model_cohesive.hh" #include "material_cohesive.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ const SolidMechanicsModelCohesiveOptions default_solid_mechanics_model_cohesive_options(_explicit_lumped_mass, false, false, true, true); /* -------------------------------------------------------------------------- */ SolidMechanicsModelCohesive::SolidMechanicsModelCohesive(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) : SolidMechanicsModel(mesh, dim, id, memory_id), mesh_facets(mesh.initMeshFacets()), - facets_check("facets_check", id), tangents("tangents", id), stress_on_facet("stress_on_facet", id), facet_stress("facet_stress", id), fragment_to_element("fragment_to_element", id), fragment_velocity(0, spatial_dimension, "fragment_velocity"), fragment_center(0, spatial_dimension, "fragment_center"), - facet_insertion("facet_insertion", id), - cohesive_el_to_facet("cohesive_el_to_facet", id), - facet_material("facet_material", id) { + facet_material("facet_material", id), + inserter(mesh, mesh_facets) { AKANTU_DEBUG_IN(); facet_generated = false; #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) facet_synchronizer = NULL; facet_stress_synchronizer = NULL; cohesive_distributed_synchronizer = NULL; - global_connectivity = NULL; rank_to_element = NULL; + global_connectivity = NULL; #endif delete material_selector; material_selector = new DefaultMaterialCohesiveSelector(*this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SolidMechanicsModelCohesive::~SolidMechanicsModelCohesive() { AKANTU_DEBUG_IN(); #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) delete cohesive_distributed_synchronizer; delete facet_synchronizer; delete facet_stress_synchronizer; delete rank_to_element; #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initFull(std::string material_file, const ModelOptions & options) { AKANTU_DEBUG_IN(); const SolidMechanicsModelCohesiveOptions & smmc_options = dynamic_cast(options); this->stress_interpolation = smmc_options.stress_interpolation; this->is_extrinsic = smmc_options.extrinsic; if (is_extrinsic) { if (!facet_generated) MeshUtils::buildAllFacets(mesh, mesh_facets); } SolidMechanicsModel::initFull(material_file, options); - mesh_facets.initByElementTypeArray(facets_check, 1, spatial_dimension - 1); - - if (is_extrinsic) { + if (is_extrinsic) initAutomaticInsertion(); - initFacetsCheck(); - -#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) - if (facet_stress_synchronizer != NULL) { - DataAccessor * data_accessor = this; - facet_stress_synchronizer->updateFacetStressSynchronizer(facets_check, - *rank_to_element, - *data_accessor); - } -#endif - } // if(material_file != "") // initCohesiveMaterials(smmc_options.extrinsic, smmc_options.init_facet_filter); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initMaterials() { AKANTU_DEBUG_IN(); + /// init element inserter + inserter.init(); + +#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) + if (facet_synchronizer != NULL) + inserter.initParallel(facet_synchronizer); + + if (facet_stress_synchronizer != NULL) { + DataAccessor * data_accessor = this; + facet_stress_synchronizer->updateFacetStressSynchronizer(inserter, + *rank_to_element, + *data_accessor); + } +#endif + // make sure the material are instantiated if(!are_materials_instantiated) instantiateMaterials(); /// find the first cohesive material UInt cohesive_index = 0; while ((dynamic_cast(materials[cohesive_index]) == NULL) && cohesive_index <= materials.size()) ++cohesive_index; AKANTU_DEBUG_ASSERT(cohesive_index != materials.size(), "No cohesive materials in the material input file"); material_selector->setFallback(cohesive_index); // set the facet information in the material in case of dynamic insertion mesh_facets.initByElementTypeArray(facet_material, 1, spatial_dimension - 1); if (is_extrinsic) { Element element; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { element.ghost_type = *gt; Mesh::type_iterator first = mesh_facets.firstType(spatial_dimension - 1, *gt); Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1, *gt); for(;first != last; ++first) { element.type = *first; Array & f_material = facet_material(*first, *gt); UInt nb_element = mesh_facets.getNbElement(*first, *gt); f_material.resize(nb_element); f_material.set(cohesive_index); for (UInt el = 0; el < nb_element; ++el) { element.element = el; UInt mat_index = (*material_selector)(element); f_material(el) = mat_index; MaterialCohesive & mat = dynamic_cast(*materials[mat_index]); mat.addFacet(element); } } } } else { for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { Mesh::type_iterator first = mesh.firstType(spatial_dimension, *gt, _ek_cohesive); Mesh::type_iterator last = mesh.lastType(spatial_dimension, *gt, _ek_cohesive); for(;first != last; ++first) { Array & el_id_by_mat = element_index_by_material(*first, *gt); Vector el_mat(2); el_mat(0) = cohesive_index; el_mat(1) = 0; el_id_by_mat.set(el_mat); } } } SolidMechanicsModel::initMaterials(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Initialize the model,basically it pre-compute the shapes, shapes derivatives * and jacobian * */ void SolidMechanicsModelCohesive::initModel() { AKANTU_DEBUG_IN(); SolidMechanicsModel::initModel(); registerFEMObject("CohesiveFEM", mesh, spatial_dimension); /// add cohesive type connectivity ElementType type = _not_defined; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType type_ghost = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension, type_ghost); Mesh::type_iterator last = mesh.lastType(spatial_dimension, type_ghost); for (; it != last; ++it) { const Array & connectivity = mesh.getConnectivity(*it, type_ghost); if (connectivity.getSize() != 0) { type = *it; ElementType type_facet = Mesh::getFacetType(type); ElementType type_cohesive = FEM::getCohesiveElementType(type_facet); mesh.addConnectivityType(type_cohesive, type_ghost); } } } AKANTU_DEBUG_ASSERT(type != _not_defined, "No elements in the mesh"); getFEM("CohesiveFEM").initShapeFunctions(_not_ghost); getFEM("CohesiveFEM").initShapeFunctions(_ghost); registerFEMObject("FacetsFEM", mesh_facets, spatial_dimension - 1); if (is_extrinsic) { getFEM("FacetsFEM").initShapeFunctions(_not_ghost); getFEM("FacetsFEM").initShapeFunctions(_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initAutomaticInsertion() { AKANTU_DEBUG_IN(); - MeshUtils::resetFacetToDouble(mesh_facets); - - /// initialize facet insertion array - mesh_facets.initByElementTypeArray(facet_insertion, 1, - spatial_dimension - 1, - false, - _ek_regular, - true); - - mesh_facets.initByElementTypeArray(cohesive_el_to_facet, 1, spatial_dimension - 1); - - for (ghost_type_t::iterator gt = ghost_type_t::begin(); - gt != ghost_type_t::end(); ++gt) { - - GhostType gt_facet = *gt; - - Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); - Mesh::type_iterator end = mesh_facets.lastType (spatial_dimension - 1, gt_facet); - - for(; it != end; ++it) { - ElementType type_facet = *it; - UInt nb_facet = mesh_facets.getNbElement(type_facet, gt_facet); - Array & cohesive_el_to_f = cohesive_el_to_facet(type_facet, gt_facet); - cohesive_el_to_f.resize(nb_facet); - - for (UInt f = 0; f < nb_facet; ++f) - cohesive_el_to_f(f) = std::numeric_limits::max(); - } - } - mesh_facets.initByElementTypeArray(facet_stress, 2 * spatial_dimension * spatial_dimension, spatial_dimension - 1); + resizeFacetStress(); + /// compute normals on facets computeNormals(); - + /// allocate stress_on_facet to store element stress on facets mesh.initByElementTypeArray(stress_on_facet, spatial_dimension * spatial_dimension, spatial_dimension); Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator last = mesh.lastType(spatial_dimension); - /// loop over element type for (; it != last; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type); UInt nb_facet_per_elem = Mesh::getNbFacetsPerElement(type); ElementType type_facet = Mesh::getFacetType(type); UInt nb_quad_per_facet = getFEM("FacetsFEM").getNbQuadraturePoints(type_facet); stress_on_facet(type).resize(nb_quad_per_facet * nb_facet_per_elem * nb_element); } if (stress_interpolation) initStressInterpolation(); } +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModelCohesive::updateAutomaticInsertion() { + AKANTU_DEBUG_IN(); + + inserter.limitCheckFacets(); + +#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) + if (facet_stress_synchronizer != NULL) { + DataAccessor * data_accessor = this; + facet_stress_synchronizer->updateFacetStressSynchronizer(inserter, + *rank_to_element, + *data_accessor); + } +#endif + + AKANTU_DEBUG_OUT(); +} + /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initStressInterpolation() { /// compute quadrature points coordinates on facets Array & position = mesh.getNodes(); ByElementTypeReal quad_facets("quad_facets", id); mesh_facets.initByElementTypeArray(quad_facets, spatial_dimension, spatial_dimension - 1); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType facet_gt = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, facet_gt); Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1, facet_gt); for (; it != last; ++it) { ElementType facet_type = *it; UInt nb_quad_per_facet = getFEM("FacetsFEM").getNbQuadraturePoints(facet_type); UInt nb_facet = mesh_facets.getNbElement(facet_type, facet_gt); UInt nb_tot_quad = nb_quad_per_facet * nb_facet; Array & quad_f = quad_facets(facet_type, facet_gt); quad_f.resize(nb_tot_quad); getFEM("FacetsFEM").interpolateOnQuadraturePoints(position, quad_f, spatial_dimension, facet_type, facet_gt); } } /// compute elements quadrature point positions and build /// element-facet quadrature points data structure ByElementTypeReal elements_quad_facets("elements_quad_facets", id); mesh.initByElementTypeArray(elements_quad_facets, spatial_dimension, spatial_dimension); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType elem_gt = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension, elem_gt); Mesh::type_iterator last = mesh.lastType(spatial_dimension, elem_gt); for (; it != last; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type, elem_gt); if (nb_element == 0) continue; /// compute elements' quadrature points and list of facet /// quadrature points positions by element Array & facet_to_element = mesh_facets.getSubelementToElement(type, elem_gt); UInt nb_facet_per_elem = facet_to_element.getNbComponent(); Array & el_q_facet = elements_quad_facets(type, elem_gt); ElementType facet_type = Mesh::getFacetType(type); UInt nb_quad_per_facet = getFEM("FacetsFEM").getNbQuadraturePoints(facet_type); el_q_facet.resize(nb_element * nb_facet_per_elem * nb_quad_per_facet); for (UInt el = 0; el < nb_element; ++el) { for (UInt f = 0; f < nb_facet_per_elem; ++f) { Element global_facet_elem = facet_to_element(el, f); UInt global_facet = global_facet_elem.element; GhostType facet_gt = global_facet_elem.ghost_type; const Array & quad_f = quad_facets(facet_type, facet_gt); for (UInt q = 0; q < nb_quad_per_facet; ++q) { for (UInt s = 0; s < spatial_dimension; ++s) { el_q_facet(el * nb_facet_per_elem * nb_quad_per_facet + f * nb_quad_per_facet + q, s) = quad_f(global_facet * nb_quad_per_facet + q, s); } } } } } } /// loop over non cohesive materials for (UInt m = 0; m < materials.size(); ++m) { try { MaterialCohesive & mat __attribute__((unused)) = dynamic_cast(*materials[m]); } catch(std::bad_cast&) { /// initialize the interpolation function materials[m]->initElementalFieldInterpolation(elements_quad_facets); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::updateResidual(bool need_initialize) { AKANTU_DEBUG_IN(); if (need_initialize) initializeUpdateResidualData(); // f -= fint std::vector::iterator mat_it; for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { try { MaterialCohesive & mat = dynamic_cast(**mat_it); mat.computeTraction(_not_ghost); } catch (std::bad_cast & bce) { } } SolidMechanicsModel::updateResidual(false); for(mat_it = materials.begin(); mat_it != materials.end(); ++mat_it) { try { MaterialCohesive & mat = dynamic_cast(**mat_it); mat.computeEnergies(); } catch (std::bad_cast & bce) { } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::computeNormals() { AKANTU_DEBUG_IN(); getFEM("FacetsFEM").computeNormalsOnControlPoints(_not_ghost); /** * @todo store tangents while computing normals instead of * recomputing them as follows: */ /* ------------------------------------------------------------------------ */ UInt tangent_components = spatial_dimension * (spatial_dimension - 1); mesh_facets.initByElementTypeArray(tangents, tangent_components, spatial_dimension - 1); 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 facet_type = *it; const Array & normals = getFEM("FacetsFEM").getNormalsOnQuadPoints(facet_type); UInt nb_quad = normals.getSize(); Array & tang = tangents(facet_type); tang.resize(nb_quad); Real * normal_it = normals.storage(); Real * tangent_it = tang.storage(); /// compute first tangent for (UInt q = 0; q < nb_quad; ++q) { /// if normal is orthogonal to xy plane, arbitrarly define tangent if ( Math::are_float_equal(Math::norm2(normal_it), 0) ) tangent_it[0] = 1; else Math::normal2(normal_it, tangent_it); normal_it += spatial_dimension; tangent_it += tangent_components; } /// compute second tangent (3D case) if (spatial_dimension == 3) { normal_it = normals.storage(); tangent_it = tang.storage(); for (UInt q = 0; q < nb_quad; ++q) { Math::normal3(normal_it, tangent_it, tangent_it + spatial_dimension); normal_it += spatial_dimension; tangent_it += tangent_components; } } } AKANTU_DEBUG_OUT(); } -/* -------------------------------------------------------------------------- */ -// void SolidMechanicsModelCohesive::initFacetFilter() { -// AKANTU_DEBUG_IN(); - -// for (ghost_type_t::iterator gt = ghost_type_t::begin(); -// gt != ghost_type_t::end(); -// ++gt) { -// GhostType gt_facet = *gt; - -// Mesh::type_iterator first = mesh_facets.firstType(spatial_dimension - 1, gt_facet); -// Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1, gt_facet); -// for(;first != last; ++first) { -// ElementType type_facet = *first; -// Array & f_material = facet_material(type_facet, gt_facet); -// UInt nb_facet = f_material.getSize(); - -// for (UInt f = 0; f < nb_facet; ++f) { -// try { -// MaterialCohesive & mat = -// dynamic_cast(*materials[f_material(f)]); - -// Array & facet_filter = mat.getFacetFilter(type_facet, gt_facet); -// facet_filter.push_back(f); - -// } catch(std::bad_cast&) { } -// } -// } -// } - -// AKANTU_DEBUG_OUT(); -// } - /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::averageStressOnFacets(UInt material_index) { AKANTU_DEBUG_IN(); Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator last = mesh.lastType(spatial_dimension); /// loop over element type for (; it != last; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type); UInt nb_quad_per_element = getFEM().getNbQuadraturePoints(type); const Array & stress = materials[material_index]->getStress(type); Array & s_on_facet = stress_on_facet(type); UInt nb_facet_per_elem = Mesh::getNbFacetsPerElement(type); ElementType type_facet = Mesh::getFacetType(type); UInt nb_quad_per_facet = getFEM("FacetsFEM").getNbQuadraturePoints(type_facet); UInt nb_facet_quad_per_elem = nb_quad_per_facet * nb_facet_per_elem; Array::const_iterator > stress_it = stress.begin(spatial_dimension, spatial_dimension); Array::iterator > s_on_facet_it = s_on_facet.begin(spatial_dimension, spatial_dimension); Matrix average_stress(spatial_dimension, spatial_dimension); for (UInt el = 0; el < nb_element; ++el) { /// compute average stress average_stress.clear(); for (UInt q = 0; q < nb_quad_per_element; ++q, ++stress_it) average_stress += *stress_it; average_stress /= nb_quad_per_element; /// store average stress for (UInt q = 0; q < nb_facet_quad_per_elem; ++q, ++s_on_facet_it) *s_on_facet_it = average_stress; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::fillStressOnFacet() { AKANTU_DEBUG_IN(); - resizeFacetArray(facet_stress); - UInt sp2 = spatial_dimension * spatial_dimension; UInt sp4 = sp2 * 2; /// loop over materials for (UInt m = 0; m < materials.size(); ++m) { try { MaterialCohesive & mat __attribute__((unused)) = dynamic_cast(*materials[m]); } catch(std::bad_cast&) { if (stress_interpolation) /// interpolate stress on facet quadrature points positions materials[m]->interpolateStress(stress_on_facet); else averageStressOnFacets(m); GhostType ghost_type = _not_ghost; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last = mesh.lastType(spatial_dimension, ghost_type); /// loop over element type for (; it != last; ++it) { ElementType type = *it; UInt nb_element = mesh.getNbElement(type, ghost_type); if (nb_element == 0) continue; Array & stress_on_f = stress_on_facet(type, ghost_type); /// store the interpolated stresses on the facet_stress vector Array & facet_to_element = mesh_facets.getSubelementToElement(type, ghost_type); UInt nb_facet_per_elem = facet_to_element.getNbComponent(); Array::iterator > facet_to_el_it = facet_to_element.begin(nb_facet_per_elem); Array::iterator< Matrix > stress_on_f_it = stress_on_f.begin(spatial_dimension, spatial_dimension); ElementType facet_type = _not_defined; GhostType facet_gt = _casper; Array > * element_to_facet = NULL; Array * f_stress = NULL; Array * f_check = NULL; UInt nb_quad_per_facet = 0; UInt element_rank = 0; Element current_el(type, 0, ghost_type); for (UInt el = 0; el < nb_element; ++el, ++facet_to_el_it) { current_el.element = el; for (UInt f = 0; f < nb_facet_per_elem; ++f) { Element global_facet_elem = (*facet_to_el_it)(f); UInt global_facet = global_facet_elem.element; if (facet_type != global_facet_elem.type || facet_gt != global_facet_elem.ghost_type) { facet_type = global_facet_elem.type; facet_gt = global_facet_elem.ghost_type; element_to_facet = &( mesh_facets.getElementToSubelement(facet_type, facet_gt) ); f_stress = &( facet_stress(facet_type, facet_gt) ); nb_quad_per_facet = getFEM("FacetsFEM").getNbQuadraturePoints(facet_type, facet_gt); - f_check = &( facets_check(facet_type, facet_gt) ); + f_check = &( inserter.getCheckFacets(facet_type, facet_gt) ); } if (!(*f_check)(global_facet)) { stress_on_f_it += nb_quad_per_facet; continue; } for (UInt q = 0; q < nb_quad_per_facet; ++q, ++stress_on_f_it) { element_rank = (*element_to_facet)(global_facet)[0] != current_el; Matrix facet_stress_local(f_stress->storage() + (global_facet * nb_quad_per_facet + q) * sp4 + element_rank * sp2, spatial_dimension, spatial_dimension); facet_stress_local = *stress_on_f_it; } } } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::checkCohesiveStress() { AKANTU_DEBUG_IN(); fillStressOnFacet(); #if defined(AKANTU_DEBUG_TOOLS) debug::element_manager.printData(debug::_dm_model_cohesive, "Interpolated stresses before", facet_stress); #endif synch_registry->synchronize(_gst_smmc_facets_stress); #if defined(AKANTU_DEBUG_TOOLS) debug::element_manager.printData(debug::_dm_model_cohesive, "Interpolated stresses", facet_stress); #endif for (UInt m = 0; m < materials.size(); ++m) { try { MaterialCohesive & mat_cohesive = dynamic_cast(*materials[m]); /// check which not ghost cohesive elements are to be created - mat_cohesive.checkInsertion(facet_stress, facet_insertion); + mat_cohesive.checkInsertion(); } catch(std::bad_cast&) { } } /// communicate data among processors synch_registry->synchronize(_gst_smmc_facets); /// insert cohesive elements - MeshUtils::insertCohesiveElements(mesh, - mesh_facets, - facet_insertion, - true); + inserter.insertExtrinsicElements(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onElementsAdded(const Array & element_list, const NewElementsEvent & event) { AKANTU_DEBUG_IN(); - /// update model data for new cohesive elements - for (ghost_type_t::iterator gt = ghost_type_t::begin(); - gt != ghost_type_t::end(); ++gt) { - - GhostType gt_facet = *gt; - - Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); - Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); - for(; it != end; ++it) { - ElementType type_facet = *it; - - /// define facet material vector - ElementType type_cohesive = FEM::getCohesiveElementType(type_facet); - - Array & el_id_by_mat = element_index_by_material(type_cohesive, - gt_facet); - - UInt old_nb_cohesive_elements = el_id_by_mat.getSize(); - UInt total_nb_cohesive_elements = mesh.getNbElement(type_cohesive, gt_facet); - UInt new_cohesive_elements - = total_nb_cohesive_elements - old_nb_cohesive_elements; - - if (new_cohesive_elements == 0) continue; - - const Array & facet_to_coh_element - = mesh.getSubelementToElement(type_cohesive, gt_facet); - - //el_id_by_mat.resize(total_nb_cohesive_elements); - - Array & f_check = facets_check(type_facet, gt_facet); - - if (f_check.getSize() > 0) - f_check.resize(f_check.getSize() + new_cohesive_elements); - -#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) - Array & cohesive_el_to_f = cohesive_el_to_facet(type_facet, gt_facet); -#endif - - //const Array & facet_material_by_type = facet_material(type_facet, gt_facet); - - bool third_dimension = spatial_dimension == 3; - - for (UInt cel = old_nb_cohesive_elements; - cel < total_nb_cohesive_elements; - ++cel) { - UInt old_facet = facet_to_coh_element(cel, third_dimension).element; - UInt new_facet = facet_to_coh_element(cel, !third_dimension).element; - - /// assign the cohesive material to each new cohesive element - //UInt material_id = facet_material_by_type(old_facet); - - // el_id_by_mat(cel, 1) = - // materials[material_id]->addElement(type_cohesive, - // cel, - // gt_facet); - - // el_id_by_mat(cel, 0) = material_id; - - /// update facets_check vector - if (f_check.getSize() > 0) { - f_check(old_facet) = false; - f_check(new_facet) = false; - } - -#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) - if (facet_synchronizer != NULL) - cohesive_el_to_f(old_facet) = cel; -#endif - } - } - - /// update shape functions - } - SolidMechanicsModel::onElementsAdded(element_list, event); + /// update shape functions getFEM("CohesiveFEM").initShapeFunctions(_not_ghost); getFEM("CohesiveFEM").initShapeFunctions(_ghost); if(is_extrinsic) { getFEM("FacetsFEM").initShapeFunctions(_not_ghost); getFEM("FacetsFEM").initShapeFunctions(_ghost); } #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) - updateFacetSynchronizer(); - if (facet_stress_synchronizer != NULL) { - DataAccessor * data_accessor = this; - facet_stress_synchronizer->updateFacetStressSynchronizer(facets_check, - *rank_to_element, - *data_accessor); - } + updateFacetSynchronizers(); #endif + resizeFacetStress(); + AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onNodesAdded(const Array & doubled_nodes, __attribute__((unused)) const NewNodesEvent & event) { AKANTU_DEBUG_IN(); UInt nb_new_nodes = doubled_nodes.getSize(); Array nodes_list(nb_new_nodes); for (UInt n = 0; n < nb_new_nodes; ++n) nodes_list(n) = doubled_nodes(n, 1); SolidMechanicsModel::onNodesAdded(nodes_list, event); for (UInt n = 0; n < nb_new_nodes; ++n) { UInt old_node = doubled_nodes(n, 0); UInt new_node = doubled_nodes(n, 1); for (UInt dim = 0; dim < spatial_dimension; ++dim) { (*displacement)(new_node, dim) = (*displacement)(old_node, dim); (*velocity) (new_node, dim) = (*velocity) (old_node, dim); (*acceleration)(new_node, dim) = (*acceleration)(old_node, dim); (*boundary) (new_node, dim) = (*boundary) (old_node, dim); if (current_position) (*current_position)(new_node, dim) = (*current_position)(old_node, dim); if (increment_acceleration) (*increment_acceleration)(new_node, dim) = (*increment_acceleration)(old_node, dim); if (increment) (*increment)(new_node, dim) = (*increment)(old_node, dim); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::buildFragmentsList() { AKANTU_DEBUG_IN(); UInt cohesive_index = 0; while ((dynamic_cast(materials[cohesive_index]) == NULL) && cohesive_index <= materials.size()) ++cohesive_index; /// find element type for _not_ghost facet Mesh::type_iterator it_f = mesh_facets.firstType(spatial_dimension - 1); Mesh::type_iterator last_f = mesh_facets.lastType(spatial_dimension - 1); ElementType internal_facet_type = _not_defined; for (; it_f != last_f; ++it_f) { UInt nb_facet = mesh_facets.getNbElement(*it_f); if (nb_facet != 0) { internal_facet_type = *it_f; break; } } AKANTU_DEBUG_ASSERT(internal_facet_type != _not_defined, "No facets in the mesh"); Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator last = mesh.lastType(spatial_dimension); UInt max = std::numeric_limits::max(); for (; it != last; ++it) { UInt nb_element = mesh.getNbElement(*it); if (nb_element != 0) { /// initialize the list of checked elements and the list of /// elements to be checked fragment_to_element.alloc(nb_element, 1, *it); fragment_to_element(*it).set(max); } } Array< std::vector > & element_to_facet = mesh_facets.getElementToSubelement(internal_facet_type); ElementType type_cohesive = FEM::getCohesiveElementType(internal_facet_type); if (mesh.getNbElement(type_cohesive) == 0) return; const Array & f_to_cohesive_el = mesh.getSubelementToElement(type_cohesive); nb_fragment = 0; it = mesh.firstType(spatial_dimension); MaterialCohesive * mat_cohesive = dynamic_cast(materials[cohesive_index]); const Array & damage = mat_cohesive->getDamage(type_cohesive); UInt nb_quad_cohesive = getFEM("CohesiveFEM").getNbQuadraturePoints(type_cohesive); for (; it != last; ++it) { Array & checked_el = fragment_to_element(*it); UInt nb_element = checked_el.getSize(); if (nb_element != 0) { Array & facet_to_element = mesh_facets.getSubelementToElement(*it); UInt nb_facet_per_elem = facet_to_element.getNbComponent(); /// loop on elements for (UInt el = 0; el < nb_element; ++el) { if (checked_el(el) == max) { /// build fragment ++nb_fragment; checked_el(el) = nb_fragment - 1; Array elem_to_check; Element first_el(*it, el); elem_to_check.push_back(first_el); /// keep looping while there are elements to check while (elem_to_check.getSize() != 0) { UInt nb_elem_check = elem_to_check.getSize(); for (UInt el_check = 0; el_check < nb_elem_check; ++el_check) { Element current_el = elem_to_check(el_check); for (UInt f = 0; f < nb_facet_per_elem; ++f) { /// find adjacent element on current facet UInt global_facet = facet_to_element(current_el.element, f).element; Element next_el; for (UInt i = 0; i < 2; ++i) { next_el = element_to_facet(global_facet)[i]; if (next_el != current_el) break; } if (next_el.kind == _ek_cohesive) { /// fragmention occurs when the cohesive element has /// reached damage = 1 on every quadrature point UInt q = 0; while (q < nb_quad_cohesive && Math::are_float_equal(damage(next_el.element * nb_quad_cohesive + q), 1)) ++q; if (q == nb_quad_cohesive) next_el = ElementNull; else { /// check which facet is the correct one UInt other_facet_index = f_to_cohesive_el(next_el.element, 0).element == global_facet; UInt other_facet = f_to_cohesive_el(next_el.element, other_facet_index).element; /// get the other regualar element next_el = element_to_facet(other_facet)[0]; } } /// if it exists, add it to the fragment list if (next_el != ElementNull) { Array & checked_next_el = fragment_to_element(next_el.type); /// check if the element isn't already part of a fragment if (checked_next_el(next_el.element) == max) { checked_next_el(next_el.element) = nb_fragment - 1; elem_to_check.push_back(next_el); } } } } /// erase elements that have already been checked for (UInt el_check = nb_elem_check; el_check > 0; --el_check) elem_to_check.erase(el_check - 1); } } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::computeFragmentsMV() { AKANTU_DEBUG_IN(); fragment_mass.resize(nb_fragment); fragment_mass.clear(); fragment_velocity.resize(nb_fragment); fragment_velocity.clear(); fragment_center.resize(nb_fragment); fragment_center.clear(); UInt nb_nodes = mesh.getNbNodes(); Array checked_node(nb_nodes); checked_node.clear(); const Array & position = mesh.getNodes(); Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator last = mesh.lastType(spatial_dimension); for (; it != last; ++it) { UInt nb_element = mesh.getNbElement(*it); if (nb_element != 0) { const Array & frag_to_el = fragment_to_element(*it); const Array & connectivity = mesh.getConnectivity(*it); UInt nb_nodes_per_elem = connectivity.getNbComponent(); /// loop over each node of every element for (UInt el = 0; el < nb_element; ++el) { for (UInt n = 0; n < nb_nodes_per_elem; ++n) { UInt node = connectivity(el, n); /// if the node hasn't been checked, store its data if (!checked_node(node)) { fragment_mass(frag_to_el(el)) += (*mass)(node); for (UInt s = 0; s < spatial_dimension; ++s) { fragment_velocity(frag_to_el(el), s) += (*mass)(node) * (*velocity)(node, s); fragment_center(frag_to_el(el), s) += (*mass)(node) * position(node, s); } checked_node(node) = true; } } } } } for (UInt frag = 0; frag < nb_fragment; ++frag) { for (UInt s = 0; s < spatial_dimension; ++s) { fragment_velocity(frag, s) /= fragment_mass(frag); fragment_center(frag, s) /= fragment_mass(frag); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::computeFragmentsData() { AKANTU_DEBUG_IN(); buildFragmentsList(); computeFragmentsMV(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); stream << space << "SolidMechanicsModelCohesive [" << std::endl; SolidMechanicsModel::printself(stream, indent + 1); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ -void SolidMechanicsModelCohesive::initFacetsCheck() { - AKANTU_DEBUG_IN(); - - resizeFacetArray(facets_check, false); - - for (ghost_type_t::iterator gt = ghost_type_t::begin(); - gt != ghost_type_t::end(); ++gt) { - - GhostType facet_gt = *gt; - Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, facet_gt); - Mesh::type_iterator last = mesh_facets.lastType(spatial_dimension - 1, facet_gt); - - for (; it != last; ++it) { - ElementType facet_type = *it; - - Array & f_check = facets_check(facet_type, facet_gt); - - const Array< std::vector > & element_to_facet - = mesh_facets.getElementToSubelement(facet_type, facet_gt); - - for (UInt f = 0; f < f_check.getSize(); ++f) { - if (element_to_facet(f)[1] == ElementNull || - (element_to_facet(f)[0].ghost_type == _ghost && - element_to_facet(f)[1].ghost_type == _ghost)) { - f_check(f) = false; - } - else f_check(f) = true; - } - } - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ -void SolidMechanicsModelCohesive::enableFacetsCheckOnArea(const Array & limits) { +void SolidMechanicsModelCohesive::resizeFacetStress() { AKANTU_DEBUG_IN(); - AKANTU_DEBUG_ASSERT(limits.getNbComponent() == 2, - "Number of components for limits array must be 2"); - - AKANTU_DEBUG_ASSERT(limits.getSize() == spatial_dimension, - "Limits array size must be equal to spatial dimension"); - - Real * bary_facet = new Real[spatial_dimension]; - - for (ghost_type_t::iterator gt = ghost_type_t::begin(); - gt != ghost_type_t::end(); - ++gt) { - GhostType ghost_type = *gt; - - Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, ghost_type); - Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, ghost_type); - for(; it != end; ++it) { - ElementType type = *it; - Array & f_check = facets_check(type, ghost_type); - UInt nb_facet = mesh_facets.getNbElement(type, ghost_type); - - for (UInt f = 0; f < nb_facet; ++f) { - if (f_check(f)) { - - mesh_facets.getBarycenter(f, type, bary_facet, ghost_type); - - UInt coord_in_limit = 0; - - while (coord_in_limit < spatial_dimension && - bary_facet[coord_in_limit] > limits(coord_in_limit, 0) && - bary_facet[coord_in_limit] < limits(coord_in_limit, 1)) - ++coord_in_limit; - - if (coord_in_limit != spatial_dimension) - f_check(f) = false; - - } - } - } - } - - delete [] bary_facet; - -#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) - if (facet_stress_synchronizer != NULL) { - DataAccessor * data_accessor = this; - facet_stress_synchronizer->updateFacetStressSynchronizer(facets_check, - *rank_to_element, - *data_accessor); - } -#endif - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ - -template -void SolidMechanicsModelCohesive::resizeFacetArray(ByElementTypeArray & by_el_type_array, - bool per_quadrature_point_data) const { - AKANTU_DEBUG_IN(); - - UInt nb_quadrature_points = 0; - for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, ghost_type); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, ghost_type); for(; it != end; ++it) { ElementType type = *it; UInt nb_facet = mesh_facets.getNbElement(type, ghost_type); - if (per_quadrature_point_data) - nb_quadrature_points = - getFEM("FacetsFEM").getNbQuadraturePoints(type, ghost_type); - else nb_quadrature_points = 1; + UInt nb_quadrature_points = + getFEM("FacetsFEM").getNbQuadraturePoints(type, ghost_type); UInt new_size = nb_facet * nb_quadrature_points; - Array & vect = by_el_type_array(type, ghost_type); - vect.resize(new_size); + facet_stress(type, ghost_type).resize(new_size); } } AKANTU_DEBUG_OUT(); } __END_AKANTU__ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive.hh index 27670e3c5..1eb791263 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive.hh @@ -1,315 +1,311 @@ /** * @file solid_mechanics_model_cohesive.hh * * @author Marco Vocialta * * @date Tue May 08 13:01:18 2012 * * @brief Solid mechanics model for cohesive elements * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model.hh" +#include "cohesive_element_inserter.hh" #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) # include "facet_synchronizer.hh" # include "facet_stress_synchronizer.hh" #endif /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_HH__ #define __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_HH__ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ struct SolidMechanicsModelCohesiveOptions : public SolidMechanicsModelOptions { SolidMechanicsModelCohesiveOptions(AnalysisMethod analysis_method = _explicit_lumped_mass, bool extrinsic = false, bool no_init_materials = false, bool init_facet_filter = true, bool stress_interpolation = true) : SolidMechanicsModelOptions(analysis_method, no_init_materials), extrinsic(extrinsic), init_facet_filter(init_facet_filter), stress_interpolation(stress_interpolation) {} bool extrinsic; bool init_facet_filter; bool stress_interpolation; }; extern const SolidMechanicsModelCohesiveOptions default_solid_mechanics_model_cohesive_options; /* -------------------------------------------------------------------------- */ /* Solid Mechanics Model for Cohesive elements */ /* -------------------------------------------------------------------------- */ class SolidMechanicsModelCohesive : public SolidMechanicsModel { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: class NewCohesiveNodesEvent : public NewNodesEvent { public: AKANTU_GET_MACRO_NOT_CONST(OldNodesList, old_nodes, Array &); AKANTU_GET_MACRO(OldNodesList, old_nodes, const Array &); protected: Array old_nodes; }; typedef FEMTemplate MyFEMCohesiveType; SolidMechanicsModelCohesive(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "solid_mechanics_model_cohesive", const MemoryID & memory_id = 0); virtual ~SolidMechanicsModelCohesive(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// assemble the residual for the explicit scheme virtual void updateResidual(bool need_initialize = true); /// function to print the contain of the class virtual void printself(std::ostream & stream, int indent = 0) const; /// function to perform a stress check on each facet and insert /// cohesive elements if needed void checkCohesiveStress(); /// initialize the cohesive model void initFull(std::string material_file, const ModelOptions & options = default_solid_mechanics_model_cohesive_options); /// initialize the model void initModel(); /// initialize cohesive material void initMaterials(); /// build fragments and compute their data (mass, velocity..) void computeFragmentsData(); /// init facet filters for cohesive materials void initFacetFilter(); /// limit the cohesive element insertion to a given area void enableFacetsCheckOnArea(const Array & limits); + /// update automatic insertion after a change in the element inserter + void updateAutomaticInsertion(); + private: /// initialize completely the model for extrinsic elements void initAutomaticInsertion(); /// initialize stress interpolation void initStressInterpolation(); /// build fragments list void buildFragmentsList(); /// compute fragments' mass and velocity void computeFragmentsMV(); /// compute facets' normals void computeNormals(); - /// resize facet array - template - void resizeFacetArray(ByElementTypeArray & by_el_type_array, - bool per_quadrature_point_data = true) const; + /// resize facet stress + void resizeFacetStress(); /// init facets_check array void initFacetsCheck(); /// fill stress_on_facet void fillStressOnFacet(); /// compute average stress on elements void averageStressOnFacets(UInt material_index); /* ------------------------------------------------------------------------ */ /* Mesh Event Handler inherited members */ /* ------------------------------------------------------------------------ */ protected: virtual void onNodesAdded (const Array & nodes_list, const NewNodesEvent & event); virtual void onElementsAdded (const Array & nodes_list, const NewElementsEvent & event); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get facet mesh AKANTU_GET_MACRO(MeshFacets, mesh_facets, const Mesh &); - /// get facets check vector - AKANTU_GET_MACRO_BY_ELEMENT_TYPE(FacetsCheck, facets_check, bool); - /// get stress on facets vector AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(StressOnFacets, facet_stress, Real); /// get number of fragments AKANTU_GET_MACRO(NbFragment, nb_fragment, UInt); /// get fragment_to_element vectors AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(FragmentToElement, fragment_to_element, UInt); /// get mass for each fragment AKANTU_GET_MACRO(FragmentsMass, fragment_mass, const Array &); /// get average velocity for each fragment AKANTU_GET_MACRO(FragmentsVelocity, fragment_velocity, const Array &); /// get center of mass coordinates for each fragment AKANTU_GET_MACRO(FragmentsCenter, fragment_center, const Array &); /// get facet material AKANTU_GET_MACRO_BY_ELEMENT_TYPE(FacetMaterial, facet_material, UInt); /// get facet material AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(FacetMaterial, facet_material, UInt); /// get facet material AKANTU_GET_MACRO(FacetMaterial, facet_material, const ByElementTypeArray &); /// THIS HAS TO BE CHANGED AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Tangents, tangents, Real); + /// get element inserter + AKANTU_GET_MACRO_NOT_CONST(ElementInserter, inserter, CohesiveElementInserter &); + /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// mesh containing facets and their data structures Mesh & mesh_facets; - /// vector containing facets in which cohesive elements can be automatically inserted - ByElementTypeArray facets_check; - /// @todo store tangents when normals are computed: ByElementTypeReal tangents; /// list of stresses on facet quadrature points for every element ByElementTypeReal stress_on_facet; /// stress on facets on the two sides by quadrature point ByElementTypeReal facet_stress; /// fragment number for each element ByElementTypeUInt fragment_to_element; /// number of fragments UInt nb_fragment; /// mass for each fragment Array fragment_mass; /// average velocity for each fragment Array fragment_velocity; /// center of mass coordinates for each element Array fragment_center; - /// facet in which cohesive elements are inserted - ByElementTypeArray facet_insertion; - - /// cohesive elements connected to each facet - ByElementTypeUInt cohesive_el_to_facet; - /// flag to know if facets have been generated bool facet_generated; /// material to use if a cohesive element is created on a facet ByElementTypeUInt facet_material; /// stress interpolation flag bool stress_interpolation; bool is_extrinsic; + /// cohesive element inserter + CohesiveElementInserter inserter; + #if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) #include "solid_mechanics_model_cohesive_parallel.hh" #endif }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #if defined (AKANTU_PARALLEL_COHESIVE_ELEMENT) # include "solid_mechanics_model_cohesive_inline_impl.cc" #endif /* -------------------------------------------------------------------------- */ class DefaultMaterialCohesiveSelector : public DefaultMaterialSelector { public: DefaultMaterialCohesiveSelector(const SolidMechanicsModelCohesive & model) : DefaultMaterialSelector(model.getElementIndexByMaterial()), facet_material(model.getFacetMaterial()), mesh(model.getMesh()), mesh_facets(model.getMeshFacets()) { } inline virtual UInt operator()(const Element & element) { if(Mesh::getKind(element.type) == _ek_cohesive) { try { const Array & cohesive_el_to_facet = mesh.getSubelementToElement(element.type, element.ghost_type); bool third_dimension = (mesh.getSpatialDimension() == 3); const Element & facet = cohesive_el_to_facet(element.element, third_dimension); return facet_material(facet.type, facet.ghost_type)(facet.element); } catch(...) { return MaterialSelector::operator()(element); } } else if (Mesh::getSpatialDimension(element.type) == mesh.getSpatialDimension() - 1) { return facet_material(element.type, element.ghost_type)(element.element); } else { return DefaultMaterialSelector::operator()(element); } } private: const ByElementTypeUInt & facet_material; const Mesh & mesh; const Mesh & mesh_facets; }; /// standard output stream operator inline std::ostream & operator <<(std::ostream & stream, const SolidMechanicsModelCohesive & _this) { _this.printself(stream); return stream; } __END_AKANTU__ #endif /* __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive_inline_impl.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive_inline_impl.cc index 42ca23a14..7504e2997 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive_inline_impl.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive_inline_impl.cc @@ -1,372 +1,343 @@ /** * @file solid_mechanics_model_cohesive_inline_impl.cc * @author Marco Vocialta * @date Fri Jan 18 09:40:01 2013 * * @brief Solid mechanics model inline implementation * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModelCohesive::getNbQuadsForFacetCheck(const Array & elements) const { UInt nb_quads = 0; UInt nb_quad_per_facet = 0; ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; Array::const_iterator it = elements.begin(); Array::const_iterator end = elements.end(); for (; it != end; ++it) { const Element & el = *it; if(el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; nb_quad_per_facet = this->getFEM("FacetsFEM").getNbQuadraturePoints(el.type, el.ghost_type); } nb_quads += nb_quad_per_facet; } return nb_quads; } /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModelCohesive::getNbNodesPerElementList(const Array & elements) const { UInt nb_nodes_per_element = 0; UInt nb_nodes = 0; ElementType current_element_type = _not_defined; Array::const_iterator el_it = elements.begin(); Array::const_iterator el_end = elements.end(); for (; el_it != el_end; ++el_it) { const Element & el = *el_it; if(el.type != current_element_type) { current_element_type = el.type; nb_nodes_per_element = Mesh::getNbNodesPerElement(current_element_type); } nb_nodes += nb_nodes_per_element; } return nb_nodes; } /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModelCohesive::getNbDataForElements(const Array & elements, SynchronizationTag tag) const { AKANTU_DEBUG_IN(); UInt size = 0; if (elements.getSize() == 0) return size; /// regular element case if (elements(0).kind == _ek_regular) { -#ifndef AKANTU_NDEBUG - if (tag == _gst_smmc_facets || - tag == _gst_smmc_facets_conn || - tag == _gst_smmc_facets_stress) - size += elements.getSize() * spatial_dimension * sizeof(Real); -#endif switch(tag) { case _gst_smmc_facets: { size += elements.getSize() * sizeof(bool); break; } case _gst_smmc_facets_conn: { UInt nb_nodes = getNbNodesPerElementList(elements); size += nb_nodes * sizeof(UInt); break; } case _gst_smmc_facets_stress: { UInt nb_quads = getNbQuadsForFacetCheck(elements); size += nb_quads * spatial_dimension * spatial_dimension * sizeof(Real); break; } default: { size += SolidMechanicsModel::getNbDataForElements(elements, tag); } } } /// cohesive element case else if (elements(0).kind == _ek_cohesive) { -#ifndef AKANTU_NDEBUG - size += elements.getSize() * spatial_dimension * sizeof(Real); /// position of the barycenter of the element (only for check) -#endif UInt nb_nodes_per_element = 0; Array::const_iterator it = elements.begin(); Array::const_iterator end = elements.end(); for (; it != end; ++it) { const Element & el = *it; nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type); } switch(tag) { case _gst_material_id: { size += elements.getSize() * 2 * sizeof(UInt); break; } case _gst_smm_boundary: { // force, displacement, boundary size += nb_nodes_per_element * spatial_dimension * (2 * sizeof(Real) + sizeof(bool)); break; } default: { } } if(tag != _gst_material_id && tag != _gst_smmc_facets) { Array * elements_per_mat = new Array[materials.size()]; this->splitElementByMaterial(elements, elements_per_mat); for (UInt i = 0; i < materials.size(); ++i) { size += materials[i]->getNbDataForElements(elements_per_mat[i], tag); } delete [] elements_per_mat; } } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModelCohesive::packElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) const { AKANTU_DEBUG_IN(); if (elements.getSize() == 0) return; if (elements(0).kind == _ek_regular) { -#ifndef AKANTU_NDEBUG - if (tag == _gst_smmc_facets || - tag == _gst_smmc_facets_conn || - tag == _gst_smmc_facets_stress) - packBarycenter(mesh_facets, buffer, elements, tag); -#endif - switch(tag) { case _gst_smmc_facets: { - packElementalDataHelper(facet_insertion, buffer, elements, - false, getFEM()); + packElementalDataHelper(inserter.getInsertionFacetsByElement(), + buffer, elements, false, getFEM()); break; } case _gst_smmc_facets_conn: { packElementalDataHelper(*global_connectivity, buffer, elements, false, getFEM()); break; } case _gst_smmc_facets_stress: { packFacetStressDataHelper(facet_stress, buffer, elements); break; } default: { SolidMechanicsModel::packElementData(buffer, elements, tag); } } } else if (elements(0).kind == _ek_cohesive) { -#ifndef AKANTU_NDEBUG - packBarycenter(mesh, buffer, elements, tag); -#endif switch(tag) { case _gst_material_id: { packElementalDataHelper(element_index_by_material, buffer, elements, false, getFEM("CohesiveFEM")); break; } case _gst_smm_boundary: { packNodalDataHelper(*force, buffer, elements, mesh); packNodalDataHelper(*velocity, buffer, elements, mesh); packNodalDataHelper(*boundary, buffer, elements, mesh); break; } default: { } } if(tag != _gst_material_id && tag != _gst_smmc_facets) { Array * elements_per_mat = new Array[materials.size()]; splitElementByMaterial(elements, elements_per_mat); for (UInt i = 0; i < materials.size(); ++i) { materials[i]->packElementData(buffer, elements_per_mat[i], tag); } delete [] elements_per_mat; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModelCohesive::unpackElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) { AKANTU_DEBUG_IN(); if (elements.getSize() == 0) return; if (elements(0).kind == _ek_regular) { -#ifndef AKANTU_NDEBUG - if (tag == _gst_smmc_facets || - tag == _gst_smmc_facets_conn || - tag == _gst_smmc_facets_stress) - unpackBarycenter(mesh_facets, buffer, elements, tag); -#endif - switch(tag) { case _gst_smmc_facets: { - unpackElementalDataHelper(facet_insertion, buffer, elements, - false, getFEM()); + unpackElementalDataHelper(inserter.getInsertionFacetsByElement(), + buffer, elements, false, getFEM()); break; } case _gst_smmc_facets_conn: { unpackElementalDataHelper(*global_connectivity, buffer, elements, false, getFEM()); break; } case _gst_smmc_facets_stress: { unpackFacetStressDataHelper(facet_stress, buffer, elements); break; } default: { SolidMechanicsModel::unpackElementData(buffer, elements, tag); } } } else if (elements(0).kind == _ek_cohesive) { -#ifndef AKANTU_NDEBUG - unpackBarycenter(mesh, buffer, elements, tag); -#endif switch(tag) { case _gst_material_id: { unpackElementalDataHelper(element_index_by_material, buffer, elements, false, getFEM("CohesiveFEM")); break; } case _gst_smm_boundary: { unpackNodalDataHelper(*force, buffer, elements, mesh); unpackNodalDataHelper(*velocity, buffer, elements, mesh); unpackNodalDataHelper(*boundary, buffer, elements, mesh); break; } default: { } } if(tag != _gst_material_id && tag != _gst_smmc_facets) { Array * elements_per_mat = new Array[materials.size()]; splitElementByMaterial(elements, elements_per_mat); for (UInt i = 0; i < materials.size(); ++i) { materials[i]->unpackElementData(buffer, elements_per_mat[i], tag); } delete [] elements_per_mat; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template inline void SolidMechanicsModelCohesive::packFacetStressDataHelper(const ByElementTypeArray & data_to_pack, CommunicationBuffer & buffer, const Array & elements) const { packUnpackFacetStressDataHelper(const_cast &>(data_to_pack), buffer, elements); } /* -------------------------------------------------------------------------- */ template inline void SolidMechanicsModelCohesive::unpackFacetStressDataHelper(ByElementTypeArray & data_to_unpack, CommunicationBuffer & buffer, const Array & elements) const { packUnpackFacetStressDataHelper(data_to_unpack, buffer, elements); } /* -------------------------------------------------------------------------- */ template inline void SolidMechanicsModelCohesive::packUnpackFacetStressDataHelper(ByElementTypeArray & data_to_pack, CommunicationBuffer & buffer, const Array & element) const { ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; UInt nb_quad_per_elem = 0; UInt sp2 = spatial_dimension * spatial_dimension; UInt nb_component = sp2 * 2; bool element_rank = 0; Array * vect = NULL; Array > * element_to_facet = NULL; Array::const_iterator it = element.begin(); Array::const_iterator end = element.end(); for (; it != end; ++it) { const Element & el = *it; if(el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; vect = &data_to_pack(el.type, el.ghost_type); element_to_facet = &( mesh_facets.getElementToSubelement(el.type, el.ghost_type) ); nb_quad_per_elem = this->getFEM("FacetsFEM").getNbQuadraturePoints(el.type, el.ghost_type); } if (pack_helper) element_rank = (*element_to_facet)(el.element)[0].ghost_type != _not_ghost; else element_rank = (*element_to_facet)(el.element)[0].ghost_type == _not_ghost; for (UInt q = 0; q < nb_quad_per_elem; ++q) { Vector data(vect->storage() + (el.element * nb_quad_per_elem + q) * nb_component + element_rank * sp2, sp2); if(pack_helper) buffer << data; else buffer >> data; } } } diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive_parallel.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive_parallel.cc index c694d6c8c..e3aac9f83 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive_parallel.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive_parallel.cc @@ -1,183 +1,170 @@ /** * @file solid_mechanics_model_cohesive_parallel.cc * * @author Marco Vocialta * * @date Fri Jun 14 16:59:55 2013 * * @brief Functions for parallel cohesive elements * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model_cohesive.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initParallel(MeshPartition * partition, DataAccessor * data_accessor, bool extrinsic) { AKANTU_DEBUG_IN(); SolidMechanicsModel::initParallel(partition, data_accessor); /// create the distributed synchronizer for cohesive elements cohesive_distributed_synchronizer = new DistributedSynchronizer(mesh, "cohesive_distributed_synchronizer"); synch_registry->registerSynchronizer(*cohesive_distributed_synchronizer, _gst_material_id); synch_registry->registerSynchronizer(*cohesive_distributed_synchronizer, _gst_smm_stress); synch_registry->registerSynchronizer(*cohesive_distributed_synchronizer, _gst_smm_boundary); DistributedSynchronizer & distributed_synchronizer = dynamic_cast(*synch_parallel); distributed_synchronizer.filterElementsByKind(cohesive_distributed_synchronizer, _ek_cohesive); /// create the facet synchronizer for extrinsic simulations if (extrinsic) { rank_to_element = new ByElementTypeUInt("prank_to_element", id); ByElementTypeUInt & prank_to_element = *rank_to_element; distributed_synchronizer.buildPrankToElement(prank_to_element); MeshUtils::buildAllFacetsParallel(mesh, mesh_facets, prank_to_element); facet_generated = true; facet_synchronizer = FacetSynchronizer::createFacetSynchronizer(distributed_synchronizer, mesh_facets); synch_registry->registerSynchronizer(*facet_synchronizer, _gst_smmc_facets); synch_registry->registerSynchronizer(*facet_synchronizer, _gst_smmc_facets_conn); synchronizeGhostFacets(); facet_stress_synchronizer = FacetStressSynchronizer::createFacetStressSynchronizer(*facet_synchronizer, mesh_facets); synch_registry->registerSynchronizer(*facet_stress_synchronizer, _gst_smmc_facets_stress); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::fillGlobalConnectivity(ByElementTypeUInt & global_connectivity, GhostType ghost_type, bool just_init) { AKANTU_DEBUG_IN(); Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, ghost_type); Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, ghost_type); for(; it != end; ++it) { ElementType type_facet = *it; Array & connectivity = mesh_facets.getConnectivity(type_facet, ghost_type); Array & g_connectivity = global_connectivity(type_facet, ghost_type); UInt nb_nodes_per_facet = connectivity.getNbComponent(); UInt nb_facet = connectivity.getSize(); g_connectivity.extendComponentsInterlaced(nb_nodes_per_facet, 1); g_connectivity.resize(nb_facet); if (just_init) continue; mesh_facets.getGlobalConnectivity(g_connectivity, type_facet, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::synchronizeGhostFacets() { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int psize = comm.getNbProc(); if (psize > 1) { /// correct facets' connectivity according to normals global_connectivity = new ByElementTypeUInt("global_connectivity", id); ByElementTypeUInt & g_connectivity = *global_connectivity; mesh_facets.initByElementTypeArray(g_connectivity, 1, spatial_dimension - 1); /// copy facet normals for not ghost elements fillGlobalConnectivity(g_connectivity, _not_ghost, false); fillGlobalConnectivity(g_connectivity, _ghost, true); /// communicate synch_registry->synchronize(_gst_smmc_facets_conn); /// flip facets - MeshUtils::flipFacets(mesh_facets, *global_connectivity, _ghost); + MeshUtils::flipFacets(mesh_facets, g_connectivity, _ghost); delete global_connectivity; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -void SolidMechanicsModelCohesive::updateFacetSynchronizer() { - /// update synchronizer if needed - if (facet_synchronizer != NULL) { - DataAccessor * data_accessor = this; +void SolidMechanicsModelCohesive::updateFacetSynchronizers() { + /// update synchronizers if needed + if (facet_synchronizer != NULL) facet_synchronizer->updateDistributedSynchronizer(*cohesive_distributed_synchronizer, - *data_accessor, - cohesive_el_to_facet); + *this, + mesh); - for (ghost_type_t::iterator gt = ghost_type_t::begin(); - gt != ghost_type_t::end(); ++gt) { + if (facet_stress_synchronizer != NULL) + facet_stress_synchronizer->updateFacetStressSynchronizer(inserter, + *rank_to_element, + *this); - GhostType gt_facet = *gt; - - Mesh::type_iterator it = mesh_facets.firstType(spatial_dimension - 1, gt_facet); - Mesh::type_iterator end = mesh_facets.lastType(spatial_dimension - 1, gt_facet); - - for(; it != end; ++it) { - ElementType type_facet = *it; - Array & cohesive_el_to_f = cohesive_el_to_facet(type_facet, gt_facet); - - for (UInt f = 0; f < cohesive_el_to_f.getSize(); ++f) - cohesive_el_to_f(f) = std::numeric_limits::max(); - } - } - } } __END_AKANTU__ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive_parallel.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive_parallel.hh index 38d205c72..5be3d5cbb 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive_parallel.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive_parallel.hh @@ -1,107 +1,107 @@ /** * @file solid_mechanics_model_cohesive_parallel.hh * * @author Marco Vocialta * @author Nicolas Richart * * @date Fri Jun 14 17:09:09 2013 * * @brief Include of the class members for parallelism * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// register the tags associated with the parallel synchronizer for /// cohesive elements void initParallel(MeshPartition * partition, DataAccessor * data_accessor = NULL, bool extrinsic = false); protected: void fillSynchronizeNormals(ByElementTypeReal & facet_normals, GhostType ghost_type); void synchronizeGhostFacets(); -void updateFacetSynchronizer(); +void updateFacetSynchronizers(); void fillGlobalConnectivity(ByElementTypeUInt & global_connectivity, GhostType ghost_type, bool just_init); /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ public: inline UInt getNbQuadsForFacetCheck(const Array & elements) const; inline UInt getNbNodesPerElementList(const Array & elements) const; inline virtual UInt getNbDataForElements(const Array & elements, SynchronizationTag tag) const; inline virtual void packElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) const; inline virtual void unpackElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag); template inline void packFacetStressDataHelper(const ByElementTypeArray & data_to_pack, CommunicationBuffer & buffer, const Array & elements) const; template inline void unpackFacetStressDataHelper(ByElementTypeArray & data_to_unpack, CommunicationBuffer & buffer, const Array & elements) const; template inline void packUnpackFacetStressDataHelper(ByElementTypeArray & data_to_pack, CommunicationBuffer & buffer, const Array & element) const; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// facet synchronizer FacetSynchronizer * facet_synchronizer; /// facet stress synchronizer FacetStressSynchronizer * facet_stress_synchronizer; /// cohesive elements synchronizer DistributedSynchronizer * cohesive_distributed_synchronizer; -/// stored ghost facet normals sent by other processors -ByElementTypeUInt * global_connectivity; - /// store processor rank for each element ByElementTypeUInt * rank_to_element; + +/// global connectivity +ByElementTypeUInt * global_connectivity; diff --git a/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc b/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc index cc9931c0f..7bc6ec5d8 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc @@ -1,551 +1,492 @@ /** * @file solid_mechanics_model_inline_impl.cc * * @author Guillaume Anciaux * @author Nicolas Richart * * @date Wed Aug 04 10:58:42 2010 * * @brief Implementation of the inline functions of the SolidMechanicsModel class * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ inline Material & SolidMechanicsModel::getMaterial(UInt mat_index) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(mat_index < materials.size(), "The model " << id << " has no material no "<< mat_index); AKANTU_DEBUG_OUT(); return *materials[mat_index]; } /* -------------------------------------------------------------------------- */ inline const Material & SolidMechanicsModel::getMaterial(UInt mat_index) const { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(mat_index < materials.size(), "The model " << id << " has no material no "<< mat_index); AKANTU_DEBUG_OUT(); return *materials[mat_index]; } /* -------------------------------------------------------------------------- */ inline Material & SolidMechanicsModel::getMaterial(const std::string & name) { AKANTU_DEBUG_IN(); std::map::const_iterator it = materials_names_to_id.find(name); AKANTU_DEBUG_ASSERT(it != materials_names_to_id.end(), "The model " << id << " has no material named "<< name); AKANTU_DEBUG_OUT(); return *materials[it->second]; } /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModel::getMaterialIndex(const std::string & name) const { AKANTU_DEBUG_IN(); std::map::const_iterator it = materials_names_to_id.find(name); AKANTU_DEBUG_ASSERT(it != materials_names_to_id.end(), "The model " << id << " has no material named "<< name); AKANTU_DEBUG_OUT(); return it->second; } /* -------------------------------------------------------------------------- */ inline const Material & SolidMechanicsModel::getMaterial(const std::string & name) const { AKANTU_DEBUG_IN(); std::map::const_iterator it = materials_names_to_id.find(name); AKANTU_DEBUG_ASSERT(it != materials_names_to_id.end(), "The model " << id << " has no material named "<< name); AKANTU_DEBUG_OUT(); return *materials[it->second]; } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::setMaterialSelector(MaterialSelector & selector) { if(is_default_material_selector) delete material_selector; material_selector = &selector; is_default_material_selector = false; } /* -------------------------------------------------------------------------- */ inline FEM & SolidMechanicsModel::getFEMBoundary(const ID & name) { return dynamic_cast(getFEMClassBoundary(name)); } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::splitElementByMaterial(const Array & elements, Array * elements_per_mat) const { ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; const Array * elem_mat = NULL; Array::const_iterator it = elements.begin(); Array::const_iterator end = elements.end(); for (; it != end; ++it) { Element el = *it; if(el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; elem_mat = &element_index_by_material(el.type, el.ghost_type); } UInt old_id = el.element; el.element = (*elem_mat)(old_id, 1); elements_per_mat[(*elem_mat)(old_id, 0)].push_back(el); } } /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModel::getNbDataForElements(const Array & elements, SynchronizationTag tag) const { AKANTU_DEBUG_IN(); UInt size = 0; - -#ifndef AKANTU_NDEBUG - size += elements.getSize() * spatial_dimension * sizeof(Real); /// position of the barycenter of the element (only for check) -#endif - UInt nb_nodes_per_element = 0; Array::const_iterator it = elements.begin(); Array::const_iterator end = elements.end(); for (; it != end; ++it) { const Element & el = *it; nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type); } switch(tag) { case _gst_material_id: { size += elements.getSize() * 2 * sizeof(UInt); break; } case _gst_smm_mass: { size += nb_nodes_per_element * sizeof(Real) * spatial_dimension; // mass vector break; } case _gst_smm_for_strain: { size += nb_nodes_per_element * spatial_dimension * sizeof(Real); // displacement break; } case _gst_smm_boundary: { // force, displacement, boundary size += nb_nodes_per_element * spatial_dimension * (2 * sizeof(Real) + sizeof(bool)); break; } default: { } } if(tag != _gst_material_id) { Array * elements_per_mat = new Array[materials.size()]; this->splitElementByMaterial(elements, elements_per_mat); for (UInt i = 0; i < materials.size(); ++i) { size += materials[i]->getNbDataForElements(elements_per_mat[i], tag); } delete [] elements_per_mat; } AKANTU_DEBUG_OUT(); return size; } -/* -------------------------------------------------------------------------- */ -inline void SolidMechanicsModel::packBarycenter(const Mesh & mesh, - CommunicationBuffer & buffer, - const Array & elements, - SynchronizationTag tag) const { - Array::const_iterator bit = elements.begin(); - Array::const_iterator bend = elements.end(); - for (; bit != bend; ++bit) { - const Element & element = *bit; - Vector barycenter(spatial_dimension); - mesh.getBarycenter(element.element, element.type, barycenter.storage(), element.ghost_type); - buffer << barycenter; - } -} - /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::packElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) const { AKANTU_DEBUG_IN(); -#ifndef AKANTU_NDEBUG - packBarycenter(mesh, buffer, elements, tag); -#endif - switch(tag) { - case _gst_material_id: { packElementalDataHelper(element_index_by_material, buffer, elements, false, getFEM()); break; } case _gst_smm_mass: { packNodalDataHelper(*mass, buffer, elements, mesh); break; } case _gst_smm_for_strain: { packNodalDataHelper(*displacement, buffer, elements, mesh); break; } case _gst_smm_boundary: { packNodalDataHelper(*force, buffer, elements, mesh); packNodalDataHelper(*velocity, buffer, elements, mesh); packNodalDataHelper(*boundary, buffer, elements, mesh); break; } default: { } } if(tag != _gst_material_id) { Array * elements_per_mat = new Array[materials.size()]; splitElementByMaterial(elements, elements_per_mat); for (UInt i = 0; i < materials.size(); ++i) { materials[i]->packElementData(buffer, elements_per_mat[i], tag); } delete [] elements_per_mat; } AKANTU_DEBUG_OUT(); } -/* -------------------------------------------------------------------------- */ -inline void SolidMechanicsModel::unpackBarycenter(const Mesh & mesh, - CommunicationBuffer & buffer, - const Array & elements, - SynchronizationTag tag) { - Array::const_iterator bit = elements.begin(); - Array::const_iterator bend = elements.end(); - - for (; bit != bend; ++bit) { - const Element & element = *bit; - - Vector barycenter_loc(spatial_dimension); - mesh.getBarycenter(element.element, element.type, barycenter_loc.storage(), element.ghost_type); - Vector barycenter(spatial_dimension); - buffer >> barycenter; - Real tolerance = 1e-15; - Real bary_norm = barycenter.norm(); - for (UInt i = 0; i < spatial_dimension; ++i) { - if((std::abs((barycenter(i) - barycenter_loc(i))/bary_norm) <= tolerance) || - (std::abs(barycenter_loc(i)) <= 0 && std::abs(barycenter(i)) <= tolerance)) continue; - AKANTU_DEBUG_ERROR("Unpacking an unknown value for the element: " - << element - << "(barycenter[" << i << "] = " << barycenter_loc(i) - << " and buffer[" << i << "] = " << barycenter(i) << ") [" - << std::abs((barycenter(i) - barycenter_loc(i))/barycenter_loc(i)) - << "] - tag: " << tag); - } - } -} - /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::unpackElementData(CommunicationBuffer & buffer, const Array & elements, SynchronizationTag tag) { AKANTU_DEBUG_IN(); -#ifndef AKANTU_NDEBUG - unpackBarycenter(mesh, buffer, elements, tag); -#endif - switch(tag) { case _gst_material_id: { unpackElementalDataHelper(element_index_by_material, buffer, elements, false, getFEM()); break; } case _gst_smm_mass: { unpackNodalDataHelper(*mass, buffer, elements, mesh); break; } case _gst_smm_for_strain: { unpackNodalDataHelper(*displacement, buffer, elements, mesh); break; } case _gst_smm_boundary: { unpackNodalDataHelper(*force, buffer, elements, mesh); unpackNodalDataHelper(*velocity, buffer, elements, mesh); unpackNodalDataHelper(*boundary, buffer, elements, mesh); break; } default: { } } if(tag != _gst_material_id) { Array * elements_per_mat = new Array[materials.size()]; splitElementByMaterial(elements, elements_per_mat); for (UInt i = 0; i < materials.size(); ++i) { materials[i]->unpackElementData(buffer, elements_per_mat[i], tag); } delete [] elements_per_mat; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModel::getNbDataToPack(SynchronizationTag tag) const { AKANTU_DEBUG_IN(); UInt size = 0; // UInt nb_nodes = mesh.getNbNodes(); switch(tag) { case _gst_smm_uv: { size += sizeof(Real) * spatial_dimension * 2; break; } case _gst_smm_res: { size += sizeof(Real) * spatial_dimension; break; } case _gst_smm_mass: { size += sizeof(Real) * spatial_dimension; break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ inline UInt SolidMechanicsModel::getNbDataToUnpack(SynchronizationTag tag) const { AKANTU_DEBUG_IN(); UInt size = 0; // UInt nb_nodes = mesh.getNbNodes(); switch(tag) { case _gst_smm_uv: { size += sizeof(Real) * spatial_dimension * 2; break; } case _gst_smm_res: { size += sizeof(Real) * spatial_dimension; break; } case _gst_smm_mass: { size += sizeof(Real) * spatial_dimension; break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::packData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag) const { AKANTU_DEBUG_IN(); switch(tag) { case _gst_smm_uv: { Array::iterator< Vector > it_disp = displacement->begin(spatial_dimension); Array::iterator< Vector > it_velo = velocity->begin(spatial_dimension); buffer << it_disp[index]; buffer << it_velo[index]; break; } case _gst_smm_res: { Array::iterator< Vector > it_res = residual->begin(spatial_dimension); buffer << it_res[index]; break; } case _gst_smm_mass: { AKANTU_DEBUG_INFO("pack mass of node " << index << " which is " << (*mass)(index,0)); Array::iterator< Vector > it_mass = mass->begin(spatial_dimension); buffer << it_mass[index]; break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer, const UInt index, SynchronizationTag tag) { AKANTU_DEBUG_IN(); switch(tag) { case _gst_smm_uv: { Array::iterator< Vector > it_disp = displacement->begin(spatial_dimension); Array::iterator< Vector > it_velo = velocity->begin(spatial_dimension); buffer >> it_disp[index]; buffer >> it_velo[index]; break; } case _gst_smm_res: { Array::iterator< Vector > it_res = residual->begin(spatial_dimension); buffer >> it_res[index]; break; } case _gst_smm_mass: { AKANTU_DEBUG_INFO("mass of node " << index << " was " << (*mass)(index,0)); Array::iterator< Vector > it_mass = mass->begin(spatial_dimension); buffer >> it_mass[index]; AKANTU_DEBUG_INFO("mass of node " << index << " is now " << (*mass)(index,0)); break; } default: { AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); } } AKANTU_DEBUG_OUT(); } __END_AKANTU__ #include "sparse_matrix.hh" #include "solver.hh" __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ template void SolidMechanicsModel::solve(Array & increment) { jacobian_matrix->clear(); updateResidualInternal(); Real c = 0.,d = 0.,e = 0.; if(method == _static) { AKANTU_DEBUG_INFO("Solving K inc = r"); e = 1.; } else { AKANTU_DEBUG_INFO("Solving (c M + d C + e K) inc = r"); NewmarkBeta * nmb_int = dynamic_cast(integrator); c = nmb_int->getAccelerationCoefficient(time_step); d = nmb_int->getVelocityCoefficient(time_step); e = nmb_int->getDisplacementCoefficient(time_step); } // J = c M + d C + e K if(stiffness_matrix) jacobian_matrix->add(*stiffness_matrix, e); // if(type != NewmarkBeta::_acceleration_corrector) // jacobian_matrix->add(*stiffness_matrix, e); if(mass_matrix) jacobian_matrix->add(*mass_matrix, c); #if !defined(AKANTU_NDEBUG) if(AKANTU_DEBUG_TEST(dblDump)) mass_matrix->saveMatrix("M.mtx"); #endif if(velocity_damping_matrix) jacobian_matrix->add(*velocity_damping_matrix, d); jacobian_matrix->applyBoundary(*boundary); #if !defined(AKANTU_NDEBUG) if(AKANTU_DEBUG_TEST(dblDump)) jacobian_matrix->saveMatrix("J.mtx"); #endif solver->setRHS(*residual); // solve @f[ J \delta w = r @f] solver->solve(increment); } /* -------------------------------------------------------------------------- */ template bool SolidMechanicsModel::solveStep(Real tolerance, UInt max_iteration) { this->implicitPred(); this->updateResidual(); //this->dump(); AKANTU_DEBUG_ASSERT(stiffness_matrix != NULL, "You should first initialize the implicit solver and assemble the stiffness matrix"); if (method==_implicit_dynamic) { AKANTU_DEBUG_ASSERT(mass_matrix != NULL, "You should first initialize the implicit solver and assemble the mass matrix"); } switch (cmethod) { case _scm_newton_raphson_tangent: case _scm_newton_raphson_tangent_not_computed: break; case _scm_newton_raphson_tangent_modified: this->assembleStiffnessMatrix(); break; default: AKANTU_DEBUG_ERROR("The resolution method " << cmethod << " has not been implemented!"); } UInt iter = 0; bool converged = false; Real error = 0.; if(criteria == _scc_residual) { converged = this->testConvergence (tolerance, error); if(converged) return converged; } do { if (cmethod == _scm_newton_raphson_tangent) this->assembleStiffnessMatrix(); solve (*increment); this->implicitCorr(); if(criteria == _scc_residual) this->updateResidual(); converged = this->testConvergence (tolerance, error); if(criteria == _scc_increment && !converged) this->updateResidual(); //this->dump(); iter++; AKANTU_DEBUG_INFO("[" << criteria << "] Convergence iteration " << std::setw(std::log10(max_iteration)) << iter << ": error " << error << (converged ? " < " : " > ") << tolerance); } while (!converged && iter < max_iteration); return converged; } diff --git a/src/synchronizer/distributed_synchronizer.cc b/src/synchronizer/distributed_synchronizer.cc index b934d7b4a..8465d9396 100644 --- a/src/synchronizer/distributed_synchronizer.cc +++ b/src/synchronizer/distributed_synchronizer.cc @@ -1,1232 +1,1285 @@ /** * @file distributed_synchronizer.cc * * @author Nicolas Richart * * @date Thu Jun 16 16:36:52 2011 * * @brief implementation of a communicator using a static_communicator for real * send/receive * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "distributed_synchronizer.hh" #include "static_communicator.hh" #include "mesh_utils.hh" #include "mesh_data.hh" /* -------------------------------------------------------------------------- */ #include #include #include #if defined(AKANTU_DEBUG_TOOLS) # include "aka_debug_tools.hh" #endif /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ DistributedSynchronizer::DistributedSynchronizer(Mesh & mesh, SynchronizerID id, MemoryID memory_id) : Synchronizer(id, memory_id), mesh(mesh), static_communicator(&StaticCommunicator::getStaticCommunicator()) { AKANTU_DEBUG_IN(); nb_proc = static_communicator->getNbProc(); rank = static_communicator->whoAmI(); send_element = new Array[nb_proc]; recv_element = new Array[nb_proc]; mesh.registerEventHandler(*this); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ DistributedSynchronizer::~DistributedSynchronizer() { AKANTU_DEBUG_IN(); for (UInt p = 0; p < nb_proc; ++p) { send_element[p].clear(); recv_element[p].clear(); } delete [] send_element; delete [] recv_element; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ DistributedSynchronizer * DistributedSynchronizer:: createDistributedSynchronizerMesh(Mesh & mesh, const MeshPartition * partition, UInt root, SynchronizerID id, MemoryID memory_id) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt nb_proc = comm.getNbProc(); UInt my_rank = comm.whoAmI(); DistributedSynchronizer & communicator = *(new DistributedSynchronizer(mesh, id, memory_id)); if(nb_proc == 1) { // old_nodes->resize(mesh.nodes->getSize()); // for (UInt i = 0; i < mesh.nodes->getSize(); ++i) (*old_nodes)(i) = i; return &communicator; } UInt * local_connectivity = NULL; UInt * local_partitions = NULL; Array * old_nodes = mesh.getNodesGlobalIdsPointer(); old_nodes->resize(0); Array * nodes = mesh.getNodesPointer(); UInt spatial_dimension = nodes->getNbComponent(); /* ------------------------------------------------------------------------ */ /* Local (rank == root) */ /* ------------------------------------------------------------------------ */ if(my_rank == root) { AKANTU_DEBUG_ASSERT(partition->getNbPartition() == nb_proc, "The number of partition does not match the number of processors: " << partition->getNbPartition() << " != " << nb_proc); /** * connectivity and communications scheme construction */ Mesh::type_iterator it = mesh.firstType(_all_dimensions, _not_ghost, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(_all_dimensions, _not_ghost, _ek_not_defined); UInt count = 0; /* --- MAIN LOOP ON TYPES --- */ for(; it != end; ++it) { ElementType type = *it; UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_element = mesh.getNbElement(*it); UInt nb_local_element[nb_proc]; UInt nb_ghost_element[nb_proc]; UInt nb_element_to_send[nb_proc]; memset(nb_local_element, 0, nb_proc*sizeof(UInt)); memset(nb_ghost_element, 0, nb_proc*sizeof(UInt)); memset(nb_element_to_send, 0, nb_proc*sizeof(UInt)); /// \todo change this ugly way to avoid a problem if an element /// type is present in the mesh but not in the partitions const Array * tmp_partition_num = NULL; try { tmp_partition_num = &partition->getPartition(type, _not_ghost); } catch(...) { continue; } const Array & partition_num = *tmp_partition_num; const CSR & ghost_partition = partition->getGhostPartitionCSR()(type, _not_ghost); // const Array & ghost_partition = partition->getGhostPartition(type, _ghost); // const Array & ghost_partition_offset = partition->getGhostPartitionOffset(type, _ghost); /* -------------------------------------------------------------------- */ /// constructing the reordering structures for (UInt el = 0; el < nb_element; ++el) { nb_local_element[partition_num(el)]++; for (CSR::const_iterator part = ghost_partition.begin(el); part != ghost_partition.end(el); ++part) { nb_ghost_element[*part]++; } nb_element_to_send[partition_num(el)] += ghost_partition.getNbCols(el) + 1; } /// allocating buffers UInt * buffers[nb_proc]; UInt * buffers_tmp[nb_proc]; for (UInt p = 0; p < nb_proc; ++p) { UInt size = nb_nodes_per_element * (nb_local_element[p] + nb_ghost_element[p]); buffers[p] = new UInt[size]; buffers_tmp[p] = buffers[p]; } /// copying the local connectivity UInt * conn_val = mesh.getConnectivity(type, _not_ghost).values; for (UInt el = 0; el < nb_element; ++el) { memcpy(buffers_tmp[partition_num(el)], conn_val + el * nb_nodes_per_element, nb_nodes_per_element * sizeof(UInt)); buffers_tmp[partition_num(el)] += nb_nodes_per_element; } /// copying the connectivity of ghost element for (UInt el = 0; el < nb_element; ++el) { for (CSR::const_iterator part = ghost_partition.begin(el); part != ghost_partition.end(el); ++part) { UInt proc = *part; memcpy(buffers_tmp[proc], conn_val + el * nb_nodes_per_element, nb_nodes_per_element * sizeof(UInt)); buffers_tmp[proc] += nb_nodes_per_element; } } /// tag info std::vector tag_names; mesh.getMeshData().getTagNames(tag_names, type); // Make sure the tags are sorted (or at least not in random order), // because they come from a map !! std::sort(tag_names.begin(), tag_names.end()); UInt nb_tags = tag_names.size(); /* -------->>>>-SIZE + CONNECTIVITY------------------------------------ */ /// send all connectivity and ghost information to all processors std::vector requests; for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { UInt size[5]; size[0] = (UInt) type; size[1] = nb_local_element[p]; size[2] = nb_ghost_element[p]; size[3] = nb_element_to_send[p]; size[4] = nb_tags; AKANTU_DEBUG_INFO("Sending connectivities informations to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_SIZES) <<")"); comm.send(size, 5, p, Tag::genTag(my_rank, count, TAG_SIZES)); AKANTU_DEBUG_INFO("Sending connectivities to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_CONNECTIVITY) <<")"); requests.push_back(comm.asyncSend(buffers[p], nb_nodes_per_element * (nb_local_element[p] + nb_ghost_element[p]), p, Tag::genTag(my_rank, count, TAG_CONNECTIVITY))); } else { local_connectivity = buffers[p]; } } /// create the renumbered connectivity AKANTU_DEBUG_INFO("Renumbering local connectivities"); MeshUtils::renumberMeshNodes(mesh, local_connectivity, nb_local_element[root], nb_ghost_element[root], type, *old_nodes); comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); for (UInt p = 0; p < nb_proc; ++p) { delete [] buffers[p]; } /* -------------------------------------------------------------------- */ for (UInt p = 0; p < nb_proc; ++p) { buffers[p] = new UInt[nb_ghost_element[p] + nb_element_to_send[p]]; buffers_tmp[p] = buffers[p]; } /// splitting the partition information to send them to processors UInt count_by_proc[nb_proc]; memset(count_by_proc, 0, nb_proc*sizeof(UInt)); for (UInt el = 0; el < nb_element; ++el) { *(buffers_tmp[partition_num(el)]++) = ghost_partition.getNbCols(el); UInt i(0); for (CSR::const_iterator part = ghost_partition.begin(el); part != ghost_partition.end(el); ++part, ++i) { *(buffers_tmp[partition_num(el)]++) = *part; } } for (UInt el = 0; el < nb_element; ++el) { UInt i(0); for (CSR::const_iterator part = ghost_partition.begin(el); part != ghost_partition.end(el); ++part, ++i) { *(buffers_tmp[*part]++) = partition_num(el); } } /* -------->>>>-PARTITIONS--------------------------------------------- */ /// last data to compute the communication scheme for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { AKANTU_DEBUG_INFO("Sending partition informations to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_PARTITIONS) <<")"); requests.push_back(comm.asyncSend(buffers[p], nb_element_to_send[p] + nb_ghost_element[p], p, Tag::genTag(my_rank, count, TAG_PARTITIONS))); } else { local_partitions = buffers[p]; } } if(Mesh::getSpatialDimension(type) == mesh.getSpatialDimension()) { AKANTU_DEBUG_INFO("Creating communications scheme"); communicator.fillCommunicationScheme(local_partitions, nb_local_element[root], nb_ghost_element[root], type); } comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); for (UInt p = 0; p < nb_proc; ++p) { delete [] buffers[p]; } /* -------------------------------------------------------------------- */ /// send data assossiated to the mesh /* -------->>>>-TAGS------------------------------------------------- */ if(nb_tags != 0) { UInt mesh_data_sizes_buffer_length; MeshData & mesh_data = mesh.getMeshData(); { // Sending information about the tags in mesh_data: name, data type and // number of components of the underlying array associated to the current type DynamicCommunicationBuffer mesh_data_sizes_buffer; std::vector::const_iterator names_it = tag_names.begin(); std::vector::const_iterator names_end = tag_names.end(); for(;names_it != names_end; ++names_it) { mesh_data_sizes_buffer << *names_it; mesh_data_sizes_buffer << mesh_data.getTypeCode(*names_it); mesh_data_sizes_buffer << mesh_data.getNbComponent(*names_it, type); } mesh_data_sizes_buffer_length = mesh_data_sizes_buffer.getSize(); AKANTU_DEBUG_INFO("Broadcasting the size of the information about the mesh data tags: (" << mesh_data_sizes_buffer_length << ")." ); comm.broadcast(&mesh_data_sizes_buffer_length, 1, root); AKANTU_DEBUG_INFO("Broadcasting the information about the mesh data tags, addr " << (void*)mesh_data_sizes_buffer.storage()); if(mesh_data_sizes_buffer_length !=0) comm.broadcast(mesh_data_sizes_buffer.storage(), mesh_data_sizes_buffer.getSize(), root); } if(mesh_data_sizes_buffer_length !=0) { //Sending the actual data to each processor DynamicCommunicationBuffer buffers[nb_proc]; std::vector::const_iterator names_it = tag_names.begin(); std::vector::const_iterator names_end = tag_names.end(); // Loop over each tag for the current type for(;names_it != names_end; ++names_it) { // Type code of the current tag (i.e. the tag named *names_it) communicator.fillTagBuffer(mesh_data, buffers, *names_it, type, partition_num, ghost_partition); } std::vector requests; for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { AKANTU_DEBUG_INFO("Sending " << buffers[p].getSize() << " bytes of mesh data to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_MESH_DATA) <<")"); requests.push_back(comm.asyncSend(buffers[p].storage(), buffers[p].getSize(), p, Tag::genTag(my_rank, count, TAG_MESH_DATA))); } } names_it = tag_names.begin(); // Loop over each tag for the current type for(;names_it != names_end; ++names_it) { // Reinitializing the mesh data on the master communicator.populateMeshData(mesh_data, buffers[root], *names_it, type, mesh_data.getTypeCode(*names_it), mesh_data.getNbComponent(*names_it, type), nb_local_element[root], nb_ghost_element[root]); } // Nécsesaire ? oui comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); } } ++count; } /* -------->>>>-SIZE----------------------------------------------------- */ for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { UInt size[5]; size[0] = (UInt) _not_defined; size[1] = 0; size[2] = 0; size[3] = 0; size[4] = 0; AKANTU_DEBUG_INFO("Sending empty connectivities informations to proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_SIZES) <<")"); comm.send(size, 5, p, Tag::genTag(my_rank, count, TAG_SIZES)); } } /* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */ /** * Nodes coordinate construction and synchronization */ std::multimap< UInt, std::pair > nodes_to_proc; /// get the list of nodes to send and send them Real * local_nodes = NULL; UInt nb_nodes_per_proc[nb_proc]; UInt * nodes_per_proc[nb_proc]; /* --------<<<<-NB_NODES + NODES----------------------------------------- */ for (UInt p = 0; p < nb_proc; ++p) { UInt nb_nodes = 0; // UInt * buffer; if(p != root) { AKANTU_DEBUG_INFO("Receiving number of nodes from proc " << p << " TAG("<< Tag::genTag(p, 0, TAG_NB_NODES) <<")"); comm.receive(&nb_nodes, 1, p, Tag::genTag(p, 0, TAG_NB_NODES)); nodes_per_proc[p] = new UInt[nb_nodes]; nb_nodes_per_proc[p] = nb_nodes; AKANTU_DEBUG_INFO("Receiving list of nodes from proc " << p << " TAG("<< Tag::genTag(p, 0, TAG_NODES) <<")"); comm.receive(nodes_per_proc[p], nb_nodes, p, Tag::genTag(p, 0, TAG_NODES)); } else { nb_nodes = old_nodes->getSize(); nb_nodes_per_proc[p] = nb_nodes; nodes_per_proc[p] = old_nodes->values; } /// get the coordinates for the selected nodes Real * nodes_to_send = new Real[nb_nodes * spatial_dimension]; Real * nodes_to_send_tmp = nodes_to_send; for (UInt n = 0; n < nb_nodes; ++n) { memcpy(nodes_to_send_tmp, nodes->values + spatial_dimension * nodes_per_proc[p][n], spatial_dimension * sizeof(Real)); // nodes_to_proc.insert(std::make_pair(buffer[n], std::make_pair(p, n))); nodes_to_send_tmp += spatial_dimension; } /* -------->>>>-COORDINATES-------------------------------------------- */ if(p != root) { /// send them for distant processors AKANTU_DEBUG_INFO("Sending coordinates to proc " << p << " TAG("<< Tag::genTag(my_rank, 0, TAG_COORDINATES) <<")"); comm.send(nodes_to_send, nb_nodes * spatial_dimension, p, Tag::genTag(my_rank, 0, TAG_COORDINATES)); delete [] nodes_to_send; } else { /// save them for local processor local_nodes = nodes_to_send; } } /// construct the local nodes coordinates UInt nb_nodes = old_nodes->getSize(); nodes->resize(nb_nodes); memcpy(nodes->values, local_nodes, nb_nodes * spatial_dimension * sizeof(Real)); delete [] local_nodes; Array * nodes_type_per_proc[nb_proc]; for (UInt p = 0; p < nb_proc; ++p) { nodes_type_per_proc[p] = new Array(nb_nodes_per_proc[p]); } communicator.fillNodesType(mesh); /* --------<<<<-NODES_TYPE-1--------------------------------------------- */ for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { AKANTU_DEBUG_INFO("Receiving first nodes types from proc " << p << " TAG("<< Tag::genTag(my_rank, count, TAG_NODES_TYPE) <<")"); comm.receive(nodes_type_per_proc[p]->values, nb_nodes_per_proc[p], p, Tag::genTag(p, 0, TAG_NODES_TYPE)); } else { nodes_type_per_proc[p]->copy(mesh.getNodesType()); } for (UInt n = 0; n < nb_nodes_per_proc[p]; ++n) { if((*nodes_type_per_proc[p])(n) == -2) nodes_to_proc.insert(std::make_pair(nodes_per_proc[p][n], std::make_pair(p, n))); } } std::multimap< UInt, std::pair >::iterator it_node; std::pair< std::multimap< UInt, std::pair >::iterator, std::multimap< UInt, std::pair >::iterator > it_range; for (UInt i = 0; i < mesh.nb_global_nodes; ++i) { it_range = nodes_to_proc.equal_range(i); if(it_range.first == nodes_to_proc.end() || it_range.first->first != i) continue; UInt node_type = (it_range.first)->second.first; for (it_node = it_range.first; it_node != it_range.second; ++it_node) { UInt proc = it_node->second.first; UInt node = it_node->second.second; if(proc != node_type) nodes_type_per_proc[proc]->values[node] = node_type; } } /* -------->>>>-NODES_TYPE-2--------------------------------------------- */ std::vector requests; for (UInt p = 0; p < nb_proc; ++p) { if(p != root) { AKANTU_DEBUG_INFO("Sending nodes types to proc " << p << " TAG("<< Tag::genTag(my_rank, 0, TAG_NODES_TYPE) <<")"); requests.push_back(comm.asyncSend(nodes_type_per_proc[p]->values, nb_nodes_per_proc[p], p, Tag::genTag(my_rank, 0, TAG_NODES_TYPE))); } else { mesh.getNodesTypePointer()->copy(*nodes_type_per_proc[p]); } } comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); for (UInt p = 0; p < nb_proc; ++p) { if(p != root) delete [] nodes_per_proc[p]; delete nodes_type_per_proc[p]; } /* ---------------------------------------------------------------------- */ /* Distant (rank != root) */ /* ---------------------------------------------------------------------- */ } else { /** * connectivity and communications scheme construction on distant processors */ ElementType type = _not_defined; UInt count = 0; do { /* --------<<<<-SIZE--------------------------------------------------- */ UInt size[5] = { 0 }; comm.receive(size, 5, root, Tag::genTag(root, count, TAG_SIZES)); type = (ElementType) size[0]; UInt nb_local_element = size[1]; UInt nb_ghost_element = size[2]; UInt nb_element_to_send = size[3]; UInt nb_tags = size[4]; if(type != _not_defined) { UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); /* --------<<<<-CONNECTIVITY----------------------------------------- */ local_connectivity = new UInt[(nb_local_element + nb_ghost_element) * nb_nodes_per_element]; AKANTU_DEBUG_INFO("Receiving connectivities from proc " << root); comm.receive(local_connectivity, nb_nodes_per_element * (nb_local_element + nb_ghost_element), root, Tag::genTag(root, count, TAG_CONNECTIVITY)); AKANTU_DEBUG_INFO("Renumbering local connectivities"); MeshUtils::renumberMeshNodes(mesh, local_connectivity, nb_local_element, nb_ghost_element, type, *old_nodes); delete [] local_connectivity; /* --------<<<<-PARTITIONS--------------------------------------------- */ local_partitions = new UInt[nb_element_to_send + nb_ghost_element * 2]; AKANTU_DEBUG_INFO("Receiving partition informations from proc " << root); comm.receive(local_partitions, nb_element_to_send + nb_ghost_element * 2, root, Tag::genTag(root, count, TAG_PARTITIONS)); if(Mesh::getSpatialDimension(type) == mesh.getSpatialDimension()) { AKANTU_DEBUG_INFO("Creating communications scheme"); communicator.fillCommunicationScheme(local_partitions, nb_local_element, nb_ghost_element, type); } delete [] local_partitions; /* --------<<<<-TAGS------------------------------------------------- */ if(nb_tags != 0) { UInt mesh_data_sizes_buffer_length; CommunicationBuffer mesh_data_sizes_buffer; MeshData & mesh_data = mesh.getMeshData(); AKANTU_DEBUG_INFO("Receiving the size of the information about the mesh data tags."); comm.broadcast(&mesh_data_sizes_buffer_length, 1, root); if(mesh_data_sizes_buffer_length != 0) { mesh_data_sizes_buffer.resize(mesh_data_sizes_buffer_length); AKANTU_DEBUG_INFO("Receiving the information about the mesh data tags, addr " << (void*)mesh_data_sizes_buffer.storage()); comm.broadcast(mesh_data_sizes_buffer.storage(), mesh_data_sizes_buffer_length, root); AKANTU_DEBUG_INFO("Size of the information about the mesh data: " << mesh_data_sizes_buffer_length); std::vector tag_names; std::vector tag_type_codes; std::vector tag_nb_component; tag_names.resize(nb_tags); tag_type_codes.resize(nb_tags); tag_nb_component.resize(nb_tags); CommunicationBuffer mesh_data_buffer; UInt type_code_int; for(UInt i(0); i < nb_tags; ++i) { mesh_data_sizes_buffer >> tag_names[i]; mesh_data_sizes_buffer >> type_code_int; tag_type_codes[i] = static_cast(type_code_int); mesh_data_sizes_buffer >> tag_nb_component[i]; } std::vector::const_iterator names_it = tag_names.begin(); std::vector::const_iterator names_end = tag_names.end(); CommunicationStatus mesh_data_comm_status; AKANTU_DEBUG_INFO("Checking size of data to receive for mesh data TAG(" << Tag::genTag(root, count, TAG_MESH_DATA) << ")"); comm.probe(root, Tag::genTag(root, count, TAG_MESH_DATA), mesh_data_comm_status); UInt mesh_data_buffer_size(mesh_data_comm_status.getSize()); AKANTU_DEBUG_INFO("Receiving " << mesh_data_buffer_size << " bytes of mesh data TAG(" << Tag::genTag(root, count, TAG_MESH_DATA) << ")"); mesh_data_buffer.resize(mesh_data_buffer_size); comm.receive(mesh_data_buffer.storage(), mesh_data_buffer_size, root, Tag::genTag(root, count, TAG_MESH_DATA)); // Loop over each tag for the current type UInt k(0); for(; names_it != names_end; ++names_it, ++k) { communicator.populateMeshData(mesh_data, mesh_data_buffer, *names_it, type, tag_type_codes[k], tag_nb_component[k], nb_local_element, nb_ghost_element); } } } } ++count; } while(type != _not_defined); /** * Nodes coordinate construction and synchronization on distant processors */ /* -------->>>>-NB_NODES + NODES----------------------------------------- */ AKANTU_DEBUG_INFO("Sending list of nodes to proc " << root); UInt nb_nodes = old_nodes->getSize(); comm.send(&nb_nodes, 1, root, Tag::genTag(my_rank, 0, TAG_NB_NODES)); comm.send(old_nodes->values, nb_nodes, root, Tag::genTag(my_rank, 0, TAG_NODES)); /* --------<<<<-COORDINATES---------------------------------------------- */ nodes->resize(nb_nodes); AKANTU_DEBUG_INFO("Receiving coordinates from proc " << root); comm.receive(nodes->values, nb_nodes * spatial_dimension, root, Tag::genTag(root, 0, TAG_COORDINATES)); communicator.fillNodesType(mesh); /* -------->>>>-NODES_TYPE-1--------------------------------------------- */ Int * nodes_types = mesh.getNodesTypePointer()->values; AKANTU_DEBUG_INFO("Sending first nodes types to proc " << root); comm.send(nodes_types, nb_nodes, root, Tag::genTag(my_rank, 0, TAG_NODES_TYPE)); /* --------<<<<-NODES_TYPE-2--------------------------------------------- */ AKANTU_DEBUG_INFO("Receiving nodes types from proc " << root); comm.receive(nodes_types, nb_nodes, root, Tag::genTag(root, 0, TAG_NODES_TYPE)); } comm.broadcast(&(mesh.nb_global_nodes), 1, root); MeshUtils::fillElementToSubElementsData(mesh); AKANTU_DEBUG_OUT(); return &communicator; } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::fillTagBuffer(const MeshData & mesh_data, DynamicCommunicationBuffer * buffers, const std::string & tag_name, const ElementType & el_type, const Array & partition_num, const CSR & ghost_partition) { #define AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA(r, extra_param, elem) \ case BOOST_PP_TUPLE_ELEM(2, 0, elem) : { \ fillTagBufferTemplated(mesh_data, buffers, tag_name, el_type, partition_num, ghost_partition); \ break; \ } \ MeshDataTypeCode data_type_code = mesh_data.getTypeCode(tag_name); switch(data_type_code) { BOOST_PP_SEQ_FOR_EACH(AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA, , AKANTU_MESH_DATA_TYPES) default : AKANTU_DEBUG_ERROR("Could not obtain the type of tag" << tag_name << "!"); break; } #undef AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::fillNodesType(Mesh & mesh) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); Int * nodes_type = mesh.getNodesTypePointer()->values; UInt * nodes_set = new UInt[nb_nodes]; std::fill_n(nodes_set, nb_nodes, 0); const UInt NORMAL_SET = 1; const UInt GHOST_SET = 2; bool * already_seen = new bool[nb_nodes]; for(UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType) g; UInt set = NORMAL_SET; if (gt == _ghost) set = GHOST_SET; std::fill_n(already_seen, nb_nodes, false); Mesh::type_iterator it = mesh.firstType(_all_dimensions, gt, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(_all_dimensions, gt, _ek_not_defined); for(; it != end; ++it) { ElementType type = *it; UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_element = mesh.getNbElement(type, gt); Array::iterator< Vector > conn_it = mesh.getConnectivity(type, gt).begin(nb_nodes_per_element); for (UInt e = 0; e < nb_element; ++e, ++conn_it) { Vector & conn = *conn_it; for (UInt n = 0; n < nb_nodes_per_element; ++n) { AKANTU_DEBUG_ASSERT(conn(n) < nb_nodes, "Node " << conn(n) << " bigger than number of nodes " << nb_nodes); if(!already_seen[conn(n)]) { nodes_set[conn(n)] += set; already_seen[conn(n)] = true; } } } } } delete [] already_seen; for (UInt i = 0; i < nb_nodes; ++i) { if(nodes_set[i] == NORMAL_SET) nodes_type[i] = -1; else if(nodes_set[i] == GHOST_SET) nodes_type[i] = -3; else if(nodes_set[i] == (GHOST_SET + NORMAL_SET)) nodes_type[i] = -2; } delete [] nodes_set; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::fillCommunicationScheme(const UInt * partition, UInt nb_local_element, UInt nb_ghost_element, ElementType type) { AKANTU_DEBUG_IN(); Element element; element.type = type; element.kind = Mesh::getKind(type); const UInt * part = partition; part = partition; for (UInt lel = 0; lel < nb_local_element; ++lel) { UInt nb_send = *part; part++; element.element = lel; element.ghost_type = _not_ghost; for (UInt p = 0; p < nb_send; ++p) { UInt proc = *part; part++; AKANTU_DEBUG(dblAccessory, "Must send : " << element << " to proc " << proc); (send_element[proc]).push_back(element); } } for (UInt gel = 0; gel < nb_ghost_element; ++gel) { UInt proc = *part; part++; element.element = gel; element.ghost_type = _ghost; AKANTU_DEBUG(dblAccessory, "Must recv : " << element << " from proc " << proc); recv_element[proc].push_back(element); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::asynchronousSynchronize(DataAccessor & data_accessor, SynchronizationTag tag) { AKANTU_DEBUG_IN(); if (communications.find(tag) == communications.end()) { communications[tag].resize(nb_proc); computeBufferSize(data_accessor, tag); } Communication & communication = communications[tag]; AKANTU_DEBUG_ASSERT(communication.send_requests.size() == 0, "There must be some pending sending communications. Tag is " << tag); std::map::iterator t_it = tag_counter.find(tag); UInt counter = 0; if(t_it == tag_counter.end()) { tag_counter[tag] = 0; } else { counter = ++(t_it->second); } for (UInt p = 0; p < nb_proc; ++p) { UInt ssize = communication.size_to_send[p]; if(p == rank || ssize == 0) continue; CommunicationBuffer & buffer = communication.send_buffer[p]; buffer.resize(ssize); #ifndef AKANTU_NDEBUG UInt nb_elements = send_element[p].getSize(); AKANTU_DEBUG_INFO("Packing data for proc " << p << " (" << ssize << "/" << nb_elements <<" data to send/elements)"); + + /// pack barycenters in debug mode + Array::const_iterator bit = send_element[p].begin(); + Array::const_iterator bend = send_element[p].end(); + for (; bit != bend; ++bit) { + const Element & element = *bit; + Vector barycenter(mesh.getSpatialDimension()); + mesh.getBarycenter(element.element, element.type, barycenter.storage(), element.ghost_type); + buffer << barycenter; + } #endif data_accessor.packElementData(buffer, send_element[p], tag); AKANTU_DEBUG_ASSERT(buffer.getPackedSize() == ssize, "a problem have been introduced with " << "false sent sizes declaration " << buffer.getPackedSize() << " != " << ssize); AKANTU_DEBUG_INFO("Posting send to proc " << p << " (tag: " << tag << " - " << ssize << " data to send)" << " [" << Tag::genTag(rank, counter, tag) << "]"); communication.send_requests.push_back(static_communicator->asyncSend(buffer.storage(), ssize, p, Tag::genTag(rank, counter, tag))); } AKANTU_DEBUG_ASSERT(communication.recv_requests.size() == 0, "There must be some pending receive communications"); for (UInt p = 0; p < nb_proc; ++p) { UInt rsize = communication.size_to_receive[p]; if(p == rank || rsize == 0) continue; CommunicationBuffer & buffer = communication.recv_buffer[p]; buffer.resize(rsize); AKANTU_DEBUG_INFO("Posting receive from proc " << p << " (tag: " << tag << " - " << rsize << " data to receive) " << " [" << Tag::genTag(p, counter, tag) << "]"); communication.recv_requests.push_back(static_communicator->asyncReceive(buffer.storage(), rsize, p, Tag::genTag(p, counter, tag))); } #if defined(AKANTU_DEBUG_TOOLS) && defined(AKANTU_CORE_CXX11) static std::set tags; if(tags.find(tag) == tags.end()) { debug::element_manager.print(debug::_dm_synch, [&send_element, rank, nb_proc, tag, id](const Element & el)->std::string { std::stringstream out; UInt elp = 0; for (UInt p = 0; p < nb_proc; ++p) { UInt pos = send_element[p].find(el); if(pos != UInt(-1)) { if(elp > 0) out << std::endl; out << id << " send (" << pos << "/" << send_element[p].getSize() << ") to proc " << p << " tag:" << tag; ++elp; } } return out.str(); }); debug::element_manager.print(debug::_dm_synch, [&recv_element, rank, nb_proc, tag, id](const Element & el)->std::string { std::stringstream out; UInt elp = 0; for (UInt p = 0; p < nb_proc; ++p) { if(p == rank) continue; UInt pos = recv_element[p].find(el); if(pos != UInt(-1)) { if(elp > 0) out << std::endl; out << id << " recv (" << pos << "/" << recv_element[p].getSize() << ") from proc " << p << " tag:" << tag; ++elp; } } return out.str(); }); tags.insert(tag); } #endif AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::waitEndSynchronize(DataAccessor & data_accessor, SynchronizationTag tag) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(communications.find(tag) != communications.end(), "No communication with the tag \"" << tag <<"\" started"); Communication & communication = communications[tag]; std::vector req_not_finished; std::vector * req_not_finished_tmp = &req_not_finished; std::vector * recv_requests_tmp = &(communication.recv_requests); // static_communicator->waitAll(recv_requests); while(!recv_requests_tmp->empty()) { for (std::vector::iterator req_it = recv_requests_tmp->begin(); req_it != recv_requests_tmp->end() ; ++req_it) { CommunicationRequest * req = *req_it; if(static_communicator->testRequest(req)) { UInt proc = req->getSource(); AKANTU_DEBUG_INFO("Unpacking data coming from proc " << proc); CommunicationBuffer & buffer = communication.recv_buffer[proc]; +#ifndef AKANTU_NDEBUG + Array::const_iterator bit = recv_element[proc].begin(); + Array::const_iterator bend = recv_element[proc].end(); + + UInt spatial_dimension = mesh.getSpatialDimension(); + + for (; bit != bend; ++bit) { + const Element & element = *bit; + + Vector barycenter_loc(spatial_dimension); + mesh.getBarycenter(element.element, + element.type, + barycenter_loc.storage(), + element.ghost_type); + Vector barycenter(spatial_dimension); + buffer >> barycenter; + Real tolerance = Math::getTolerance(); + Real bary_norm = barycenter.norm(); + for (UInt i = 0; i < spatial_dimension; ++i) { + if((std::abs((barycenter(i) - barycenter_loc(i))/bary_norm) <= tolerance) || + (std::abs(barycenter_loc(i)) <= 0 && std::abs(barycenter(i)) <= tolerance)) continue; + AKANTU_DEBUG_ERROR("Unpacking an unknown value for the element: " + << element + << "(barycenter[" << i << "] = " << barycenter_loc(i) + << " and buffer[" << i << "] = " << barycenter(i) << ") [" + << std::abs((barycenter(i) - barycenter_loc(i))/barycenter_loc(i)) + << "] - tag: " << tag); + } + } +#endif + data_accessor.unpackElementData(buffer, recv_element[proc], tag); buffer.resize(0); AKANTU_DEBUG_ASSERT(buffer.getLeftToUnpack() == 0, "all data have not been unpacked: " << buffer.getLeftToUnpack() << " bytes left"); static_communicator->freeCommunicationRequest(req); } else { req_not_finished_tmp->push_back(req); } } std::vector * swap = req_not_finished_tmp; req_not_finished_tmp = recv_requests_tmp; recv_requests_tmp = swap; req_not_finished_tmp->clear(); } AKANTU_DEBUG_INFO("Waiting that every send requests are received"); static_communicator->waitAll(communication.send_requests); for (std::vector::iterator req_it = communication.send_requests.begin(); req_it != communication.send_requests.end() ; ++req_it) { CommunicationRequest & req = *(*req_it); if(static_communicator->testRequest(&req)) { UInt proc = req.getDestination(); CommunicationBuffer & buffer = communication.send_buffer[proc]; buffer.resize(0); static_communicator->freeCommunicationRequest(&req); } } communication.send_requests.clear(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::computeBufferSize(DataAccessor & data_accessor, SynchronizationTag tag) { AKANTU_DEBUG_IN(); for (UInt p = 0; p < nb_proc; ++p) { UInt ssend = 0; UInt sreceive = 0; if(p != rank) { if(send_element[p].getSize() != 0) { - ssend = data_accessor.getNbDataForElements(send_element[p], tag); +#ifndef AKANTU_NDEBUG + ssend += send_element[p].getSize() * mesh.getSpatialDimension() * sizeof(Real); +#endif + ssend += data_accessor.getNbDataForElements(send_element[p], tag); AKANTU_DEBUG_INFO("I have " << ssend << "(" << ssend / 1024. << "kB - "<< send_element[p].getSize() <<" element(s)) data to send to " << p << " for tag " << tag); } if(recv_element[p].getSize() != 0) { - sreceive = data_accessor.getNbDataForElements(recv_element[p], tag); +#ifndef AKANTU_NDEBUG + sreceive += recv_element[p].getSize() * mesh.getSpatialDimension() * sizeof(Real); +#endif + sreceive += data_accessor.getNbDataForElements(recv_element[p], tag); AKANTU_DEBUG_INFO("I have " << sreceive << "(" << sreceive / 1024. << "kB - "<< recv_element[p].getSize() <<" element(s)) data to receive for tag " << tag); } } communications[tag].size_to_send [p] = ssend; communications[tag].size_to_receive[p] = sreceive; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::printself(std::ostream & stream, int indent) const { std::string space; for(Int i = 0; i < indent; i++, space += AKANTU_INDENT); Int prank = StaticCommunicator::getStaticCommunicator().whoAmI(); Int psize = StaticCommunicator::getStaticCommunicator().getNbProc(); stream << "[" << prank << "/" << psize << "]" << space << "DistributedSynchronizer [" << std::endl; for (UInt p = 0; p < nb_proc; ++p) { if (p == UInt(prank)) continue; stream << "[" << prank << "/" << psize << "]" << space << " + Communication to proc " << p << " [" << std::endl; if(AKANTU_DEBUG_TEST(dblDump)) { stream << "[" << prank << "/" << psize << "]" << space << " - Element to send to proc " << p << " [" << std::endl; Array::iterator it_el = send_element[p].begin(); Array::iterator end_el = send_element[p].end(); for(;it_el != end_el; ++it_el) stream << "[" << prank << "/" << psize << "]" << space << " " << *it_el << std::endl; stream << "[" << prank << "/" << psize << "]" << space << " ]" << std::endl; stream << "[" << prank << "/" << psize << "]" << space << " - Element to recv from proc " << p << " [" << std::endl; it_el = recv_element[p].begin(); end_el = recv_element[p].end(); for(;it_el != end_el; ++it_el) stream << "[" << prank << "/" << psize << "]" << space << " " << *it_el << std::endl;stream << "[" << prank << "/" << psize << "]" << space << " ]" << std::endl; } std::map< SynchronizationTag, Communication>::const_iterator it = communications.begin(); std::map< SynchronizationTag, Communication>::const_iterator end = communications.end(); for (; it != end; ++it) { const SynchronizationTag & tag = it->first; const Communication & communication = it->second; UInt ssend = communication.size_to_send[p]; UInt sreceive = communication.size_to_receive[p]; stream << "[" << prank << "/" << psize << "]" << space << " - Tag " << tag << " -> " << ssend << "byte(s) -- <- " << sreceive << "byte(s)" << std::endl; } } } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::onElementsRemoved(const Array & element_to_remove, const ByElementTypeUInt & new_numbering, __attribute__((unused)) const RemovedElementsEvent & event) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt psize = comm.getNbProc(); UInt prank = comm.whoAmI(); std::vector isend_requests; Array * list_of_el = new Array[nb_proc]; // Handling ghost elements for (UInt p = 0; p < psize; ++p) { if (p == prank) continue; Array & recv = recv_element[p]; if(recv.getSize() == 0) continue; Array::iterator recv_begin = recv.begin(); Array::iterator recv_end = recv.end(); Array::const_iterator er_it = element_to_remove.begin(); Array::const_iterator er_end = element_to_remove.end(); Array & list = list_of_el[p]; for (UInt i = 0; recv_begin != recv_end; ++i, ++recv_begin) { const Element & el = *recv_begin; Array::const_iterator pos = std::find(er_it, er_end, el); if(pos == er_end) { list.push_back(i); } } if(list.getSize() == recv.getSize()) list.push_back(UInt(0)); else list.push_back(UInt(-1)); AKANTU_DEBUG_INFO("Sending a message of size " << list.getSize() << " to proc " << p << " TAG(" << Tag::genTag(prank, 0, 0) << ")"); isend_requests.push_back(comm.asyncSend(list.storage(), list.getSize(), p, Tag::genTag(prank, 0, 0))); list.erase(list.getSize() - 1); if(list.getSize() == recv.getSize()) continue; Array new_recv; for (UInt nr = 0; nr < list.getSize(); ++nr) { Element & el = recv(list(nr)); el.element = new_numbering(el.type, el.ghost_type)(el.element); new_recv.push_back(el); } AKANTU_DEBUG_INFO("I had " << recv.getSize() << " elements to recv from proc " << p << " and " << list.getSize() << " elements to keep. I have " << new_recv.getSize() << " elements left."); recv.copy(new_recv); } for (UInt p = 0; p < psize; ++p) { if (p == prank) continue; Array & send = send_element[p]; if(send.getSize() == 0) continue; CommunicationStatus status; AKANTU_DEBUG_INFO("Getting number of elements of proc " << p << " not needed anymore TAG("<< Tag::genTag(p, 0, 0) <<")"); comm.probe(p, Tag::genTag(p, 0, 0), status); Array list(status.getSize()); AKANTU_DEBUG_INFO("Receiving list of elements (" << status.getSize() - 1 << " elements) no longer needed by proc " << p << " TAG("<< Tag::genTag(p, 0, 0) <<")"); comm.receive(list.storage(), list.getSize(), p, Tag::genTag(p, 0, 0)); if(list.getSize() == 1 && list(0) == 0) continue; list.erase(list.getSize() - 1); Array new_send; for (UInt ns = 0; ns < list.getSize(); ++ns) { new_send.push_back(send(list(ns))); } AKANTU_DEBUG_INFO("I had " << send.getSize() << " elements to send to proc " << p << " and " << list.getSize() << " elements to keep. I have " << new_send.getSize() << " elements left."); send.copy(new_send); } comm.waitAll(isend_requests); comm.freeCommunicationRequest(isend_requests); delete [] list_of_el; AKANTU_DEBUG_OUT(); } // void DistributedSynchronizer::checkCommunicationScheme() { // for (UInt p = 0; p < psize; ++p) { // if (p == prank) continue; // for(UInt e(0), e < recv_element.getSize()) // } // } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::buildPrankToElement(ByElementTypeUInt & prank_to_element) { AKANTU_DEBUG_IN(); - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); - UInt psize = comm.getNbProc(); - UInt prank = comm.whoAmI(); - UInt spatial_dimension = mesh.getSpatialDimension(); mesh.initByElementTypeArray(prank_to_element, 1, spatial_dimension, false, _ek_not_defined, true); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_not_defined); Mesh::type_iterator end = mesh.lastType(spatial_dimension, _not_ghost, _ek_not_defined); /// assign prank to all not ghost elements for (; it != end; ++it) { UInt nb_element = mesh.getNbElement(*it); Array & prank_to_el = prank_to_element(*it); for (UInt el = 0; el < nb_element; ++el) { - prank_to_el(el) = prank; + prank_to_el(el) = rank; } } /// assign prank to all ghost elements - for (UInt p = 0; p < psize; ++p) { + for (UInt p = 0; p < nb_proc; ++p) { UInt nb_ghost_element = recv_element[p].getSize(); for (UInt el = 0; el < nb_ghost_element; ++el) { UInt element = recv_element[p](el).element; ElementType type = recv_element[p](el).type; GhostType ghost_type = recv_element[p](el).ghost_type; Array & prank_to_el = prank_to_element(type, ghost_type); prank_to_el(element) = p; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void DistributedSynchronizer::filterElementsByKind(DistributedSynchronizer * new_synchronizer, ElementKind kind) { AKANTU_DEBUG_IN(); Array * newsy_send_element = new_synchronizer->send_element; Array * newsy_recv_element = new_synchronizer->recv_element; Array * new_send_element = new Array[nb_proc]; Array * new_recv_element = new Array[nb_proc]; - StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); - UInt nb_proc = comm.getNbProc(); - for (UInt p = 0; p < nb_proc; ++p) { /// send element copying part new_send_element[p].resize(0); for (UInt el = 0; el < send_element[p].getSize(); ++el) { Element & element = send_element[p](el); if (element.kind == kind) newsy_send_element[p].push_back(element); else new_send_element[p].push_back(element); } /// recv element copying part new_recv_element[p].resize(0); for (UInt el = 0; el < recv_element[p].getSize(); ++el) { Element & element = recv_element[p](el); if (element.kind == kind) newsy_recv_element[p].push_back(element); else new_recv_element[p].push_back(element); } } /// deleting and reassigning old pointers delete [] send_element; delete [] recv_element; send_element = new_send_element; recv_element = new_recv_element; AKANTU_DEBUG_OUT(); } +/* -------------------------------------------------------------------------- */ +void DistributedSynchronizer::reset() { + AKANTU_DEBUG_IN(); + + for (UInt p = 0; p < nb_proc; ++p) { + send_element[p].resize(0); + recv_element[p].resize(0); + } + + AKANTU_DEBUG_OUT(); +} + + __END_AKANTU__ diff --git a/src/synchronizer/distributed_synchronizer.hh b/src/synchronizer/distributed_synchronizer.hh index 2289d188e..94cec1ef8 100644 --- a/src/synchronizer/distributed_synchronizer.hh +++ b/src/synchronizer/distributed_synchronizer.hh @@ -1,222 +1,225 @@ /** * @file distributed_synchronizer.hh * * @author Guillaume Anciaux * @author Nicolas Richart * * @date Thu Jun 16 16:36:52 2011 * * @brief wrapper to the static communicator * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_DISTRIBUTED_SYNCHRONIZER_HH__ #define __AKANTU_DISTRIBUTED_SYNCHRONIZER_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_vector.hh" #include "static_communicator.hh" #include "synchronizer.hh" #include "mesh.hh" #include "mesh_partition.hh" #include "communication_buffer.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class DistributedSynchronizer : public Synchronizer, public MeshEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: DistributedSynchronizer(Mesh & mesh, SynchronizerID id = "distributed_synchronizer", MemoryID memory_id = 0); public: virtual ~DistributedSynchronizer(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// get a mesh and a partition and create the local mesh and the associated /// DistributedSynchronizer static DistributedSynchronizer * createDistributedSynchronizerMesh(Mesh & mesh, const MeshPartition * partition, UInt root = 0, SynchronizerID id = "distributed_synchronizer", MemoryID memory_id = 0); /* ------------------------------------------------------------------------ */ /* Inherited from Synchronizer */ /* ------------------------------------------------------------------------ */ /// asynchronous synchronization of ghosts void asynchronousSynchronize(DataAccessor & data_accessor,SynchronizationTag tag); /// wait end of asynchronous synchronization of ghosts void waitEndSynchronize(DataAccessor & data_accessor,SynchronizationTag tag); /// build processor to element corrispondance void buildPrankToElement(ByElementTypeUInt & prank_to_element); virtual void printself(std::ostream & stream, int indent = 0) const; /// mesh event handler onRemovedElement virtual void onElementsRemoved(const Array & element_list, const ByElementTypeUInt & new_numbering, const RemovedElementsEvent & event); /// filter elements of a certain kind and copy them into a new synchronizer void filterElementsByKind(DistributedSynchronizer * new_synchronizer, ElementKind kind); + /// reset send and recv element lists + void reset(); + protected: /// fill the nodes type vector void fillNodesType(Mesh & mesh); void fillNodesType(const MeshData & mesh_data, DynamicCommunicationBuffer * buffers, const std::string & tag_name, const ElementType & el_type, const Array & partition_num); template void fillTagBufferTemplated(const MeshData & mesh_data, DynamicCommunicationBuffer * buffers, const std::string & tag_name, const ElementType & el_type, const Array & partition_num, const CSR & ghost_partition); void fillTagBuffer(const MeshData & mesh_data, DynamicCommunicationBuffer * buffers, const std::string & tag_name, const ElementType & el_type, const Array & partition_num, const CSR & ghost_partition); template void populateMeshDataTemplated(MeshData & mesh_data, BufferType & buffer, const std::string & tag_name, const ElementType & el_type, UInt nb_component, UInt nb_local_element, UInt nb_ghost_element); template void populateMeshData(MeshData & mesh_data, BufferType & buffer, const std::string & tag_name, const ElementType & el_type, const MeshDataTypeCode & type_code, UInt nb_component, UInt nb_local_element, UInt nb_ghost_element); /// fill the communications array of a distributedSynchronizer based on a partition array void fillCommunicationScheme(const UInt * partition, UInt nb_local_element, UInt nb_ghost_element, ElementType type); /// compute buffer size for a given tag and data accessor void computeBufferSize(DataAccessor & data_accessor, SynchronizationTag tag); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: enum CommTags { TAG_SIZES = 0, TAG_CONNECTIVITY = 1, TAG_DATA = 2, TAG_PARTITIONS = 3, TAG_NB_NODES = 4, TAG_NODES = 5, TAG_COORDINATES = 6, TAG_NODES_TYPE = 7, TAG_MESH_DATA = 8 }; protected: /// reference to the underlying mesh Mesh & mesh; /// the static memory instance StaticCommunicator * static_communicator; class Communication { public: void resize(UInt size) { send_buffer.resize(size); recv_buffer.resize(size); size_to_send .resize(size); size_to_receive.resize(size); } public: /// size of data to send to each processor std::vector size_to_send; /// size of data to recv to each processor std::vector size_to_receive; std::vector< CommunicationBuffer > send_buffer; std::vector< CommunicationBuffer > recv_buffer; std::vector send_requests; std::vector recv_requests; }; std::map communications; /// list of element to send to proc p Array * send_element; /// list of element to receive from proc p Array * recv_element; UInt nb_proc; UInt rank; friend class FilteredSynchronizer; friend class FacetSynchronizer; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "distributed_synchronizer_tmpl.hh" __END_AKANTU__ #endif /* __AKANTU_DISTRIBUTED_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/facet_stress_synchronizer.cc b/src/synchronizer/facet_stress_synchronizer.cc index a35af7ca2..78050fc15 100644 --- a/src/synchronizer/facet_stress_synchronizer.cc +++ b/src/synchronizer/facet_stress_synchronizer.cc @@ -1,139 +1,139 @@ /** * @file facet_stress_synchronizer.cc * @author Marco Vocialta * @date Mon Aug 26 10:19:47 2013 * * @brief Stress check on facets synchronizer * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "facet_stress_synchronizer.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ FacetStressSynchronizer::FacetStressSynchronizer(Mesh & mesh_facets, SynchronizerID id, MemoryID memory_id) : DistributedSynchronizer(mesh_facets, id, memory_id) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ FacetStressSynchronizer * FacetStressSynchronizer:: createFacetStressSynchronizer(FacetSynchronizer & facet_synchronizer, Mesh & mesh_facets, SynchronizerID id, MemoryID memory_id) { AKANTU_DEBUG_IN(); FacetStressSynchronizer & fs_synchronizer = *(new FacetStressSynchronizer(mesh_facets, id, memory_id)); for (UInt p = 0; p < fs_synchronizer.nb_proc; ++p) { fs_synchronizer.send_element[p].copy(facet_synchronizer.recv_element[p]); fs_synchronizer.recv_element[p].copy(facet_synchronizer.send_element[p]); } AKANTU_DEBUG_OUT(); return &fs_synchronizer; } /* -------------------------------------------------------------------------- */ -void FacetStressSynchronizer::updateFacetStressSynchronizer(const ByElementTypeArray & facets_check, +void FacetStressSynchronizer::updateFacetStressSynchronizer(const CohesiveElementInserter & inserter, const ByElementTypeUInt & rank_to_element, DataAccessor & data_accessor) { AKANTU_DEBUG_IN(); - updateElementList(send_element, facets_check, rank_to_element); - updateElementList(recv_element, facets_check, rank_to_element); + updateElementList(send_element, inserter, rank_to_element); + updateElementList(recv_element, inserter, rank_to_element); std::map::iterator it = communications.begin(); std::map::iterator end = communications.end(); for (; it != end; ++it) { SynchronizationTag tag = it->first; computeBufferSize(data_accessor, tag); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FacetStressSynchronizer::updateElementList(Array * elements, - const ByElementTypeArray & facets_check, + const CohesiveElementInserter & inserter, const ByElementTypeUInt & rank_to_element) { AKANTU_DEBUG_IN(); for (UInt p = 0; p < nb_proc; ++p) { ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; const Array * f_check = NULL; const Array< std::vector > * element_to_facet = NULL; UInt nb_element = 0; Array::iterator it_new = elements[p].begin(); Array::iterator it = elements[p].begin(); Array::iterator end = elements[p].end(); for (; it != end; ++it) { const Element & el = *it; if(el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; element_to_facet = & mesh.getElementToSubelement(el.type, el.ghost_type); - f_check = & facets_check(el.type, el.ghost_type); + f_check = & inserter.getCheckFacets(el.type, el.ghost_type); } if ( (*f_check)(el.element) ) { const Element & el_0 = (*element_to_facet)(el.element)[0]; const Array & rank_el_0 = rank_to_element(el_0.type, el_0.ghost_type); const Element & el_1 = (*element_to_facet)(el.element)[1]; const Array & rank_el_1 = rank_to_element(el_1.type, el_1.ghost_type); if ( (rank_el_0(el_0.element) == rank && rank_el_1(el_1.element) == p) || (rank_el_0(el_0.element) == p && rank_el_1(el_1.element) == rank) ) { *it_new = el; ++it_new; ++nb_element; } } } elements[p].resize(nb_element); } AKANTU_DEBUG_OUT(); } __END_AKANTU__ diff --git a/src/synchronizer/facet_stress_synchronizer.hh b/src/synchronizer/facet_stress_synchronizer.hh index bb87a1284..9a3d8d2a7 100644 --- a/src/synchronizer/facet_stress_synchronizer.hh +++ b/src/synchronizer/facet_stress_synchronizer.hh @@ -1,94 +1,95 @@ /** * @file facet_stress_synchronizer.hh * @author Marco Vocialta * @date Mon Aug 26 10:03:41 2013 * * @brief Stress check on facets synchronizer * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_FACET_STRESS_SYNCHRONIZER_HH__ #define __AKANTU_FACET_STRESS_SYNCHRONIZER_HH__ #include "distributed_synchronizer.hh" #include "facet_synchronizer.hh" +#include "cohesive_element_inserter.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class FacetStressSynchronizer : public DistributedSynchronizer { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ protected: FacetStressSynchronizer(Mesh & mesh_facets, SynchronizerID id = "facet_stress_synchronizer", MemoryID memory_id = 0); // virtual ~FacetStressSynchronizer(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: static FacetStressSynchronizer * createFacetStressSynchronizer(FacetSynchronizer & facet_synchronizer, Mesh & mesh_facets, SynchronizerID id = "facet_stress_synchronizer", MemoryID memory_id = 0); - void updateFacetStressSynchronizer(const ByElementTypeArray & facets_check, + void updateFacetStressSynchronizer(const CohesiveElementInserter & inserter, const ByElementTypeUInt & rank_to_element, DataAccessor & data_accessor); protected: void updateElementList(Array * elements, - const ByElementTypeArray & facets_check, + const CohesiveElementInserter & inserter, const ByElementTypeUInt & rank_to_element); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ // #include "facet_stress_synchronizer_inline_impl.cc" __END_AKANTU__ #endif /* __AKANTU_FACET_STRESS_SYNCHRONIZER_HH__ */ diff --git a/src/synchronizer/facet_synchronizer.cc b/src/synchronizer/facet_synchronizer.cc index 1a1b798a2..3167dbd7d 100644 --- a/src/synchronizer/facet_synchronizer.cc +++ b/src/synchronizer/facet_synchronizer.cc @@ -1,473 +1,479 @@ /** * @file facet_synchronizer.cc * @author Marco Vocialta * @date Tue Mar 26 09:55:38 2013 * * @brief Facet synchronizer for parallel simulations with cohesive elments * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "facet_synchronizer.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ /* -------------------------------------------------------------------------- */ FacetSynchronizer::FacetSynchronizer(Mesh & mesh, SynchronizerID id, MemoryID memory_id) : DistributedSynchronizer(mesh, id, memory_id) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ FacetSynchronizer * FacetSynchronizer:: createFacetSynchronizer(DistributedSynchronizer & distributed_synchronizer, Mesh & mesh, SynchronizerID id, MemoryID memory_id) { AKANTU_DEBUG_IN(); FacetSynchronizer & f_synchronizer = *(new FacetSynchronizer(mesh, id, memory_id)); f_synchronizer.setupFacetSynchronization(distributed_synchronizer); AKANTU_DEBUG_OUT(); return &f_synchronizer; } /* -------------------------------------------------------------------------- */ void FacetSynchronizer::updateDistributedSynchronizer(DistributedSynchronizer & distributed_synchronizer, DataAccessor & data_accessor, - const ByElementTypeUInt & cohesive_el_to_facet) { + const Mesh & mesh_cohesive) { AKANTU_DEBUG_IN(); Array * distrib_send_element = distributed_synchronizer.send_element; Array * distrib_recv_element = distributed_synchronizer.recv_element; - updateElementList(distrib_send_element, send_element, cohesive_el_to_facet); - updateElementList(distrib_recv_element, recv_element, cohesive_el_to_facet); + updateElementList(distrib_send_element, send_element, mesh_cohesive); + updateElementList(distrib_recv_element, recv_element, mesh_cohesive); std::map::iterator it = distributed_synchronizer.communications.begin(); std::map::iterator end = distributed_synchronizer.communications.end(); for (; it != end; ++it) { SynchronizationTag tag = it->first; distributed_synchronizer.computeBufferSize(data_accessor, tag); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FacetSynchronizer::updateElementList(Array * elements, const Array * facets, - const ByElementTypeUInt & cohesive_el_to_facet) { + const Mesh & mesh_cohesive) { AKANTU_DEBUG_IN(); ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; - ElementType current_coh_element_type = _not_defined; - - UInt max_uint = std::numeric_limits::max(); - const Array * cohesive_el_to_f = NULL; - - Element cohesive_element(_not_defined, 0, _not_ghost, _ek_cohesive); + UInt old_nb_cohesive_elements = 0; + const Array< std::vector > * element_to_facet = NULL; for (UInt p = 0; p < nb_proc; ++p) { const Array & fa = facets[p]; Array & el = elements[p]; Array::const_iterator it = fa.begin(); Array::const_iterator end = fa.end(); for (; it != end; ++it) { const Element & facet = *it; if(facet.type != current_element_type || facet.ghost_type != current_ghost_type) { current_element_type = facet.type; - current_coh_element_type = FEM::getCohesiveElementType(current_element_type); current_ghost_type = facet.ghost_type; - cohesive_el_to_f = &(cohesive_el_to_facet(current_element_type, - current_ghost_type)); - cohesive_element.type = current_coh_element_type; - cohesive_element.ghost_type = current_ghost_type; + + ElementType current_coh_element_type + = FEM::getCohesiveElementType(current_element_type); + + /// compute old number of cohesive elements + old_nb_cohesive_elements = mesh_cohesive.getNbElement(current_coh_element_type, + current_ghost_type); + old_nb_cohesive_elements -= mesh.getData("facet_to_double", + current_element_type, + current_ghost_type).getSize(); + + element_to_facet = & mesh.getData >("element_to_subelement", + current_element_type, + current_ghost_type); } - cohesive_element.element = (*cohesive_el_to_f)(facet.element); + const Element & cohesive_element = (*element_to_facet)(facet.element)[1]; - if (cohesive_element.element != max_uint) + if (cohesive_element.kind == _ek_cohesive && + cohesive_element.element >= old_nb_cohesive_elements) el.push_back(cohesive_element); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FacetSynchronizer::setupFacetSynchronization(DistributedSynchronizer & distributed_synchronizer) { AKANTU_DEBUG_IN(); Array * distrib_send_element = distributed_synchronizer.send_element; Array * distrib_recv_element = distributed_synchronizer.recv_element; /// build rank to facet correspondance ByElementTypeUInt rank_to_facet("rank_to_facet", id); initRankToFacet(rank_to_facet); buildRankToFacet(rank_to_facet, distrib_recv_element); /// generate temp_send/recv element arrays with their connectivity Array temp_send_element(nb_proc); Array temp_recv_element(nb_proc); Array send_connectivity(nb_proc); Array recv_connectivity(nb_proc); UInt spatial_dimension = mesh.getSpatialDimension(); for (UInt p = 0; p < nb_proc; ++p) { std::stringstream sstr; sstr << p; temp_send_element(p) = new ByElementTypeUInt("temp_send_element_proc_"+sstr.str(), id); mesh.initByElementTypeArray(*temp_send_element(p), 1, spatial_dimension - 1); temp_recv_element(p) = new ByElementTypeUInt("temp_recv_element_proc_"+sstr.str(), id); mesh.initByElementTypeArray(*temp_recv_element(p), 1, spatial_dimension - 1); send_connectivity(p) = new ByElementTypeUInt("send_connectivity_proc_"+sstr.str(), id); recv_connectivity(p) = new ByElementTypeUInt("recv_connectivity_proc_"+sstr.str(), id); } initGlobalConnectivity(send_connectivity); initGlobalConnectivity(recv_connectivity); /// build global connectivity arrays getFacetGlobalConnectivity<_not_ghost>(distributed_synchronizer, rank_to_facet, distrib_send_element, send_connectivity, temp_send_element); getFacetGlobalConnectivity<_ghost>(distributed_synchronizer, rank_to_facet, distrib_recv_element, recv_connectivity, temp_recv_element); /// build send/recv facet arrays buildSendElementList(send_connectivity, recv_connectivity, temp_send_element); buildRecvElementList(temp_recv_element); #ifndef AKANTU_NDEBUG /// count recv facets for each processor Array nb_facets_recv(nb_proc); nb_facets_recv.clear(); Mesh::type_iterator first = mesh.firstType(spatial_dimension - 1, _ghost); Mesh::type_iterator last = mesh.lastType(spatial_dimension - 1, _ghost); for (; first != last; ++first) { const Array & r_to_f = rank_to_facet(*first, _ghost); UInt nb_facet = r_to_f.getSize(); for (UInt f = 0; f < nb_facet; ++f) { UInt proc = r_to_f(f); if (proc != rank) ++nb_facets_recv(proc); } } for (UInt p = 0; p < nb_proc; ++p) { AKANTU_DEBUG_ASSERT(nb_facets_recv(p) == recv_element[p].getSize(), "Wrong number of recv facets"); } #endif for (UInt p = 0; p < nb_proc; ++p) { delete temp_send_element(p); delete temp_recv_element(p); delete send_connectivity(p); delete recv_connectivity(p); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FacetSynchronizer::buildSendElementList(const Array & send_connectivity, const Array & recv_connectivity, const Array & temp_send_element) { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt spatial_dimension = mesh.getSpatialDimension(); GhostType ghost_type = _ghost; Mesh::type_iterator first = mesh.firstType(spatial_dimension - 1, ghost_type); Mesh::type_iterator last = mesh.lastType(spatial_dimension - 1, ghost_type); /// do every communication by element type for (; first != last; ++first) { ElementType facet_type = *first; std::vector send_requests; UInt * send_size = new UInt[nb_proc]; /// send asynchronous data for (UInt p = 0; p < nb_proc; ++p) { if (p == rank) continue; const Array & recv_conn = (*recv_connectivity(p))(facet_type, _ghost); send_size[p] = recv_conn.getSize(); /// send connectivity size send_requests.push_back(comm.asyncSend(send_size + p, 1, p, Tag::genTag(rank, p, 0))); /// send connectivity data send_requests.push_back(comm.asyncSend(recv_conn.storage(), recv_conn.getSize() * recv_conn.getNbComponent(), p, Tag::genTag(rank, p, 1))); } UInt * recv_size = new UInt[nb_proc]; UInt nb_nodes_per_facet = Mesh::getNbNodesPerElement(facet_type); /// receive data for (UInt p = 0; p < nb_proc; ++p) { if (p == rank) continue; /// receive connectivity size comm.receive(recv_size + p, 1, p, Tag::genTag(p, rank, 0)); Array conn_to_match(recv_size[p], nb_nodes_per_facet); /// receive connectivity comm.receive(conn_to_match.storage(), conn_to_match.getSize() * conn_to_match.getNbComponent(), p, Tag::genTag(p, rank, 1)); const Array & send_conn = (*send_connectivity(p))(facet_type, _not_ghost); const Array & list = (*temp_send_element(p))(facet_type, _not_ghost); UInt nb_local_facets = send_conn.getSize(); AKANTU_DEBUG_ASSERT(nb_local_facets == list.getSize(), "connectivity and facet list have different sizes"); Array checked(nb_local_facets); checked.clear(); Element facet(facet_type, 0, _not_ghost, _ek_regular); Array::iterator > c_to_match_it = conn_to_match.begin(nb_nodes_per_facet); Array::iterator > c_to_match_end = conn_to_match.end(nb_nodes_per_facet); /// for every sent facet of other processors, find the /// corresponding one in the local send connectivity data in /// order to build the send_element arrays for (; c_to_match_it != c_to_match_end; ++c_to_match_it) { Array::const_iterator > c_local_it = send_conn.begin(nb_nodes_per_facet); Array::const_iterator > c_local_end = send_conn.end(nb_nodes_per_facet); for (UInt f = 0; f < nb_local_facets; ++f, ++c_local_it) { if (checked(f)) continue; if ( (*c_to_match_it) == (*c_local_it) ) { checked(f) = true; facet.element = list(f); send_element[p].push_back(facet); break; } } AKANTU_DEBUG_ASSERT(c_local_it != c_local_end, "facet not found"); } } /// wait for all communications to be done and free the /// communication request array comm.waitAll(send_requests); comm.freeCommunicationRequest(send_requests); delete [] send_size; delete [] recv_size; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FacetSynchronizer::buildRecvElementList(const Array & temp_recv_element) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); for (UInt p = 0; p < nb_proc; ++p) { if (p == rank) continue; GhostType ghost_type = _ghost; Mesh::type_iterator first = mesh.firstType(spatial_dimension - 1, ghost_type); Mesh::type_iterator last = mesh.lastType(spatial_dimension - 1, ghost_type); for (; first != last; ++first) { ElementType facet_type = *first; const Array & list = (*temp_recv_element(p))(facet_type, ghost_type); UInt nb_local_facets = list.getSize(); Element facet(facet_type, 0, ghost_type, _ek_regular); for (UInt f = 0; f < nb_local_facets; ++f) { facet.element = list(f); recv_element[p].push_back(facet); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FacetSynchronizer::initGlobalConnectivity(Array & connectivity) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); for (UInt p = 0; p < nb_proc; ++p) { if (p == rank) continue; ByElementTypeUInt & global_conn = (*connectivity(p)); mesh.initByElementTypeArray(global_conn, 1, spatial_dimension - 1); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator first = mesh.firstType(spatial_dimension - 1, ghost_type); Mesh::type_iterator last = mesh.lastType(spatial_dimension - 1, ghost_type); for (; first != last; ++first) { ElementType type = *first; Array & g_conn = global_conn(type, ghost_type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); g_conn.extendComponentsInterlaced(nb_nodes_per_element, 1); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FacetSynchronizer::initRankToFacet(ByElementTypeUInt & rank_to_facet) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); mesh.initByElementTypeArray(rank_to_facet, 1, spatial_dimension - 1); GhostType ghost_type = _ghost; Mesh::type_iterator first = mesh.firstType(spatial_dimension - 1, ghost_type); Mesh::type_iterator last = mesh.lastType(spatial_dimension - 1, ghost_type); for (; first != last; ++first) { ElementType type = *first; UInt nb_facet = mesh.getNbElement(type, ghost_type); Array & rank_to_f = rank_to_facet(type, ghost_type); rank_to_f.resize(nb_facet); for (UInt f = 0; f < nb_facet; ++f) rank_to_f(f) = rank; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void FacetSynchronizer::buildRankToFacet(ByElementTypeUInt & rank_to_facet, const Array * elements) { AKANTU_DEBUG_IN(); for (UInt p = 0; p < nb_proc; ++p) { if (p == rank) continue; const Array & elem = elements[p]; UInt nb_element = elem.getSize(); for (UInt el = 0; el < nb_element; ++el) { ElementType type = elem(el).type; GhostType gt = elem(el).ghost_type; UInt el_index = elem(el).element; const Array & facet_to_element = mesh.getSubelementToElement(type, gt); UInt nb_facets_per_element = Mesh::getNbFacetsPerElement(type); ElementType facet_type = Mesh::getFacetType(type); for (UInt f = 0; f < nb_facets_per_element; ++f) { const Element & facet = facet_to_element(el_index, f); if (facet == ElementNull) continue; UInt facet_index = facet.element; GhostType facet_gt = facet.ghost_type; if (facet_gt == _not_ghost) continue; Array & t_to_f = rank_to_facet(facet_type, facet_gt); if ((p < t_to_f(facet_index)) || (t_to_f(facet_index) == rank)) t_to_f(facet_index) = p; } } } AKANTU_DEBUG_OUT(); } __END_AKANTU__ diff --git a/src/synchronizer/facet_synchronizer.hh b/src/synchronizer/facet_synchronizer.hh index d590037c0..45938b5e7 100644 --- a/src/synchronizer/facet_synchronizer.hh +++ b/src/synchronizer/facet_synchronizer.hh @@ -1,132 +1,132 @@ /** * @file facet_synchronizer.hh * @author Marco Vocialta * @date Tue Mar 26 09:49:44 2013 * * @brief Facet synchronizer for parallel simulations with cohesive elments * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_FACET_SYNCHRONIZER_HH__ #define __AKANTU_FACET_SYNCHRONIZER_HH__ #include "distributed_synchronizer.hh" #include "fem.hh" /* -------------------------------------------------------------------------- */ __BEGIN_AKANTU__ class FacetSynchronizer : public DistributedSynchronizer { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ protected: FacetSynchronizer(Mesh & mesh, SynchronizerID id = "facet_synchronizer", MemoryID memory_id = 0); // public: // virtual ~FacetSynchronizer() {}; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// get a distributed synchronizer and a facet mesh, and create the /// associated FacetSynchronizer static FacetSynchronizer * createFacetSynchronizer(DistributedSynchronizer & distributed_synchronizer, Mesh & mesh, SynchronizerID id = "facet_synchronizer", MemoryID memory_id = 0); /// update distributed synchronizer after elements' insertion void updateDistributedSynchronizer(DistributedSynchronizer & distributed_synchronizer, DataAccessor & data_accessor, - const ByElementTypeUInt & cohesive_el_to_facet); + const Mesh & mesh_cohesive); protected: /// update elements list based on facets list void updateElementList(Array * elements, const Array * facets, - const ByElementTypeUInt & cohesive_el_to_facet); + const Mesh & mesh_cohesive); /// setup facet synchronization void setupFacetSynchronization(DistributedSynchronizer & distributed_synchronizer); /// build send facet arrays void buildSendElementList(const Array & send_connectivity, const Array & recv_connectivity, const Array & temp_send_element); /// build recv facet arrays void buildRecvElementList(const Array & temp_recv_element); /// get facets' global connectivity for a list of elements template inline void getFacetGlobalConnectivity(const DistributedSynchronizer & distributed_synchronizer, const ByElementTypeUInt & rank_to_facet, const Array * elements, Array & connectivity, Array & facets); /// init connectivities of send/recv elements void initGlobalConnectivity(Array & connectivity); /// initialize ByElementType containing correspondance between /// facets and processors void initRankToFacet(ByElementTypeUInt & rank_to_facet); /// find which processor a facet is assigned to void buildRankToFacet(ByElementTypeUInt & rank_to_facet, const Array * elements); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: friend class FacetStressSynchronizer; }; /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "facet_synchronizer_inline_impl.cc" __END_AKANTU__ #endif /* __AKANTU_FACET_SYNCHRONIZER_HH__ */ diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_extrinsic/test_cohesive_extrinsic.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_extrinsic/test_cohesive_extrinsic.cc index d6b7fbeba..2f42a3549 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_extrinsic/test_cohesive_extrinsic.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_extrinsic/test_cohesive_extrinsic.cc @@ -1,194 +1,190 @@ /** * @file test_cohesive_extrinsic.cc * * @author Marco Vocialta * * @date Tue May 08 13:01:18 2012 * * @brief Test for cohesive elements * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_io_msh.hh" #include "mesh_utils.hh" #include "solid_mechanics_model_cohesive.hh" #include "material.hh" // #if defined(AKANTU_USE_IOHELPER) // # include "io_helper.hh" // #endif /* -------------------------------------------------------------------------- */ using namespace akantu; int main(int argc, char *argv[]) { initialize(argc, argv); debug::setDebugLevel(dblWarning); const UInt spatial_dimension = 2; const UInt max_steps = 1000; Mesh mesh(spatial_dimension); mesh.read("triangle.msh"); SolidMechanicsModelCohesive model(mesh); /// model initialization model.initFull("material.dat", SolidMechanicsModelCohesiveOptions(_explicit_lumped_mass, true)); Real time_step = model.getStableTimeStep()*0.05; model.setTimeStep(time_step); std::cout << "Time step: " << time_step << std::endl; model.assembleMassLumped(); /* ------------------------------------------------------------------------ */ /* Facet part */ /* ------------------------------------------------------------------------ */ - Array limits(spatial_dimension, 2); - limits(0, 0) = -100; - limits(0, 1) = 100; - limits(1, 0) = -0.30; - limits(1, 1) = -0.20; - - model.enableFacetsCheckOnArea(limits); + CohesiveElementInserter & inserter = model.getElementInserter(); + inserter.setLimit('y', -0.30, -0.20); + model.updateAutomaticInsertion(); /* ------------------------------------------------------------------------ */ /* End of facet part */ /* ------------------------------------------------------------------------ */ Array & position = mesh.getNodes(); Array & velocity = model.getVelocity(); Array & boundary = model.getBoundary(); Array & displacement = model.getDisplacement(); // const Array & residual = model.getResidual(); UInt nb_nodes = mesh.getNbNodes(); /// boundary conditions for (UInt n = 0; n < nb_nodes; ++n) { if (position(n, 1) > 0.99 || position(n, 1) < -0.99) boundary(n, 1) = true; if (position(n, 0) > 0.99 || position(n, 0) < -0.99) boundary(n, 0) = true; } /// initial conditions Real loading_rate = 0.5; Real disp_update = loading_rate * time_step; for (UInt n = 0; n < nb_nodes; ++n) { velocity(n, 1) = loading_rate * position(n, 1); } model.updateResidual(); model.setBaseName("extrinsic"); model.addDumpFieldVector("displacement"); model.addDumpField("velocity" ); model.addDumpField("acceleration"); model.addDumpField("residual" ); model.addDumpField("stress"); model.addDumpField("strain"); model.dump(); // std::ofstream edis("edis.txt"); // std::ofstream erev("erev.txt"); // Array & residual = model.getResidual(); // const Array & stress = model.getMaterial(0).getStress(type); /// Main loop for (UInt s = 1; s <= max_steps; ++s) { /// update displacement on extreme nodes for (UInt n = 0; n < mesh.getNbNodes(); ++n) { if (position(n, 1) > 0.99 || position(n, 1) < -0.99) displacement(n, 1) += disp_update * position(n, 1); } model.checkCohesiveStress(); model.explicitPred(); model.updateResidual(); model.updateAcceleration(); model.explicitCorr(); if(s % 1 == 0) { model.dump(); std::cout << "passing step " << s << "/" << max_steps << std::endl; } // Real Ed = dynamic_cast (model.getMaterial(1)).getDissipatedEnergy(); // Real Er = dynamic_cast (model.getMaterial(1)).getReversibleEnergy(); // edis << s << " " // << Ed << std::endl; // erev << s << " " // << Er << std::endl; } // edis.close(); // erev.close(); // mesh.write("mesh_final.msh"); Real Ed = model.getEnergy("dissipated"); Real Edt = 200 * std::sqrt(2); std::cout << Ed << " " << Edt << std::endl; if (Ed < Edt * 0.999 || Ed > Edt * 1.001 || std::isnan(Ed)) { std::cout << "The dissipated energy is incorrect" << std::endl; finalize(); return EXIT_FAILURE; } // for (UInt n = 0; n < position.getSize(); ++n) { // for (UInt s = 0; s < spatial_dimension; ++s) { // position(n, s) += displacement(n, s); // } // } finalize(); std::cout << "OK: test_cohesive_extrinsic was passed!" << std::endl; return EXIT_SUCCESS; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_extrinsic/test_cohesive_extrinsic_quadrangle.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_extrinsic/test_cohesive_extrinsic_quadrangle.cc index 90d8e6482..df353d28b 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_extrinsic/test_cohesive_extrinsic_quadrangle.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_extrinsic/test_cohesive_extrinsic_quadrangle.cc @@ -1,243 +1,223 @@ /** * @file test_cohesive_extrinsic_quadrangle.cc * * @author Marco Vocialta * * @date Wed Oct 03 10:20:53 2012 * * @brief Test for extrinsic cohesive elements and quadrangles * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_io_msh.hh" #include "mesh_utils.hh" #include "solid_mechanics_model_cohesive.hh" #include "material.hh" #if defined(AKANTU_USE_IOHELPER) # include "io_helper.hh" #endif /* -------------------------------------------------------------------------- */ using namespace akantu; int main(int argc, char *argv[]) { initialize(argc, argv); debug::setDebugLevel(dblWarning); const UInt spatial_dimension = 2; const UInt max_steps = 1000; - const ElementType type = _quadrangle_8; - Mesh mesh(spatial_dimension); mesh.read("quadrangle.msh"); SolidMechanicsModelCohesive model(mesh); /// model initialization model.initFull("material.dat", SolidMechanicsModelCohesiveOptions(_explicit_lumped_mass, true)); Real time_step = model.getStableTimeStep()*0.05; model.setTimeStep(time_step); // std::cout << "Time step: " << time_step << std::endl; model.assembleMassLumped(); /* ------------------------------------------------------------------------ */ /* Facet part */ /* ------------------------------------------------------------------------ */ - // std::cout << mesh << std::endl; - - const Mesh & mesh_facets = model.getMeshFacets(); - - const ElementType type_facet = mesh.getFacetType(type); - UInt nb_facet = mesh_facets.getNbElement(type_facet); - const Array & position = mesh.getNodes(); - // const Array & connectivity = mesh_facets.getConnectivity(type_facet); - - Array & facet_check = model.getFacetsCheck(type_facet); - - Real * bary_facet = new Real[spatial_dimension]; - for (UInt f = 0; f < nb_facet; ++f) { - mesh_facets.getBarycenter(f, type_facet, bary_facet); - if (bary_facet[1] < 0.05 && bary_facet[1] > -0.05) - facet_check(f) = true; - else - facet_check(f) = false; - } - delete[] bary_facet; - - // std::cout << mesh << std::endl; + CohesiveElementInserter & inserter = model.getElementInserter(); + inserter.setLimit('y', -0.05, 0.05); + model.updateAutomaticInsertion(); /* ------------------------------------------------------------------------ */ /* End of facet part */ /* ------------------------------------------------------------------------ */ + const Array & position = mesh.getNodes(); Array & velocity = model.getVelocity(); Array & boundary = model.getBoundary(); Array & displacement = model.getDisplacement(); // const Array & residual = model.getResidual(); UInt nb_nodes = mesh.getNbNodes(); /// boundary conditions for (UInt n = 0; n < nb_nodes; ++n) { if (position(n, 1) > 0.99 || position(n, 1) < -0.99) boundary(n, 1) = true; if (position(n, 0) > 0.99 || position(n, 0) < -0.99) boundary(n, 0) = true; } model.updateResidual(); // iohelper::ElemType paraview_type = iohelper::QUAD2; // UInt nb_element = mesh.getNbElement(type); // /// initialize the paraview output // iohelper::DumperParaview dumper; // dumper.SetMode(iohelper::TEXT); // dumper.SetPoints(mesh.getNodes().values, // spatial_dimension, mesh.getNbNodes(), "explicit"); // dumper.SetConnectivity((int *)mesh.getConnectivity(type).values, // paraview_type, nb_element, iohelper::C_MODE); // dumper.AddNodeDataField(model.getDisplacement().values, // spatial_dimension, "displacements"); // dumper.AddNodeDataField(model.getVelocity().values, // spatial_dimension, "velocity"); // dumper.AddNodeDataField(model.getAcceleration().values, // spatial_dimension, "acceleration"); // dumper.AddNodeDataField(model.getResidual().values, // spatial_dimension, "forces"); // dumper.AddElemDataField(model.getMaterial(0).getStrain(type).values, // spatial_dimension*spatial_dimension, "strain"); // dumper.AddElemDataField(model.getMaterial(0).getStress(type).values, // spatial_dimension*spatial_dimension, "stress"); // dumper.SetEmbeddedValue("displacements", 1); // dumper.SetEmbeddedValue("forces", 1); // dumper.SetPrefix("paraview/"); // dumper.Init(); // dumper.Dump(); /// initial conditions Real loading_rate = 0.2; Real disp_update = loading_rate * time_step; for (UInt n = 0; n < nb_nodes; ++n) { velocity(n, 1) = loading_rate * position(n, 1); } // std::ofstream edis("edis.txt"); // std::ofstream erev("erev.txt"); // Array & residual = model.getResidual(); // const Array & stress = model.getMaterial(0).getStress(type); /// Main loop for (UInt s = 1; s <= max_steps; ++s) { /// update displacement on extreme nodes for (UInt n = 0; n < nb_nodes; ++n) { if (position(n, 1) > 0.99 || position(n, 1) < -0.99) displacement(n, 1) += disp_update * position(n, 1); } model.checkCohesiveStress(); model.explicitPred(); model.updateResidual(); model.updateAcceleration(); model.explicitCorr(); if(s % 1 == 0) { // dumper.SetPoints(mesh.getNodes().values, // spatial_dimension, mesh.getNbNodes(), "explicit"); // dumper.SetConnectivity((int *)mesh.getConnectivity(type).values, // paraview_type, nb_element, iohelper::C_MODE); // dumper.AddNodeDataField(model.getDisplacement().values, // spatial_dimension, "displacements"); // dumper.AddNodeDataField(model.getVelocity().values, // spatial_dimension, "velocity"); // dumper.AddNodeDataField(model.getAcceleration().values, // spatial_dimension, "acceleration"); // dumper.AddNodeDataField(model.getResidual().values, // spatial_dimension, "forces"); // dumper.AddElemDataField(model.getMaterial(0).getStrain(type).values, // spatial_dimension*spatial_dimension, "strain"); // dumper.AddElemDataField(model.getMaterial(0).getStress(type).values, // spatial_dimension*spatial_dimension, "stress"); // dumper.SetEmbeddedValue("displacements", 1); // dumper.SetEmbeddedValue("forces", 1); // dumper.SetPrefix("paraview/"); // dumper.Init(); // dumper.Dump(); std::cout << "passing step " << s << "/" << max_steps << std::endl; } // Real Ed = dynamic_cast (model.getMaterial(1)).getDissipatedEnergy(); // Real Er = dynamic_cast (model.getMaterial(1)).getReversibleEnergy(); // edis << s << " " // << Ed << std::endl; // erev << s << " " // << Er << std::endl; } // edis.close(); // erev.close(); mesh.write("mesh_final.msh"); Real Ed = model.getEnergy("dissipated"); Real Edt = 200; std::cout << Ed << " " << Edt << std::endl; if (Ed < Edt * 0.99 || Ed > Edt * 1.01 || std::isnan(Ed)) { std::cout << "The dissipated energy is incorrect" << std::endl; return EXIT_FAILURE; } finalize(); std::cout << "OK: test_cohesive_extrinsic_quadrangle was passed!" << std::endl; return EXIT_SUCCESS; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic/test_cohesive_intrinsic.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic/test_cohesive_intrinsic.cc index 9060410f3..39626fdd9 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic/test_cohesive_intrinsic.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic/test_cohesive_intrinsic.cc @@ -1,209 +1,205 @@ /** * @file test_cohesive_intrinsic.cc * * @author Marco Vocialta * * @date Tue May 08 13:01:18 2012 * * @brief Test for cohesive elements * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_io_msh.hh" #include "mesh_utils.hh" #include "solid_mechanics_model_cohesive.hh" #include "material.hh" #include "dumper_paraview.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; static void updateDisplacement(SolidMechanicsModelCohesive &, Array &, ElementType, Real); int main(int argc, char *argv[]) { initialize(argc, argv); debug::setDebugLevel(dblWarning); const UInt spatial_dimension = 2; const UInt max_steps = 350; const ElementType type = _triangle_6; Mesh mesh(spatial_dimension); mesh.read("triangle.msh"); /* ------------------------------------------------------------------------ */ /* Facet part */ /* ------------------------------------------------------------------------ */ std::cout << mesh << std::endl; - Array limits(spatial_dimension, 2); - limits(0, 0) = -0.26; - limits(0, 1) = -0.24; - limits(1, 0) = -100; - limits(1, 1) = 100; - - MeshUtils::insertIntrinsicCohesiveElementsInArea(mesh, limits); + CohesiveElementInserter inserter(mesh); + inserter.setLimit('x', -0.26, -0.24); + inserter.insertIntrinsicElements(); mesh.write("mesh_cohesive.msh"); // std::cout << mesh << std::endl; /* ------------------------------------------------------------------------ */ /* End of facet part */ /* ------------------------------------------------------------------------ */ SolidMechanicsModelCohesive model(mesh); /// model initialization model.initFull("material.dat"); Real time_step = model.getStableTimeStep()*0.8; model.setTimeStep(time_step); // std::cout << "Time step: " << time_step << std::endl; model.assembleMassLumped(); Array & boundary = model.getBoundary(); // const Array & residual = model.getResidual(); UInt nb_nodes = mesh.getNbNodes(); UInt nb_element = mesh.getNbElement(type); /// boundary conditions for (UInt dim = 0; dim < spatial_dimension; ++dim) { for (UInt n = 0; n < nb_nodes; ++n) { boundary(n, dim) = true; } } model.updateResidual(); model.setBaseName("intrinsic"); model.addDumpFieldVector("displacement"); model.addDumpField("velocity" ); model.addDumpField("acceleration"); model.addDumpField("residual" ); model.addDumpField("stress"); model.addDumpField("strain"); model.addDumpField("force"); model.dump(); DumperParaview dumper("cohesive_elements_triangle"); dumper.registerMesh(mesh, spatial_dimension, _not_ghost, _ek_cohesive); DumperIOHelper::Field * cohesive_displacement = new DumperIOHelper::NodalField(model.getDisplacement()); cohesive_displacement->setPadding(3); dumper.registerField("displacement", cohesive_displacement); dumper.dump(); /// update displacement Array elements; Real * bary = new Real[spatial_dimension]; for (UInt el = 0; el < nb_element; ++el) { mesh.getBarycenter(el, type, bary); if (bary[0] > -0.25) elements.push_back(el); } delete[] bary; Real increment = 0.01; updateDisplacement(model, elements, type, increment); /// Main loop for (UInt s = 1; s <= max_steps; ++s) { model.explicitPred(); model.updateResidual(); model.updateAcceleration(); model.explicitCorr(); updateDisplacement(model, elements, type, increment); if(s % 1 == 0) { model.dump(); dumper.dump(); std::cout << "passing step " << s << "/" << max_steps << std::endl; } } Real Ed = model.getEnergy("dissipated"); Real Edt = 2 * sqrt(2); std::cout << Ed << " " << Edt << std::endl; if (Ed < Edt * 0.999 || Ed > Edt * 1.001 || std::isnan(Ed)) { std::cout << "The dissipated energy is incorrect" << std::endl; return EXIT_FAILURE; } finalize(); std::cout << "OK: test_cohesive_intrinsic was passed!" << std::endl; return EXIT_SUCCESS; } static void updateDisplacement(SolidMechanicsModelCohesive & model, Array & elements, ElementType type, Real increment) { Mesh & mesh = model.getFEM().getMesh(); UInt nb_element = elements.getSize(); UInt nb_nodes = mesh.getNbNodes(); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); const Array & connectivity = mesh.getConnectivity(type); Array & displacement = model.getDisplacement(); Array update(nb_nodes); update.clear(); for (UInt el = 0; el < nb_element; ++el) { for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = connectivity(elements(el), n); if (!update(node)) { displacement(node, 0) += increment; // displacement(node, 1) += increment; update(node) = true; } } } } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic/test_cohesive_intrinsic_quadrangle.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic/test_cohesive_intrinsic_quadrangle.cc index 934abacee..a004a5c4d 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic/test_cohesive_intrinsic_quadrangle.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic/test_cohesive_intrinsic_quadrangle.cc @@ -1,260 +1,239 @@ /** * @file test_cohesive_intrinsic_quadrangle.cc * * @author Marco Vocialta * * @date Wed Oct 03 10:20:53 2012 * * @brief Intrinsic cohesive elements' test for quadrangles * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" #include "mesh_utils.hh" #include "solid_mechanics_model_cohesive.hh" #include "material.hh" #include "dumper_paraview.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; static void updateDisplacement(SolidMechanicsModelCohesive &, Array &, ElementType, Real); int main(int argc, char *argv[]) { initialize(argc, argv); const UInt spatial_dimension = 2; const UInt max_steps = 350; const ElementType type = _quadrangle_4; Mesh mesh(spatial_dimension); mesh.read("quadrangle.msh"); /* ------------------------------------------------------------------------ */ /* Facet part */ /* ------------------------------------------------------------------------ */ - Mesh mesh_facets(spatial_dimension, mesh.getNodes(), "mesh_facets"); - MeshUtils::buildAllFacets(mesh, mesh_facets); - debug::setDebugLevel(dblDump); std::cout << mesh << std::endl; - std::cout << mesh_facets << std::endl; debug::setDebugLevel(dblWarning); - const ElementType type_facet = Mesh::getFacetType(type); - - UInt nb_facet = mesh_facets.getNbElement(type_facet); - // const Array & position = mesh.getNodes(); - // Array & displacement = model.getDisplacement(); - // const Array & connectivity = mesh_facets.getConnectivity(type_facet); - - Array facet_insertion(nb_facet); - facet_insertion.clear(); - Real * bary_facet = new Real[spatial_dimension]; - for (UInt f = 0; f < nb_facet; ++f) { - mesh_facets.getBarycenter(f, type_facet, bary_facet); - if (bary_facet[0] > -0.01 && bary_facet[0] < 0.01) facet_insertion(f) = true; - } - delete[] bary_facet; - - MeshUtils::insertIntrinsicCohesiveElements(mesh, - mesh_facets, - type_facet, - facet_insertion); + CohesiveElementInserter inserter(mesh); + inserter.setLimit('x', -0.01, 0.01); + inserter.insertIntrinsicElements(); mesh.write("mesh_cohesive_quadrangle.msh"); debug::setDebugLevel(dblDump); std::cout << mesh << std::endl; debug::setDebugLevel(dblWarning); /* ------------------------------------------------------------------------ */ /* End of facet part */ /* ------------------------------------------------------------------------ */ SolidMechanicsModelCohesive model(mesh); /// model initialization model.initFull("material.dat"); Real time_step = model.getStableTimeStep()*0.8; model.setTimeStep(time_step); // std::cout << "Time step: " << time_step << std::endl; model.assembleMassLumped(); Array & boundary = model.getBoundary(); // const Array & residual = model.getResidual(); UInt nb_nodes = mesh.getNbNodes(); UInt nb_element = mesh.getNbElement(type); /// boundary conditions for (UInt dim = 0; dim < spatial_dimension; ++dim) { for (UInt n = 0; n < nb_nodes; ++n) { boundary(n, dim) = true; } } model.updateResidual(); model.setBaseName("intrinsic_quadrangle"); model.addDumpFieldVector("displacement"); model.addDumpField("velocity" ); model.addDumpField("acceleration"); model.addDumpField("residual" ); model.addDumpField("stress"); model.addDumpField("strain"); model.addDumpField("force"); model.dump(); DumperParaview dumper("cohesive_elements_quadrangle"); dumper.registerMesh(mesh, spatial_dimension, _not_ghost, _ek_cohesive); DumperIOHelper::Field * cohesive_displacement = new DumperIOHelper::NodalField(model.getDisplacement()); cohesive_displacement->setPadding(3); dumper.registerField("displacement", cohesive_displacement); dumper.dump(); /// update displacement Array elements; Real * bary = new Real[spatial_dimension]; for (UInt el = 0; el < nb_element; ++el) { mesh.getBarycenter(el, type, bary); if (bary[0] > 0.) elements.push_back(el); } delete[] bary; Real increment = 0.01; updateDisplacement(model, elements, type, increment); // for (UInt n = 0; n < nb_nodes; ++n) { // if (position(n, 1) + displacement(n, 1) > 0) { // if (position(n, 0) == 0) { // displacement(n, 1) -= 0.25; // } // if (position(n, 0) == 1) { // displacement(n, 1) += 0.25; // } // } // } // std::ofstream edis("edis.txt"); // std::ofstream erev("erev.txt"); /// Main loop for (UInt s = 1; s <= max_steps; ++s) { model.explicitPred(); model.updateResidual(); model.updateAcceleration(); model.explicitCorr(); updateDisplacement(model, elements, type, increment); if(s % 1 == 0) { model.dump(); dumper.dump(); std::cout << "passing step " << s << "/" << max_steps << std::endl; } // // update displacement // for (UInt n = 0; n < nb_nodes; ++n) { // if (position(n, 1) + displacement(n, 1) > 0) { // displacement(n, 0) -= 0.01; // } // } // Real Ed = dynamic_cast (model.getMaterial(1)).getDissipatedEnergy(); // Real Er = dynamic_cast (model.getMaterial(1)).getReversibleEnergy(); // edis << s << " " // << Ed << std::endl; // erev << s << " " // << Er << std::endl; } // edis.close(); // erev.close(); Real Ed = model.getEnergy("dissipated"); Real Edt = 1; std::cout << Ed << " " << Edt << std::endl; if (Ed < Edt * 0.999 || Ed > Edt * 1.001) { std::cout << "The dissipated energy is incorrect" << std::endl; return EXIT_FAILURE; } finalize(); std::cout << "OK: test_cohesive_intrinsic_quadrangle was passed!" << std::endl; return EXIT_SUCCESS; } static void updateDisplacement(SolidMechanicsModelCohesive & model, Array & elements, ElementType type, Real increment) { Mesh & mesh = model.getFEM().getMesh(); UInt nb_element = elements.getSize(); UInt nb_nodes = mesh.getNbNodes(); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); const Array & connectivity = mesh.getConnectivity(type); Array & displacement = model.getDisplacement(); Array update(nb_nodes); update.clear(); for (UInt el = 0; el < nb_element; ++el) { for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = connectivity(elements(el), n); if (!update(node)) { displacement(node, 0) += increment; // displacement(node, 1) += increment; update(node) = true; } } } } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic/test_cohesive_intrinsic_tetrahedron.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic/test_cohesive_intrinsic_tetrahedron.cc index c023d6530..360aafe1f 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic/test_cohesive_intrinsic_tetrahedron.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic/test_cohesive_intrinsic_tetrahedron.cc @@ -1,473 +1,469 @@ /** * @file test_cohesive_intrinsic_tetrahedron.cc * * @author Marco Vocialta * * @date Tue Aug 20 14:37:18 2013 * * @brief Test for cohesive elements * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_io_msh.hh" #include "mesh_utils.hh" #include "solid_mechanics_model_cohesive.hh" #include "material.hh" #include "material_cohesive.hh" #include "dumper_paraview.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; void updateDisplacement(SolidMechanicsModelCohesive &, Array &, ElementType, Vector &); bool checkTractions(SolidMechanicsModelCohesive & model, ElementType type, Vector & opening, Vector & theoretical_traction, Matrix & rotation); void findNodesToCheck(const Mesh & mesh, const Array & elements, ElementType type, Array & nodes_to_check); bool checkEquilibrium(const Array & residual); bool checkResidual(const Array & residual, const Vector & traction, const Array & nodes_to_check, const Matrix & rotation); int main(int argc, char *argv[]) { initialize(argc, argv); // debug::setDebugLevel(dblDump); const UInt spatial_dimension = 3; const UInt max_steps = 60; const Real increment_constant = 0.01; const ElementType type = _tetrahedron_10; Mesh mesh(spatial_dimension); mesh.read("tetrahedron.msh"); /* ------------------------------------------------------------------------ */ /* Facet part */ /* ------------------------------------------------------------------------ */ + CohesiveElementInserter inserter(mesh); + Array limits(spatial_dimension, 2); - limits(0, 0) = -0.01; - limits(0, 1) = 0.01; - limits(1, 0) = -100; - limits(1, 1) = 100; - limits(2, 0) = -100; - limits(2, 1) = 100; - - MeshUtils::insertIntrinsicCohesiveElementsInArea(mesh, limits); + inserter.setLimit('x', -0.01, 0.01); + inserter.insertIntrinsicElements(); // std::cout << mesh << std::endl; /* ------------------------------------------------------------------------ */ /* End of facet part */ /* ------------------------------------------------------------------------ */ SolidMechanicsModelCohesive model(mesh); /// model initialization model.initFull("material_tetrahedron.dat"); Array & boundary = model.getBoundary(); boundary.set(true); UInt nb_element = mesh.getNbElement(type); model.updateResidual(); model.setBaseName("intrinsic_tetrahedron"); model.addDumpFieldVector("displacement"); model.addDumpField("residual" ); model.dump(); DumperParaview dumper("cohesive_elements_tetrahedron"); dumper.registerMesh(mesh, spatial_dimension, _not_ghost, _ek_cohesive); DumperIOHelper::Field * cohesive_displacement = new DumperIOHelper::NodalField(model.getDisplacement()); cohesive_displacement->setPadding(3); dumper.registerField("displacement", cohesive_displacement); // dumper.registerField("damage", new DumperIOHelper:: // HomogenizedField(model, // "damage", // spatial_dimension, // _not_ghost, // _ek_cohesive)); dumper.dump(); /// find elements to displace Array elements; Real * bary = new Real[spatial_dimension]; for (UInt el = 0; el < nb_element; ++el) { mesh.getBarycenter(el, type, bary); if (bary[0] > 0.01) elements.push_back(el); } delete[] bary; /// find nodes to check Array nodes_to_check; findNodesToCheck(mesh, elements, type, nodes_to_check); /// rotate mesh Real angle = 1.; Matrix rotation(spatial_dimension, spatial_dimension); rotation.clear(); rotation(0, 0) = std::cos(angle); rotation(0, 1) = std::sin(angle) * -1.; rotation(1, 0) = std::sin(angle); rotation(1, 1) = std::cos(angle); rotation(2, 2) = 1.; Vector increment_tmp(spatial_dimension); for (UInt dim = 0; dim < spatial_dimension; ++dim) { increment_tmp(dim) = (dim + 1) * increment_constant; } Vector increment(spatial_dimension); increment.mul(rotation, increment_tmp); Array & position = mesh.getNodes(); Array position_tmp(position); Array::iterator > position_it = position.begin(spatial_dimension); Array::iterator > position_end = position.end(spatial_dimension); Array::iterator > position_tmp_it = position_tmp.begin(spatial_dimension); for (; position_it != position_end; ++position_it, ++position_tmp_it) position_it->mul(rotation, *position_tmp_it); model.dump(); dumper.dump(); updateDisplacement(model, elements, type, increment); Real theoretical_Ed = 0; Vector opening(spatial_dimension); Vector traction(spatial_dimension); Vector opening_old(spatial_dimension); Vector traction_old(spatial_dimension); opening.clear(); traction.clear(); opening_old.clear(); traction_old.clear(); Vector Dt(spatial_dimension); Vector Do(spatial_dimension); const Array & residual = model.getResidual(); /// Main loop for (UInt s = 1; s <= max_steps; ++s) { model.updateResidual(); opening += increment_tmp; if (checkTractions(model, type, opening, traction, rotation) || checkEquilibrium(residual) || checkResidual(residual, traction, nodes_to_check, rotation)) { finalize(); return EXIT_FAILURE; } /// compute energy Do = opening; Do -= opening_old; Dt = traction_old; Dt += traction; theoretical_Ed += .5 * Do.dot(Dt); opening_old = opening; traction_old = traction; updateDisplacement(model, elements, type, increment); if(s % 10 == 0) { std::cout << "passing step " << s << "/" << max_steps << std::endl; model.dump(); dumper.dump(); } } model.dump(); dumper.dump(); Real Ed = model.getEnergy("dissipated"); theoretical_Ed *= 4.; std::cout << Ed << " " << theoretical_Ed << std::endl; if (!Math::are_float_equal(Ed, theoretical_Ed) || std::isnan(Ed)) { std::cout << "The dissipated energy is incorrect" << std::endl; finalize(); return EXIT_FAILURE; } finalize(); std::cout << "OK: test_cohesive_intrinsic_tetrahedron was passed!" << std::endl; return EXIT_SUCCESS; } /* -------------------------------------------------------------------------- */ void updateDisplacement(SolidMechanicsModelCohesive & model, Array & elements, ElementType type, Vector & increment) { UInt spatial_dimension = model.getSpatialDimension(); Mesh & mesh = model.getFEM().getMesh(); UInt nb_element = elements.getSize(); UInt nb_nodes = mesh.getNbNodes(); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); const Array & connectivity = mesh.getConnectivity(type); Array & displacement = model.getDisplacement(); Array update(nb_nodes); update.clear(); for (UInt el = 0; el < nb_element; ++el) { for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = connectivity(elements(el), n); if (!update(node)) { Vector node_disp(displacement.storage() + node * spatial_dimension, spatial_dimension); node_disp += increment; update(node) = true; } } } } /* -------------------------------------------------------------------------- */ bool checkTractions(SolidMechanicsModelCohesive & model, ElementType type, Vector & opening, Vector & theoretical_traction, Matrix & rotation) { UInt spatial_dimension = model.getSpatialDimension(); const MaterialCohesive & mat_cohesive = dynamic_cast < const MaterialCohesive & > (model.getMaterial(1)); const Real sigma_c = mat_cohesive.getParam< RandomInternalField >("sigma_c"); const Real beta = mat_cohesive.getParam("beta"); // const Real G_cI = mat_cohesive.getParam("G_cI"); // Real G_cII = mat_cohesive.getParam("G_cII"); const Real delta_0 = mat_cohesive.getParam("delta_0"); const Real kappa = mat_cohesive.getParam("kappa"); Real delta_c = delta_0 * sigma_c / (sigma_c - 1.); ElementType type_facet = Mesh::getFacetType(type); ElementType type_cohesive = FEM::getCohesiveElementType(type_facet); const Array & traction = mat_cohesive.getTraction(type_cohesive); const Array & damage = mat_cohesive.getDamage(type_cohesive); UInt nb_quad_per_el = model.getFEM("CohesiveFEM").getNbQuadraturePoints(type_cohesive); UInt nb_element = model.getMesh().getNbElement(type_cohesive); UInt tot_nb_quad = nb_element * nb_quad_per_el; Vector normal_opening(spatial_dimension); normal_opening.clear(); normal_opening(0) = opening(0); Real normal_opening_norm = normal_opening.norm(); Vector tangential_opening(spatial_dimension); tangential_opening.clear(); for (UInt dim = 1; dim < spatial_dimension; ++dim) tangential_opening(dim) = opening(dim); Real tangential_opening_norm = tangential_opening.norm(); Real beta2_kappa2 = beta * beta/kappa/kappa; Real beta2_kappa = beta * beta/kappa; Real delta = std::sqrt(tangential_opening_norm * tangential_opening_norm * beta2_kappa2 + normal_opening_norm * normal_opening_norm); delta = std::max(delta, delta_0); Real theoretical_damage = std::min(delta / delta_c, 1.); if (Math::are_float_equal(theoretical_damage, 1.)) theoretical_traction.clear(); else { theoretical_traction = tangential_opening; theoretical_traction *= beta2_kappa; theoretical_traction += normal_opening; theoretical_traction *= sigma_c / delta * (1. - theoretical_damage); } Vector theoretical_traction_rotated(spatial_dimension); theoretical_traction_rotated.mul(rotation, theoretical_traction); for (UInt q = 0; q < tot_nb_quad; ++q) { for (UInt dim = 0; dim < spatial_dimension; ++dim) { if (!Math::are_float_equal(theoretical_traction_rotated(dim), traction(q, dim))) { std::cout << "Tractions are incorrect" << std::endl; return 1; } } if (!Math::are_float_equal(theoretical_damage, damage(q))) { std::cout << "Damage is incorrect" << std::endl; return 1; } } return 0; } /* -------------------------------------------------------------------------- */ void findNodesToCheck(const Mesh & mesh, const Array & elements, ElementType type, Array & nodes_to_check) { const Array & connectivity = mesh.getConnectivity(type); const Array & position = mesh.getNodes(); UInt nb_nodes = position.getSize(); UInt nb_nodes_per_elem = connectivity.getNbComponent(); Array checked_nodes(nb_nodes); checked_nodes.clear(); for (UInt el = 0; el < elements.getSize(); ++el) { UInt element = elements(el); Vector conn_el(connectivity.storage() + nb_nodes_per_elem * element, nb_nodes_per_elem); for (UInt n = 0; n < nb_nodes_per_elem; ++n) { UInt node = conn_el(n); if (Math::are_float_equal(position(node, 0), 0.) && checked_nodes(node) == false) { checked_nodes(node) = true; nodes_to_check.push_back(node); } } } } /* -------------------------------------------------------------------------- */ bool checkEquilibrium(const Array & residual) { UInt spatial_dimension = residual.getNbComponent(); Vector residual_sum(spatial_dimension); residual_sum.clear(); Array::const_iterator > res_it = residual.begin(spatial_dimension); Array::const_iterator > res_end = residual.end(spatial_dimension); for (; res_it != res_end; ++res_it) residual_sum += *res_it; for (UInt s = 0; s < spatial_dimension; ++s) { if (!Math::are_float_equal(residual_sum(s), 0.)) { std::cout << "System is not in equilibrium!" << std::endl; return 1; } } return 0; } /* -------------------------------------------------------------------------- */ bool checkResidual(const Array & residual, const Vector & traction, const Array & nodes_to_check, const Matrix & rotation) { UInt spatial_dimension = residual.getNbComponent(); Vector total_force(spatial_dimension); total_force.clear(); for (UInt n = 0; n < nodes_to_check.getSize(); ++n) { UInt node = nodes_to_check(n); Vector res(residual.storage() + node * spatial_dimension, spatial_dimension); total_force += res; } Vector theoretical_total_force(spatial_dimension); theoretical_total_force.mul(rotation, traction); theoretical_total_force *= -1 * 2 * 2; for (UInt s = 0; s < spatial_dimension; ++s) { if (!Math::are_float_equal(total_force(s), theoretical_total_force(s))) { std::cout << "Total force isn't correct!" << std::endl; return 1; } } return 0; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic/test_cohesive_intrinsic_tetrahedron_fragmentation.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic/test_cohesive_intrinsic_tetrahedron_fragmentation.cc index d07dfc6af..61c7d9290 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic/test_cohesive_intrinsic_tetrahedron_fragmentation.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic/test_cohesive_intrinsic_tetrahedron_fragmentation.cc @@ -1,188 +1,153 @@ /** * @file test_cohesive_intrinsic_tetrahedron.cc * * @author Marco Vocialta * * @date Tue Aug 20 14:37:18 2013 * * @brief Test for cohesive elements * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" #include "mesh_utils.hh" #include "solid_mechanics_model_cohesive.hh" #include "material.hh" #include "dumper_paraview.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; int main(int argc, char *argv[]) { initialize(argc, argv); // debug::setDebugLevel(dblDump); ElementType type = _tetrahedron_10; const UInt spatial_dimension = 3; const UInt max_steps = 100; Mesh mesh(spatial_dimension); mesh.read("tetrahedron_full.msh"); /* ------------------------------------------------------------------------ */ /* Facet part */ /* ------------------------------------------------------------------------ */ - // Array limits(spatial_dimension, 2); - // limits(0, 0) = -100; - // limits(0, 1) = 100; - // limits(1, 0) = -100; - // limits(1, 1) = 100; - // limits(2, 0) = -100; - // limits(2, 1) = 100; - - // MeshUtils::insertIntrinsicCohesiveElementsInArea(mesh, limits); - - Mesh mesh_facets(spatial_dimension, mesh.getNodes(), "mesh_facets"); - MeshUtils::buildAllFacets(mesh, mesh_facets); - - MeshUtils::resetFacetToDouble(mesh_facets); - - ByElementTypeArray facet_insertion("facet_insertion", ""); - mesh_facets.initByElementTypeArray(facet_insertion, 1, spatial_dimension - 1, - false, _ek_regular, true); - - const ElementType type_facet = Mesh::getFacetType(type); - Array & f_insertion = facet_insertion(type_facet); - Array > & element_to_facet - = mesh_facets.getElementToSubelement(type_facet); - - UInt nb_facet = mesh_facets.getNbElement(type_facet); - - for (UInt f = 0; f < nb_facet; ++f) { - - if (element_to_facet(f)[1] == ElementNull) continue; - - f_insertion(f) = true; - - MeshUtils::insertCohesiveElements(mesh, - mesh_facets, - facet_insertion, - false); - } + CohesiveElementInserter inserter(mesh); + inserter.insertIntrinsicElements(); /* ------------------------------------------------------------------------ */ /* End of facet part */ /* ------------------------------------------------------------------------ */ SolidMechanicsModelCohesive model(mesh); /// model initialization model.initFull("material.dat"); Real time_step = model.getStableTimeStep()*0.8; model.setTimeStep(time_step); // std::cout << "Time step: " << time_step << std::endl; model.assembleMassLumped(); model.updateResidual(); model.setBaseName("intrinsic_tetrahedron_fragmentation"); model.addDumpFieldVector("displacement"); model.addDumpField("velocity" ); model.addDumpField("acceleration"); model.addDumpField("residual" ); model.addDumpField("stress"); model.addDumpField("strain"); model.dump(); DumperParaview dumper("cohesive_elements_tetrahedron_fragmentation"); dumper.registerMesh(mesh, spatial_dimension, _not_ghost, _ek_cohesive); DumperIOHelper::Field * cohesive_displacement = new DumperIOHelper::NodalField(model.getDisplacement()); cohesive_displacement->setPadding(3); dumper.registerField("displacement", cohesive_displacement); // dumper.registerField("damage", new DumperIOHelper:: // HomogenizedField(model, // "damage", // spatial_dimension, // _not_ghost, // _ek_cohesive)); dumper.dump(); /// update displacement UInt nb_element = mesh.getNbElement(type); UInt nb_nodes = mesh.getNbNodes(); UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); Real * bary = new Real[spatial_dimension]; const Array & connectivity = mesh.getConnectivity(type); Array & displacement = model.getDisplacement(); Array update(nb_nodes); for (UInt s = 0; s < max_steps; ++s) { Real increment = s / 10.; update.clear(); for (UInt el = 0; el < nb_element; ++el) { mesh.getBarycenter(el, type, bary); for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = connectivity(el, n); if (!update(node)) { for (UInt dim = 0; dim < spatial_dimension; ++dim) { displacement(node, dim) = increment * bary[dim]; update(node) = true; } } } } if (s % 10 == 0) { model.dump(); dumper.dump(); } } delete[] bary; if (nb_nodes != nb_element * Mesh::getNbNodesPerElement(type)) { std::cout << "Wrong number of nodes" << std::endl; finalize(); return EXIT_FAILURE; } finalize(); std::cout << "OK: test_cohesive_intrinsic_tetrahedron was passed!" << std::endl; return EXIT_SUCCESS; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic_impl/test_cohesive_intrinsic_impl.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic_impl/test_cohesive_intrinsic_impl.cc index ec25041b6..bd2358c51 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic_impl/test_cohesive_intrinsic_impl.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_cohesive_intrinsic_impl/test_cohesive_intrinsic_impl.cc @@ -1,181 +1,165 @@ /** * @file test_cohesive_intrinsic_impl.cc * * @author Seyedeh Mohadeseh Taheri Mousavi * @author Marco Vocialta * * @date Mon Jul 09 14:13:56 2012 * * @brief Test for cohesive elements * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" #include "mesh_utils.hh" #include "solid_mechanics_model_cohesive.hh" #include "material_cohesive.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; int main(int argc, char *argv[]) { initialize(argc, argv); debug::setDebugLevel(dblError); const UInt spatial_dimension = 2; const ElementType type = _triangle_6; Mesh mesh(spatial_dimension); mesh.read("implicit.msh"); - Mesh mesh_facets(spatial_dimension, mesh.getNodes(), "mesh_facets"); - MeshUtils::buildAllFacets(mesh, mesh_facets); - - const ElementType type_facet = mesh.getFacetType(type); - UInt nb_facet = mesh_facets.getNbElement(type_facet); - - Array facet_insertion(nb_facet); - facet_insertion.clear(); - Real * bary_facet = new Real[spatial_dimension]; - for (UInt f = 0; f < nb_facet; ++f) { - mesh_facets.getBarycenter(f, type_facet, bary_facet); - if (bary_facet[1] < 1.1 && bary_facet[1] > .9) - facet_insertion(f) = true; - } - delete[] bary_facet; - - MeshUtils::insertIntrinsicCohesiveElements(mesh, - mesh_facets, - type_facet, - facet_insertion); + CohesiveElementInserter inserter(mesh); + inserter.setLimit('y', 0.9, 1.1); + inserter.insertIntrinsicElements(); // mesh.write("implicit_cohesive.msh"); SolidMechanicsModelCohesive model(mesh); /// model initialization model.initFull("material.dat", SolidMechanicsModelCohesiveOptions(_static)); /// boundary conditions Array & boundary = model.getBoundary(); UInt nb_nodes = mesh.getNbNodes(); Array & position = mesh.getNodes(); Array & displacement = model.getDisplacement(); + const ElementType type_facet = mesh.getFacetType(type); for (UInt n = 0; n < nb_nodes; ++n) { if (std::abs(position(n,1))< Math::getTolerance()){ boundary(n, 1) = true; displacement(n,1) = 0.0; } if ((std::abs(position(n,0))< Math::getTolerance())&& (position(n,1)< 1.1)){ boundary(n, 0) = true; displacement(n,0) = 0.0; } if ((std::abs(position(n,0)-1)< Math::getTolerance())&&(std::abs(position(n,1)-1)< Math::getTolerance())){ boundary(n, 0) = true; displacement(n,0) = 0.0; } if (std::abs(position(n,1)-2)< Math::getTolerance()){ boundary(n, 1) = true; } } model.setBaseName("intrinsic_impl"); model.addDumpField("displacement"); // model.addDumpField("mass" ); model.addDumpField("velocity" ); model.addDumpField("acceleration"); model.addDumpField("force" ); model.addDumpField("residual" ); // model.addDumpField("damage" ); model.addDumpField("stress" ); model.addDumpField("strain" ); model.dump(); const MaterialCohesive & mat_coh = dynamic_cast< const MaterialCohesive &> (model.getMaterial(1)); ElementType type_cohesive = FEM::getCohesiveElementType(type_facet); const Array & opening = mat_coh.getOpening(type_cohesive); //const Array & traction = mat_coh.getTraction(type_cohesive); model.updateResidual(); const Array & residual = model.getResidual(); UInt max_step = 1000; Real increment = 3./max_step; Real error_tol = 10e-6; std::ofstream fout; fout.open("output"); /// Main loop for ( UInt nstep = 0; nstep < max_step; ++nstep){ for (UInt n = 0; n < nb_nodes; ++n) { if (std::abs(position(n,1)-2)< Math::getTolerance()){ displacement(n,1) += increment; } } bool converged = model.solveStep<_scm_newton_raphson_tangent, _scc_residual>(1e-5, 100); AKANTU_DEBUG_ASSERT(converged, "Did not converge"); model.dump(); Real resid = 0; for (UInt n = 0; n < nb_nodes; ++n) { if (std::abs(position(n, 1) - 2.)/2. < Math::getTolerance()){ resid += residual(n, 1); } } Real analytical = exp(1) * std::abs(opening(0, 1)) * exp (-std::abs(opening(0, 1))/0.5)/0.5; //the residual force is comparing with the theoretical value of the cohesive law error_tol = std::abs((std::abs(resid) - analytical)/analytical); fout << nstep << " " << -resid << " " << analytical << " " << error_tol << std::endl; if (error_tol > 1e-3) { std::cout << "Relative error: " << error_tol << std::endl; std::cout << "Test failed!" << std::endl; return EXIT_FAILURE; } } fout.close(); finalize(); std::cout << "Test passed!" << std::endl; return EXIT_SUCCESS; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_facet_stress_synchronizer/test_cohesive_facet_stress_synchronizer.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_facet_stress_synchronizer/test_cohesive_facet_stress_synchronizer.cc index a55a591ff..36d5be1bf 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_facet_stress_synchronizer/test_cohesive_facet_stress_synchronizer.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_facet_stress_synchronizer/test_cohesive_facet_stress_synchronizer.cc @@ -1,226 +1,227 @@ /** * @file test_cohesive_facet_stress_synchronizer.cc * @author Marco Vocialta * @date Mon Oct 28 17:24:55 2013 * * @brief Test for facet stress synchronizer * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "mesh.hh" #include "mesh_io.hh" #include "mesh_io_msh.hh" #include "mesh_utils.hh" #include "solid_mechanics_model_cohesive.hh" #include "material.hh" // #if defined(AKANTU_USE_IOHELPER) // # include "io_helper.hh" // #endif /* -------------------------------------------------------------------------- */ using namespace akantu; Real function(Real constant, Real x, Real y, Real z) { return constant + 2. * x + 3. * y + 4 * z; } int main(int argc, char *argv[]) { initialize(argc, argv); debug::setDebugLevel(dblWarning); const UInt spatial_dimension = 3; ElementType type = _tetrahedron_10; ElementType type_facet = Mesh::getFacetType(type); Mesh mesh(spatial_dimension); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); akantu::MeshPartition * partition = NULL; if(prank == 0) { // Read the mesh mesh.read("tetrahedron.msh"); /// partition the mesh partition = new MeshPartitionScotch(mesh, spatial_dimension); partition->partitionate(psize); } SolidMechanicsModelCohesive model(mesh); model.initParallel(partition, NULL, true); model.initFull("material.dat", SolidMechanicsModelCohesiveOptions(_explicit_lumped_mass, true)); Array & position = mesh.getNodes(); /* ------------------------------------------------------------------------ */ /* Facet part */ /* ------------------------------------------------------------------------ */ /// compute quadrature points positions on facets const Mesh & mesh_facets = model.getMeshFacets(); UInt nb_facet = mesh_facets.getNbElement(type_facet); UInt nb_quad_per_facet = model.getFEM("FacetsFEM").getNbQuadraturePoints(type_facet); UInt nb_tot_quad = nb_quad_per_facet * nb_facet; Array quad_facets(nb_tot_quad, spatial_dimension); model.getFEM("FacetsFEM").interpolateOnQuadraturePoints(position, quad_facets, spatial_dimension, type_facet); /* ------------------------------------------------------------------------ */ /* End of facet part */ /* ------------------------------------------------------------------------ */ /// compute quadrature points position of the elements UInt nb_quad_per_element = model.getFEM().getNbQuadraturePoints(type); UInt nb_element = mesh.getNbElement(type); UInt nb_tot_quad_el = nb_quad_per_element * nb_element; Array quad_elements(nb_tot_quad_el, spatial_dimension); model.getFEM().interpolateOnQuadraturePoints(position, quad_elements, spatial_dimension, type); /// assign some values to stresses Array & stress = const_cast&>(model.getMaterial(0).getStress(type)); Array::iterator > stress_it = stress.begin(spatial_dimension, spatial_dimension); for (UInt q = 0; q < nb_tot_quad_el; ++q, ++stress_it) { /// compute values for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = i; j < spatial_dimension; ++j) { UInt index = i * spatial_dimension + j; (*stress_it)(i, j) = function(index, quad_elements(q, 0), quad_elements(q, 1), quad_elements(q, 2)); } } /// fill symmetrical part for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < i; ++j) { (*stress_it)(i, j) = (*stress_it)(j, i); } } // stress_it->clear(); // for (UInt i = 0; i < spatial_dimension; ++i) // (*stress_it)(i, i) = sigma_c * 5; } /// compute and communicate stress on facets model.checkCohesiveStress(); /* ------------------------------------------------------------------------ */ /* Check facet stress */ /* ------------------------------------------------------------------------ */ const Array & facet_stress = model.getStressOnFacets(type_facet); - const Array & facet_check = model.getFacetsCheck(type_facet); + const Array & facet_check + = model.getElementInserter().getCheckFacets(type_facet); const Array > & elements_to_facet = model.getMeshFacets().getElementToSubelement(type_facet); Array::iterator > quad_facet_it = quad_facets.begin(spatial_dimension); Array::const_iterator > facet_stress_it = facet_stress.begin(spatial_dimension, spatial_dimension * 2); Matrix current_stress(spatial_dimension, spatial_dimension); for (UInt f = 0; f < nb_facet; ++f) { if (!facet_check(f) || (elements_to_facet(f)[0].ghost_type == _not_ghost && elements_to_facet(f)[1].ghost_type == _not_ghost)) { quad_facet_it += nb_quad_per_facet; facet_stress_it += nb_quad_per_facet; continue; } for (UInt q = 0; q < nb_quad_per_facet; ++q, ++quad_facet_it, ++facet_stress_it) { /// compute current_stress for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = i; j < spatial_dimension; ++j) { UInt index = i * spatial_dimension + j; current_stress(i, j) = function(index, (*quad_facet_it)(0), (*quad_facet_it)(1), (*quad_facet_it)(2)); } } /// fill symmetrical part for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < i; ++j) { current_stress(i, j) = current_stress(j, i); } } /// compare it to interpolated one for (UInt s = 0; s < 2; ++s) { Matrix stress_to_check(facet_stress_it->storage() + s * spatial_dimension * spatial_dimension, spatial_dimension, spatial_dimension); for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt j = 0; j < spatial_dimension; ++j) { if (!Math::are_float_equal(stress_to_check(i, j), current_stress(i, j))) { std::cout << "Stress doesn't match" << std::endl; finalize(); return EXIT_FAILURE; } } } } } } finalize(); if (prank == 0) std::cout << "OK: test_cohesive_facet_stress_synchronizer passed!" << std::endl; return EXIT_SUCCESS; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic.cc index 7ca4c9542..286253661 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic.cc @@ -1,216 +1,212 @@ /** * @file test_cohesive_parallel.cc * @author Marco Vocialta * @date Wed Nov 28 16:59:11 2012 * * @brief parallel test for cohesive elements * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "mesh_io.hh" #include "mesh_utils.hh" #include "solid_mechanics_model_cohesive.hh" #include "dumper_paraview.hh" #include "static_communicator.hh" #include "dof_synchronizer.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; int main(int argc, char *argv[]) { initialize(argc, argv); debug::setDebugLevel(dblWarning); const UInt max_steps = 500; UInt spatial_dimension = 2; Mesh mesh(spatial_dimension); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); akantu::MeshPartition * partition = NULL; if(prank == 0) { // Read the mesh mesh.read("mesh.msh"); /// partition the mesh partition = new MeshPartitionScotch(mesh, spatial_dimension); // debug::setDebugLevel(dblDump); partition->partitionate(psize); // debug::setDebugLevel(dblWarning); } SolidMechanicsModelCohesive model(mesh); model.initParallel(partition, NULL, true); // debug::setDebugLevel(dblDump); // std::cout << mesh << std::endl; // debug::setDebugLevel(dblWarning); model.initFull("material.dat", SolidMechanicsModelCohesiveOptions(_explicit_lumped_mass, true)); /* ------------------------------------------------------------------------ */ /* Facet part */ /* ------------------------------------------------------------------------ */ - Array limits(spatial_dimension, 2); - limits(0, 0) = -100; - limits(0, 1) = 100; - limits(1, 0) = -0.30; - limits(1, 1) = -0.20; - - model.enableFacetsCheckOnArea(limits); + CohesiveElementInserter & inserter = model.getElementInserter(); + inserter.setLimit('y', -0.30, -0.20); + model.updateAutomaticInsertion(); /* ------------------------------------------------------------------------ */ /* End of facet part */ /* ------------------------------------------------------------------------ */ // debug::setDebugLevel(dblDump); // std::cout << mesh_facets << std::endl; // debug::setDebugLevel(dblWarning); Real time_step = model.getStableTimeStep()*0.1; model.setTimeStep(time_step); std::cout << "Time step: " << time_step << std::endl; model.assembleMassLumped(); Array & position = mesh.getNodes(); Array & velocity = model.getVelocity(); Array & boundary = model.getBoundary(); Array & displacement = model.getDisplacement(); // const Array & residual = model.getResidual(); UInt nb_nodes = mesh.getNbNodes(); /// boundary conditions for (UInt n = 0; n < nb_nodes; ++n) { if (position(n, 1) > 0.99 || position(n, 1) < -0.99) boundary(n, 1) = true; if (position(n, 0) > 0.99 || position(n, 0) < -0.99) boundary(n, 0) = true; } /// initial conditions Real loading_rate = 0.5; Real disp_update = loading_rate * time_step; for (UInt n = 0; n < nb_nodes; ++n) { velocity(n, 1) = loading_rate * position(n, 1); } model.synchronizeBoundaries(); model.updateResidual(); model.setBaseName("extrinsic_parallel"); model.addDumpFieldVector("displacement"); model.addDumpFieldVector("velocity" ); model.addDumpFieldVector("acceleration"); model.addDumpFieldVector("residual" ); model.addDumpFieldTensor("stress"); model.addDumpFieldTensor("strain"); model.addDumpField("partitions"); // model.getDumper().getDumper().setMode(iohelper::BASE64); model.dump(); DumperParaview dumper("cohesive_elements"); dumper.registerMesh(mesh, spatial_dimension, _not_ghost, _ek_cohesive); DumperIOHelper::Field * cohesive_displacement = new DumperIOHelper::NodalField(model.getDisplacement()); cohesive_displacement->setPadding(3); dumper.registerField("displacement", cohesive_displacement); // dumper.registerField("damage", new DumperIOHelper:: // HomogenizedField(model, // "damage", // spatial_dimension, // _not_ghost, // _ek_cohesive)); /// Main loop for (UInt s = 1; s <= max_steps; ++s) { /// update displacement on extreme nodes for (UInt n = 0; n < nb_nodes; ++n) { if (position(n, 1) > 0.99 || position(n, 1) < -0.99) displacement(n, 1) += disp_update * position(n, 1); } model.checkCohesiveStress(); model.explicitPred(); model.updateResidual(); model.updateAcceleration(); model.explicitCorr(); // model.dump(); if(s % 10 == 0) { if(prank == 0) std::cout << "passing step " << s << "/" << max_steps << std::endl; } // // update displacement // for (UInt n = 0; n < nb_nodes; ++n) { // if (position(n, 1) + displacement(n, 1) > 0) { // displacement(n, 0) -= 0.01; // } // } // Real Ed = dynamic_cast (model.getMaterial(1)).getDissipatedEnergy(); // Real Er = dynamic_cast (model.getMaterial(1)).getReversibleEnergy(); // edis << s << " " // << Ed << std::endl; // erev << s << " " // << Er << std::endl; } dumper.dump(); // edis.close(); // erev.close(); Real Ed = model.getEnergy("dissipated"); Real Edt = 200 * sqrt(2); if(prank == 0) { std::cout << Ed << " " << Edt << std::endl; if (Ed < Edt * 0.999 || Ed > Edt * 1.001 || std::isnan(Ed)) { std::cout << "The dissipated energy is incorrect" << std::endl; finalize(); return EXIT_FAILURE; } } finalize(); return EXIT_SUCCESS; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic_tetrahedron_displacement.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic_tetrahedron_displacement.cc index edd9bed01..a6a935db3 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic_tetrahedron_displacement.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_extrinsic/test_cohesive_parallel_extrinsic_tetrahedron_displacement.cc @@ -1,417 +1,417 @@ /** * @file test_cohesive_parallel_extrinsic_tetrahedron_displacement.cc * @author Marco Vocialta * @date Mon Nov 18 10:04:13 2013 * * @brief Displacement test for 3D cohesive elements * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include "mesh_io.hh" #include "mesh_utils.hh" #include "solid_mechanics_model_cohesive.hh" #include "dumper_paraview.hh" #include "static_communicator.hh" #include "dof_synchronizer.hh" #include "material_cohesive_linear.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; bool checkDisplacement(SolidMechanicsModelCohesive & model, ElementType type, std::ofstream & error_output, UInt step, bool barycenters); int main(int argc, char *argv[]) { initialize(argc, argv); debug::setDebugLevel(dblWarning); const UInt max_steps = 500; UInt spatial_dimension = 3; ElementType type = _tetrahedron_10; Mesh mesh(spatial_dimension); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); akantu::MeshPartition * partition = NULL; if(prank == 0) { // Read the mesh mesh.read("tetrahedron.msh"); /// partition the mesh partition = new MeshPartitionScotch(mesh, spatial_dimension); // debug::setDebugLevel(dblDump); partition->partitionate(psize); // debug::setDebugLevel(dblWarning); } SolidMechanicsModelCohesive model(mesh); model.initParallel(partition, NULL, true); // debug::setDebugLevel(dblDump); // std::cout << mesh << std::endl; // debug::setDebugLevel(dblWarning); model.initFull("material.dat", SolidMechanicsModelCohesiveOptions(_explicit_lumped_mass, true)); /* ------------------------------------------------------------------------ */ /* Facet part */ /* ------------------------------------------------------------------------ */ - Array limits(spatial_dimension, 2); - limits(0, 0) = -0.01; - limits(0, 1) = 0.01; - limits(1, 0) = -100; - limits(1, 1) = 100; - limits(2, 0) = -100; - limits(2, 1) = 100; + // Array limits(spatial_dimension, 2); + // limits(0, 0) = -0.01; + // limits(0, 1) = 0.01; + // limits(1, 0) = -100; + // limits(1, 1) = 100; + // limits(2, 0) = -100; + // limits(2, 1) = 100; - model.enableFacetsCheckOnArea(limits); + // model.enableFacetsCheckOnArea(limits); /* ------------------------------------------------------------------------ */ /* End of facet part */ /* ------------------------------------------------------------------------ */ // debug::setDebugLevel(dblDump); // std::cout << mesh_facets << std::endl; // debug::setDebugLevel(dblWarning); Real time_step = model.getStableTimeStep()*0.1; model.setTimeStep(time_step); std::cout << "Time step: " << time_step << std::endl; model.assembleMassLumped(); Array & position = mesh.getNodes(); Array & velocity = model.getVelocity(); Array & boundary = model.getBoundary(); Array & displacement = model.getDisplacement(); // const Array & residual = model.getResidual(); UInt nb_nodes = mesh.getNbNodes(); /// boundary conditions for (UInt n = 0; n < nb_nodes; ++n) { if (position(n, 0) > 0.99 || position(n, 0) < -0.99) { for (UInt dim = 0; dim < spatial_dimension; ++dim) { boundary(n, dim) = true; } } if (position(n, 0) > 0.99 || position(n, 0) < -0.99) { for (UInt dim = 0; dim < spatial_dimension; ++dim) { boundary(n, dim) = true; } } } // #if defined (AKANTU_DEBUG_TOOLS) // Vector facet_center(spatial_dimension); // facet_center(0) = 0; // facet_center(1) = -0.16666667; // facet_center(2) = 0.5; // debug::element_manager.setMesh(mesh); // debug::element_manager.addModule(debug::_dm_material_cohesive); // debug::element_manager.addModule(debug::_dm_debug_tools); // //debug::element_manager.addModule(debug::_dm_integrator); // #endif /// initial conditions Real loading_rate = 1; Real disp_update = loading_rate * time_step; for (UInt n = 0; n < nb_nodes; ++n) { velocity(n, 0) = loading_rate * position(n, 0); velocity(n, 1) = loading_rate * position(n, 0); } model.synchronizeBoundaries(); model.updateResidual(); std::stringstream paraview_output; paraview_output << "extrinsic_parallel_tetrahedron_" << psize; model.setBaseName(paraview_output.str()); model.addDumpFieldVector("displacement"); model.addDumpFieldVector("velocity" ); model.addDumpFieldVector("acceleration"); model.addDumpFieldVector("residual" ); model.addDumpFieldTensor("stress"); model.addDumpFieldTensor("strain"); model.addDumpField("partitions"); // model.getDumper().getDumper().setMode(iohelper::BASE64); model.dump(); DumperParaview dumper("cohesive_elements"); dumper.registerMesh(mesh, spatial_dimension, _not_ghost, _ek_cohesive); DumperIOHelper::Field * cohesive_displacement = new DumperIOHelper::NodalField(model.getDisplacement()); cohesive_displacement->setPadding(3); dumper.registerField("displacement", cohesive_displacement); // dumper.registerField("damage", new DumperIOHelper:: // HomogenizedField(model, // "damage", // spatial_dimension, // _not_ghost, // _ek_cohesive)); dumper.dump(); std::stringstream error_stream; error_stream << "error" << ".csv"; std::ofstream error_output; error_output.open(error_stream.str().c_str()); error_output << "# Step, Average, Max, Min" << std::endl; if (checkDisplacement(model, type, error_output, 0, true)) {} /// Main loop for (UInt s = 1; s <= max_steps; ++s) { /// update displacement on extreme nodes for (UInt n = 0; n < mesh.getNbNodes(); ++n) { if (position(n, 0) > 0.99 || position(n, 0) < -0.99) { displacement(n, 0) += disp_update * position(n, 0); displacement(n, 1) += disp_update * position(n, 0); } } model.checkCohesiveStress(); model.explicitPred(); model.updateResidual(); model.updateAcceleration(); model.explicitCorr(); if(s % 100 == 0) { if(prank == 0) std::cout << "passing step " << s << "/" << max_steps << std::endl; } } + model.dump(); + dumper.dump(); + if (!checkDisplacement(model, type, error_output, max_steps, false)) { finalize(); return EXIT_FAILURE; } - model.dump(); - dumper.dump(); - finalize(); return EXIT_SUCCESS; } bool checkDisplacement(SolidMechanicsModelCohesive & model, ElementType type, std::ofstream & error_output, UInt step, bool barycenters) { Mesh & mesh = model.getMesh(); UInt spatial_dimension = mesh.getSpatialDimension(); const Array & connectivity = mesh.getConnectivity(type); const Array & displacement = model.getDisplacement(); UInt nb_element = mesh.getNbElement(type); UInt nb_nodes_per_elem = Mesh::getNbNodesPerElement(type); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); if (psize == 1) { std::stringstream displacement_file; displacement_file << "displacement/displacement_" << std::setfill('0') << std::setw(6) << step; std::ofstream displacement_output; displacement_output.open(displacement_file.str().c_str()); for (UInt el = 0; el < nb_element; ++el) { for (UInt n = 0; n < nb_nodes_per_elem; ++n) { UInt node = connectivity(el, n); for (UInt dim = 0; dim < spatial_dimension; ++dim) { displacement_output << std::setprecision(15) << displacement(node, dim) << " "; } displacement_output << std::endl; } } displacement_output.close(); if (barycenters) { std::stringstream barycenter_file; barycenter_file << "displacement/barycenters"; std::ofstream barycenter_output; barycenter_output.open(barycenter_file.str().c_str()); Element element(type, 0); Vector bary(spatial_dimension); for (UInt el = 0; el < nb_element; ++el) { element.element = el; mesh.getBarycenter(element, bary); for (UInt dim = 0; dim < spatial_dimension; ++dim) { barycenter_output << std::setprecision(15) << bary(dim) << " "; } barycenter_output << std::endl; } barycenter_output.close(); } } else { if (barycenters) return true; /// read data std::stringstream displacement_file; displacement_file << "displacement/displacement_" << std::setfill('0') << std::setw(6) << step; std::ifstream displacement_input; displacement_input.open(displacement_file.str().c_str()); Array displacement_serial(0, spatial_dimension); Vector disp_tmp(spatial_dimension); while (displacement_input.good()) { for (UInt i = 0; i < spatial_dimension; ++i) displacement_input >> disp_tmp(i); displacement_serial.push_back(disp_tmp); } std::stringstream barycenter_file; barycenter_file << "displacement/barycenters"; std::ifstream barycenter_input; barycenter_input.open(barycenter_file.str().c_str()); Array barycenter_serial(0, spatial_dimension); while (barycenter_input.good()) { for (UInt dim = 0; dim < spatial_dimension; ++dim) barycenter_input >> disp_tmp(dim); barycenter_serial.push_back(disp_tmp); } Element element(type, 0); Vector bary(spatial_dimension); Array::iterator > it; Array::iterator > begin = barycenter_serial.begin(spatial_dimension); Array::iterator > end = barycenter_serial.end(spatial_dimension); Array::const_iterator > disp_it; Array::iterator > disp_serial_it; Vector difference(spatial_dimension); Array error; /// compute error for (UInt el = 0; el < nb_element; ++el) { element.element = el; mesh.getBarycenter(element, bary); /// find element for (it = begin; it != end; ++it) { UInt matched_dim = 0; while (matched_dim < spatial_dimension && Math::are_float_equal(bary(matched_dim), (*it)(matched_dim))) ++matched_dim; if (matched_dim == spatial_dimension) break; } if (it == end) { std::cout << "Element barycenter not found!" << std::endl; return false; } UInt matched_el = it - begin; disp_serial_it = displacement_serial.begin(spatial_dimension) + matched_el * nb_nodes_per_elem; for (UInt n = 0; n < nb_nodes_per_elem; ++n, ++disp_serial_it) { UInt node = connectivity(el, n); if (!mesh.isLocalOrMasterNode(node)) continue; disp_it = displacement.begin(spatial_dimension) + node; difference = *disp_it; difference -= *disp_serial_it; error.push_back(difference.norm()); } } /// compute average error Real average_error = std::accumulate(error.begin(), error.end(), 0.); comm.allReduce(&average_error, 1, _so_sum); UInt error_size = error.getSize(); comm.allReduce(&error_size, 1, _so_sum); average_error /= error_size; /// compute maximum and minimum Real max_error = *std::max_element(error.begin(), error.end()); comm.allReduce(&max_error, 1, _so_max); Real min_error = *std::min_element(error.begin(), error.end()); comm.allReduce(&min_error, 1, _so_min); /// output data if (prank == 0) { error_output << step << ", " << average_error << ", " << max_error << ", " << min_error << std::endl; } - if (max_error > 1.e-13) { + if (max_error > 1.e-9) { std::cout << "Displacement error is too big!" << std::endl; return false; } } return true; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_intrinsic/test_cohesive_parallel_intrinsic.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_intrinsic/test_cohesive_parallel_intrinsic.cc index 30fa85276..c302078b8 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_intrinsic/test_cohesive_parallel_intrinsic.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_intrinsic/test_cohesive_parallel_intrinsic.cc @@ -1,178 +1,174 @@ /** * @file test_cohesive_parallel_intrinsic.cc * @author Marco Vocialta * @date Wed Nov 28 16:59:11 2012 * * @brief parallel test for intrinsic cohesive elements * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "mesh_io.hh" #include "mesh_utils.hh" #include "model.hh" #include "solid_mechanics_model_cohesive.hh" #include "dumper_paraview.hh" #include "static_communicator.hh" #include "dof_synchronizer.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; int main(int argc, char *argv[]) { initialize(argc, argv); debug::setDebugLevel(dblWarning); const UInt max_steps = 350; UInt spatial_dimension = 2; Mesh mesh(spatial_dimension); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); akantu::MeshPartition * partition = NULL; if(prank == 0) { // Read the mesh mesh.read("mesh.msh"); /// insert cohesive elements - Array limits(spatial_dimension, 2); - limits(0, 0) = -0.26; - limits(0, 1) = -0.24; - limits(1, 0) = -100; - limits(1, 1) = 100; - - MeshUtils::insertIntrinsicCohesiveElementsInArea(mesh, limits); + CohesiveElementInserter inserter(mesh); + inserter.setLimit('x', -0.26, -0.24); + inserter.insertIntrinsicElements(); /// partition the mesh partition = new MeshPartitionScotch(mesh, spatial_dimension); // debug::setDebugLevel(dblDump); partition->partitionate(psize); // debug::setDebugLevel(dblWarning); } SolidMechanicsModelCohesive model(mesh); model.initParallel(partition); debug::setDebugLevel(dblDump); std::cout << mesh << std::endl; debug::setDebugLevel(dblWarning); model.initFull("material.dat"); Real time_step = model.getStableTimeStep()*0.8; model.setTimeStep(time_step); // std::cout << "Time step: " << time_step << std::endl; model.assembleMassLumped(); Array & position = mesh.getNodes(); Array & velocity = model.getVelocity(); Array & boundary = model.getBoundary(); // Array & displacement = model.getDisplacement(); // const Array & residual = model.getResidual(); UInt nb_nodes = mesh.getNbNodes(); Real epsilon = std::numeric_limits::epsilon(); for (UInt n = 0; n < nb_nodes; ++n) { if (std::abs(position(n, 0) - 1.) < epsilon) boundary(n, 0) = true; } model.synchronizeBoundaries(); model.updateResidual(); model.setBaseName("intrinsic_parallel"); model.addDumpFieldVector("displacement"); model.addDumpField("velocity" ); model.addDumpField("acceleration"); model.addDumpField("residual" ); model.addDumpField("stress"); model.addDumpField("strain"); //model.addDumpField("partitions"); model.addDumpField("force"); model.getDumper().getDumper().setMode(iohelper::BASE64); model.dump(); /// initial conditions Real loading_rate = .2; for (UInt n = 0; n < nb_nodes; ++n) { velocity(n, 0) = loading_rate * position(n, 0); } /// Main loop for (UInt s = 1; s <= max_steps; ++s) { model.explicitPred(); model.updateResidual(); model.updateAcceleration(); model.explicitCorr(); if(s % 1 == 0) { model.dump(); if(prank == 0) std::cout << "passing step " << s << "/" << max_steps << std::endl; } // // update displacement // for (UInt n = 0; n < nb_nodes; ++n) { // if (position(n, 1) + displacement(n, 1) > 0) { // displacement(n, 0) -= 0.01; // } // } // Real Ed = dynamic_cast (model.getMaterial(1)).getDissipatedEnergy(); // Real Er = dynamic_cast (model.getMaterial(1)).getReversibleEnergy(); // edis << s << " " // << Ed << std::endl; // erev << s << " " // << Er << std::endl; } // edis.close(); // erev.close(); Real Ed = model.getEnergy("dissipated"); Real Edt = 2 * sqrt(2); if(prank == 0) { std::cout << Ed << " " << Edt << std::endl; if (std::abs((Ed - Edt) / Edt) > 0.01 || std::isnan(Ed)) { std::cout << "The dissipated energy is incorrect" << std::endl; return EXIT_FAILURE; } } finalize(); if(prank == 0) std::cout << "OK: Test passed!" << std::endl; return EXIT_SUCCESS; } diff --git a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_intrinsic/test_cohesive_parallel_intrinsic_tetrahedron.cc b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_intrinsic/test_cohesive_parallel_intrinsic_tetrahedron.cc index 994a38bb8..82716c924 100644 --- a/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_intrinsic/test_cohesive_parallel_intrinsic_tetrahedron.cc +++ b/test/test_model/test_solid_mechanics_model/test_cohesive/test_parallel_cohesive/test_cohesive_parallel_intrinsic/test_cohesive_parallel_intrinsic_tetrahedron.cc @@ -1,747 +1,741 @@ /** * @file test_cohesive_parallel_intrinsic_tetrahedron.cc * @author Marco Vocialta * @date Fri Sep 20 15:59:40 2013 * * @brief Test for 3D intrinsic cohesive elements simulation in parallel * * @section LICENSE * * Copyright (©) 2010-2011 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "mesh_io.hh" #include "mesh_utils.hh" #include "model.hh" #include "solid_mechanics_model_cohesive.hh" #include "dumper_paraview.hh" #include "static_communicator.hh" #include "dof_synchronizer.hh" #include "material_cohesive.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; void updateDisplacement(SolidMechanicsModelCohesive & model, const ByElementTypeUInt & elements, Vector & increment); bool checkTractions(SolidMechanicsModelCohesive & model, Vector & opening, Vector & theoretical_traction, Matrix & rotation); void findNodesToCheck(const Mesh & mesh, const ByElementTypeUInt & elements, Array & nodes_to_check, Int psize); bool checkEquilibrium(const Mesh & mesh, const Array & residual); bool checkResidual(const Array & residual, const Vector & traction, const Array & nodes_to_check, const Matrix & rotation); void findElementsToDisplace(const Mesh & mesh, ByElementTypeUInt & elements); int main(int argc, char *argv[]) { initialize(argc, argv); debug::setDebugLevel(dblInfo); const UInt spatial_dimension = 3; const UInt max_steps = 60; const Real increment_constant = 0.01; ElementType type = _tetrahedron_10; Mesh mesh(spatial_dimension); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); UInt nb_nodes_to_check_serial = 0; UInt total_nb_nodes = 0; UInt nb_elements_check_serial = 0; Array nodes_to_check_serial; akantu::MeshPartition * partition = NULL; if(prank == 0) { // Read the mesh mesh.read("tetrahedron.msh"); /// count nodes with zero position const Array & position = mesh.getNodes(); for (UInt n = 0; n < position.getSize(); ++n) { if (Math::are_float_equal(position(n, 0), 0.)) ++nb_nodes_to_check_serial; } /// insert cohesive elements - Array limits(spatial_dimension, 2); - limits(0, 0) = -0.01; - limits(0, 1) = 0.01; - limits(1, 0) = -100; - limits(1, 1) = 100; - limits(2, 0) = -100; - limits(2, 1) = 100; - - MeshUtils::insertIntrinsicCohesiveElementsInArea(mesh, limits); + CohesiveElementInserter inserter(mesh); + inserter.setLimit('x', -0.01, 0.01); + inserter.insertIntrinsicElements(); total_nb_nodes = mesh.getNbNodes(); /// find nodes to check in serial ByElementTypeUInt elements_serial("elements_serial", ""); findElementsToDisplace(mesh, elements_serial); nb_elements_check_serial = elements_serial(type).getSize(); findNodesToCheck(mesh, elements_serial, nodes_to_check_serial, 1); /// partition the mesh partition = new MeshPartitionScotch(mesh, spatial_dimension); debug::setDebugLevel(dblDump); partition->partitionate(psize); debug::setDebugLevel(dblInfo); } comm.broadcast(&nb_nodes_to_check_serial, 1, 0); comm.broadcast(&nb_elements_check_serial, 1, 0); SolidMechanicsModelCohesive model(mesh); model.initParallel(partition); model.initFull("material_tetrahedron.dat"); { comm.broadcast(&total_nb_nodes, 1, 0); Array nb_local_nodes(psize); nb_local_nodes.clear(); for (UInt n = 0; n < mesh.getNbNodes(); ++n) { if (mesh.isLocalOrMasterNode(n)) ++nb_local_nodes(prank); } comm.allGather(nb_local_nodes.storage(), 1); UInt total_nb_nodes_parallel = std::accumulate(nb_local_nodes.begin(), nb_local_nodes.end(), 0); Array global_nodes_list(total_nb_nodes_parallel); UInt first_global_node = std::accumulate(nb_local_nodes.begin(), nb_local_nodes.begin() + prank, 0); for (UInt n = 0; n < mesh.getNbNodes(); ++n) { if (mesh.isLocalOrMasterNode(n)) { global_nodes_list(first_global_node) = mesh.getNodeGlobalId(n); ++first_global_node; } } comm.allGatherV(global_nodes_list.storage(), nb_local_nodes.storage()); if (prank == 0) std::cout << "Maximum node index: " << *(std::max_element(global_nodes_list.begin(), global_nodes_list.end())) << std::endl; Array repeated_nodes; repeated_nodes.resize(0); for (UInt n = 0; n < total_nb_nodes_parallel; ++n) { UInt appearances = std::count(global_nodes_list.begin() + n, global_nodes_list.end(), global_nodes_list(n)); if (appearances > 1) { std::cout << "Node " << global_nodes_list(n) << " appears " << appearances << " times" << std::endl; std::cout << " in position: " << n; repeated_nodes.push_back(global_nodes_list(n)); UInt * node_position = global_nodes_list.storage() + n; for (UInt i = 1; i < appearances; ++i) { node_position = std::find(node_position + 1, global_nodes_list.storage() + total_nb_nodes_parallel, global_nodes_list(n)); UInt current_index = node_position - global_nodes_list.storage(); std::cout << ", " << current_index; } std::cout << std::endl << std::endl; } } for (UInt n = 0; n < mesh.getNbNodes(); ++n) { UInt global_node = mesh.getNodeGlobalId(n); if (std::find(repeated_nodes.begin(), repeated_nodes.end(), global_node) != repeated_nodes.end()) { std::cout << "Repeated global node " << global_node << " corresponds to local node " << n << std::endl; } } if (total_nb_nodes != total_nb_nodes_parallel) { if (prank == 0) { std::cout << "Error: total number of nodes is wrong in parallel" << std::endl; std::cout << "Serial: " << total_nb_nodes << " Parallel: " << total_nb_nodes_parallel << std::endl; } finalize(); return EXIT_FAILURE; } } model.updateResidual(); model.setBaseName("intrinsic_parallel_tetrahedron"); model.addDumpFieldVector("displacement"); model.addDumpField("residual"); model.addDumpField("partitions"); model.dump(); DumperParaview dumper("cohesive_elements_parallel_tetrahedron"); dumper.registerMesh(mesh, spatial_dimension, _not_ghost, _ek_cohesive); DumperIOHelper::Field * cohesive_displacement = new DumperIOHelper::NodalField(model.getDisplacement()); cohesive_displacement->setPadding(3); dumper.registerField("displacement", cohesive_displacement); dumper.dump(); /// find elements to displace ByElementTypeUInt elements("elements", ""); findElementsToDisplace(mesh, elements); UInt nb_elements_check = elements(type).getSize(); comm.allReduce(&nb_elements_check, 1, _so_sum); if (nb_elements_check != nb_elements_check_serial) { if (prank == 0) { std::cout << "Error: number of elements to check is wrong" << std::endl; std::cout << "Serial: " << nb_elements_check_serial << " Parallel: " << nb_elements_check << std::endl; } finalize(); return EXIT_FAILURE; } /// find nodes to check Array nodes_to_check; findNodesToCheck(mesh, elements, nodes_to_check, psize); Vector nodes_to_check_size(psize); nodes_to_check_size(prank) = nodes_to_check.getSize(); comm.allGather(nodes_to_check_size.storage(), 1); UInt nodes_to_check_global_size = std::accumulate(nodes_to_check_size.storage(), nodes_to_check_size.storage() + psize, 0); Array nodes_to_check_global(nodes_to_check_global_size); UInt begin_index = std::accumulate(nodes_to_check_size.storage(), nodes_to_check_size.storage() + prank, 0); for (UInt i = begin_index; i < begin_index + nodes_to_check_size(prank); ++i) { UInt node = nodes_to_check(i - begin_index); nodes_to_check_global(i) = mesh.getNodeGlobalId(node); } comm.allGatherV(nodes_to_check_global.storage(), nodes_to_check_size.storage()); if (nodes_to_check_global_size != nb_nodes_to_check_serial) { if (prank == 0) { std::cout << "Error: number of nodes to check is wrong in parallel" << std::endl; std::cout << "Serial: " << nb_nodes_to_check_serial << " Parallel: " << nodes_to_check_global_size << std::endl; for (UInt n = 0; n < nodes_to_check_serial.getSize(); ++n) { if (std::find(nodes_to_check_global.begin(), nodes_to_check_global.end(), nodes_to_check_serial(n)) == nodes_to_check_global.end()) { std::cout << "Node number " << nodes_to_check_serial(n) << " not found in parallel" << std::endl; } } } finalize(); return EXIT_FAILURE; } /// rotate mesh Real angle = 1.; Matrix rotation(spatial_dimension, spatial_dimension); rotation.clear(); rotation(0, 0) = std::cos(angle); rotation(0, 1) = std::sin(angle) * -1.; rotation(1, 0) = std::sin(angle); rotation(1, 1) = std::cos(angle); rotation(2, 2) = 1.; Vector increment_tmp(spatial_dimension); for (UInt dim = 0; dim < spatial_dimension; ++dim) { increment_tmp(dim) = (dim + 1) * increment_constant; } Vector increment(spatial_dimension); increment.mul(rotation, increment_tmp); Array & position = mesh.getNodes(); Array position_tmp(position); Array::iterator > position_it = position.begin(spatial_dimension); Array::iterator > position_end = position.end(spatial_dimension); Array::iterator > position_tmp_it = position_tmp.begin(spatial_dimension); for (; position_it != position_end; ++position_it, ++position_tmp_it) position_it->mul(rotation, *position_tmp_it); model.dump(); dumper.dump(); updateDisplacement(model, elements, increment); Real theoretical_Ed = 0; Vector opening(spatial_dimension); Vector traction(spatial_dimension); Vector opening_old(spatial_dimension); Vector traction_old(spatial_dimension); opening.clear(); traction.clear(); opening_old.clear(); traction_old.clear(); Vector Dt(spatial_dimension); Vector Do(spatial_dimension); const Array & residual = model.getResidual(); /// Main loop for (UInt s = 1; s <= max_steps; ++s) { model.updateResidual(); opening += increment_tmp; if (checkTractions(model, opening, traction, rotation) || checkEquilibrium(mesh, residual) || checkResidual(residual, traction, nodes_to_check, rotation)) { finalize(); return EXIT_FAILURE; } /// compute energy Do = opening; Do -= opening_old; Dt = traction_old; Dt += traction; theoretical_Ed += .5 * Do.dot(Dt); opening_old = opening; traction_old = traction; updateDisplacement(model, elements, increment); if(s % 10 == 0) { if (prank == 0) std::cout << "passing step " << s << "/" << max_steps << std::endl; model.dump(); dumper.dump(); } } model.dump(); dumper.dump(); Real Ed = model.getEnergy("dissipated"); theoretical_Ed *= 4.; if (prank == 0) std::cout << "Dissipated energy: " << Ed << ", theoretical value: " << theoretical_Ed << std::endl; if (!Math::are_float_equal(Ed, theoretical_Ed) || std::isnan(Ed)) { if (prank == 0) std::cout << "Error: the dissipated energy is incorrect" << std::endl; finalize(); return EXIT_FAILURE; } finalize(); if(prank == 0) std::cout << "OK: Test passed!" << std::endl; return EXIT_SUCCESS; } /* -------------------------------------------------------------------------- */ void updateDisplacement(SolidMechanicsModelCohesive & model, const ByElementTypeUInt & elements, Vector & increment) { UInt spatial_dimension = model.getSpatialDimension(); Mesh & mesh = model.getFEM().getMesh(); UInt nb_nodes = mesh.getNbNodes(); Array & displacement = model.getDisplacement(); Array update(nb_nodes); update.clear(); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last = mesh.lastType(spatial_dimension, ghost_type); for (; it != last; ++it) { ElementType type = *it; const Array & elem = elements(type, ghost_type); const Array & connectivity = mesh.getConnectivity(type, ghost_type); UInt nb_nodes_per_element = connectivity.getNbComponent(); for (UInt el = 0; el < elem.getSize(); ++el) { for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = connectivity(elem(el), n); if (!update(node)) { Vector node_disp(displacement.storage() + node * spatial_dimension, spatial_dimension); node_disp += increment; update(node) = true; } } } } } } /* -------------------------------------------------------------------------- */ bool checkTractions(SolidMechanicsModelCohesive & model, Vector & opening, Vector & theoretical_traction, Matrix & rotation) { UInt spatial_dimension = model.getSpatialDimension(); const Mesh & mesh = model.getMesh(); const MaterialCohesive & mat_cohesive = dynamic_cast < const MaterialCohesive & > (model.getMaterial(1)); const Real sigma_c = mat_cohesive.getParam< RandomInternalField >("sigma_c"); const Real beta = mat_cohesive.getParam("beta"); // const Real G_cI = mat_cohesive.getParam("G_cI"); // Real G_cII = mat_cohesive.getParam("G_cII"); const Real delta_0 = mat_cohesive.getParam("delta_0"); const Real kappa = mat_cohesive.getParam("kappa"); Real delta_c = delta_0 * sigma_c / (sigma_c - 1.); Vector normal_opening(spatial_dimension); normal_opening.clear(); normal_opening(0) = opening(0); Real normal_opening_norm = normal_opening.norm(); Vector tangential_opening(spatial_dimension); tangential_opening.clear(); for (UInt dim = 1; dim < spatial_dimension; ++dim) tangential_opening(dim) = opening(dim); Real tangential_opening_norm = tangential_opening.norm(); Real beta2_kappa2 = beta * beta/kappa/kappa; Real beta2_kappa = beta * beta/kappa; Real delta = std::sqrt(tangential_opening_norm * tangential_opening_norm * beta2_kappa2 + normal_opening_norm * normal_opening_norm); delta = std::max(delta, delta_0); Real theoretical_damage = std::min(delta / delta_c, 1.); if (Math::are_float_equal(theoretical_damage, 1.)) theoretical_traction.clear(); else { theoretical_traction = tangential_opening; theoretical_traction *= beta2_kappa; theoretical_traction += normal_opening; theoretical_traction *= sigma_c / delta * (1. - theoretical_damage); } Vector theoretical_traction_rotated(spatial_dimension); theoretical_traction_rotated.mul(rotation, theoretical_traction); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type, _ek_cohesive); Mesh::type_iterator last = mesh.lastType(spatial_dimension, ghost_type, _ek_cohesive); for (; it != last; ++it) { ElementType type = *it; const Array & traction = mat_cohesive.getTraction(type, ghost_type); const Array & damage = mat_cohesive.getDamage(type, ghost_type); UInt nb_quad_per_el = model.getFEM("CohesiveFEM").getNbQuadraturePoints(type); UInt nb_element = model.getMesh().getNbElement(type, ghost_type); UInt tot_nb_quad = nb_element * nb_quad_per_el; for (UInt q = 0; q < tot_nb_quad; ++q) { for (UInt dim = 0; dim < spatial_dimension; ++dim) { if (!Math::are_float_equal(theoretical_traction_rotated(dim), traction(q, dim))) { std::cout << "Error: tractions are incorrect" << std::endl; return 1; } } if (ghost_type == _not_ghost) if (!Math::are_float_equal(theoretical_damage, damage(q))) { std::cout << "Error: damage is incorrect" << std::endl; return 1; } } } } return 0; } /* -------------------------------------------------------------------------- */ void findNodesToCheck(const Mesh & mesh, const ByElementTypeUInt & elements, Array & nodes_to_check, Int psize) { StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int prank = comm.whoAmI(); nodes_to_check.resize(0); Array global_nodes_to_check; UInt spatial_dimension = mesh.getSpatialDimension(); const Array & position = mesh.getNodes(); UInt nb_nodes = position.getSize(); Array checked_nodes(nb_nodes); checked_nodes.clear(); Mesh::type_iterator it = mesh.firstType(spatial_dimension); Mesh::type_iterator last = mesh.lastType(spatial_dimension); for (; it != last; ++it) { ElementType type = *it; const Array & elem = elements(type); const Array & connectivity = mesh.getConnectivity(type); UInt nb_nodes_per_elem = connectivity.getNbComponent(); for (UInt el = 0; el < elem.getSize(); ++el) { UInt element = elem(el); Vector conn_el(connectivity.storage() + nb_nodes_per_elem * element, nb_nodes_per_elem); for (UInt n = 0; n < nb_nodes_per_elem; ++n) { UInt node = conn_el(n); if (Math::are_float_equal(position(node, 0), 0.) && !checked_nodes(node)) { checked_nodes(node) = true; nodes_to_check.push_back(node); global_nodes_to_check.push_back(mesh.getNodeGlobalId(node)); } } } } std::vector requests; for (Int p = prank + 1; p < psize; ++p) { requests.push_back(comm.asyncSend(global_nodes_to_check.storage(), global_nodes_to_check.getSize(), p, prank)); } Array recv_nodes; for (Int p = 0; p < prank; ++p) { CommunicationStatus status; comm.probe(p, p, status); UInt recv_nodes_size = recv_nodes.getSize(); recv_nodes.resize(recv_nodes_size + status.getSize()); comm.receive(recv_nodes.storage() + recv_nodes_size, status.getSize(), p, p); } comm.waitAll(requests); comm.freeCommunicationRequest(requests); for (UInt i = 0; i < recv_nodes.getSize(); ++i) { Array::iterator node_position = std::find(global_nodes_to_check.begin(), global_nodes_to_check.end(), recv_nodes(i)); if (node_position != global_nodes_to_check.end()) { UInt index = node_position - global_nodes_to_check.begin(); nodes_to_check.erase(index); global_nodes_to_check.erase(index); } } } /* -------------------------------------------------------------------------- */ bool checkEquilibrium(const Mesh & mesh, const Array & residual) { UInt spatial_dimension = residual.getNbComponent(); Vector residual_sum(spatial_dimension); residual_sum.clear(); Array::const_iterator > res_it = residual.begin(spatial_dimension); for (UInt n = 0; n < residual.getSize(); ++n, ++res_it) { if (mesh.isLocalOrMasterNode(n)) residual_sum += *res_it; } StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); comm.allReduce(residual_sum.storage(), spatial_dimension, _so_sum); for (UInt s = 0; s < spatial_dimension; ++s) { if (!Math::are_float_equal(residual_sum(s), 0.)) { if (comm.whoAmI() == 0) std::cout << "Error: system is not in equilibrium!" << std::endl; return 1; } } return 0; } /* -------------------------------------------------------------------------- */ bool checkResidual(const Array & residual, const Vector & traction, const Array & nodes_to_check, const Matrix & rotation) { UInt spatial_dimension = residual.getNbComponent(); Vector total_force(spatial_dimension); total_force.clear(); for (UInt n = 0; n < nodes_to_check.getSize(); ++n) { UInt node = nodes_to_check(n); Vector res(residual.storage() + node * spatial_dimension, spatial_dimension); total_force += res; } StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); comm.allReduce(total_force.storage(), spatial_dimension, _so_sum); Vector theoretical_total_force(spatial_dimension); theoretical_total_force.mul(rotation, traction); theoretical_total_force *= -1 * 2 * 2; for (UInt s = 0; s < spatial_dimension; ++s) { if (!Math::are_float_equal(total_force(s), theoretical_total_force(s))) { if (comm.whoAmI() == 0) std::cout << "Error: total force isn't correct!" << std::endl; return 1; } } return 0; } /* -------------------------------------------------------------------------- */ void findElementsToDisplace(const Mesh & mesh, ByElementTypeUInt & elements) { UInt spatial_dimension = mesh.getSpatialDimension(); mesh.initByElementTypeArray(elements, 1, spatial_dimension); Vector bary(spatial_dimension); for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; Mesh::type_iterator it = mesh.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last = mesh.lastType(spatial_dimension, ghost_type); for (; it != last; ++it) { ElementType type = *it; Array & elem = elements(type, ghost_type); UInt nb_element = mesh.getNbElement(type, ghost_type); for (UInt el = 0; el < nb_element; ++el) { mesh.getBarycenter(el, type, bary.storage(), ghost_type); if (bary(0) > 0.0001) elem.push_back(el); } } } }