diff --git a/src/common/aka_safe_enum.hh b/src/common/aka_safe_enum.hh index ab8c4928f..20af59899 100644 --- a/src/common/aka_safe_enum.hh +++ b/src/common/aka_safe_enum.hh @@ -1,83 +1,83 @@ /** * @file aka_safe_enum.hh * * @author Nicolas Richart * * @date creation: Thu Feb 21 2013 * @date last modification: Sun Oct 19 2014 * * @brief Safe enums type (see More C++ Idioms/Type Safe Enum on Wikibooks * http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Type_Safe_Enum) * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_AKA_SAFE_ENUM_HH__ #define __AKANTU_AKA_SAFE_ENUM_HH__ namespace akantu { /// Safe enumerated type template class safe_enum : public def { using type = typename def::type; public: - explicit safe_enum(type v) : val(v) {} + explicit safe_enum(type v = def::_end_) : val(v) {} inner underlying() const { return val; } bool operator == (const safe_enum & s) const { return this->val == s.val; } bool operator != (const safe_enum & s) const { return this->val != s.val; } bool operator < (const safe_enum & s) const { return this->val < s.val; } bool operator <= (const safe_enum & s) const { return this->val <= s.val; } bool operator > (const safe_enum & s) const { return this->val > s.val; } bool operator >= (const safe_enum & s) const { return this->val >= s.val; } operator inner() { return val; }; public: // Works only if enumerations are contiguous. class iterator { public: explicit iterator(type v) : it(v) { } iterator & operator++() { ++it; return *this; } safe_enum operator*() { return safe_enum(static_cast(it)); } bool operator!=(iterator const & it) { return it.it != this->it; } private: int it; }; static iterator begin() { return iterator(def::_begin_); } static iterator end() { return iterator(def::_end_); } protected: inner val; }; } // akantu #endif /* __AKANTU_AKA_SAFE_ENUM_HH__ */ diff --git a/src/fe_engine/shape_lagrange_base.cc b/src/fe_engine/shape_lagrange_base.cc index 5f6c79c3d..12c7fb0d8 100644 --- a/src/fe_engine/shape_lagrange_base.cc +++ b/src/fe_engine/shape_lagrange_base.cc @@ -1,126 +1,161 @@ /** * @file shape_lagrange_base.cc * * @author Nicolas Richart * * @date creation Thu Jul 27 2017 * * @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_lagrange_base.hh" #include "mesh_iterators.hh" /* -------------------------------------------------------------------------- */ namespace akantu { ShapeLagrangeBase::ShapeLagrangeBase(const Mesh & mesh, const ElementKind & kind, const ID & id, const MemoryID & memory_id) : ShapeFunctions(mesh, id, memory_id), shapes("shapes_generic", id, memory_id), shapes_derivatives("shapes_derivatives_generic", id, memory_id), _kind(kind) {} /* -------------------------------------------------------------------------- */ ShapeLagrangeBase::~ShapeLagrangeBase() = default; +/* -------------------------------------------------------------------------- */ +#define AKANTU_COMPUTE_SHAPES(type) \ + _this.template computeShapesOnIntegrationPoints( \ + nodes, integration_points, shapes, ghost_type, filter_elements) + +namespace shape_lagrange { + namespace details { + template struct Helper { + template + static void call(const S &, const Array &, const Matrix &, + Array &, const ElementType &, const GhostType &, + const Array &) { + AKANTU_DEBUG_TO_IMPLEMENT(); + } + }; + +#define AKANTU_COMPUTE_SHAPES_KIND(kind) \ + template <> struct Helper { \ + template \ + static void call(const S & _this, const Array & nodes, \ + const Matrix & integration_points, \ + Array & shapes, const ElementType & type, \ + const GhostType & ghost_type, \ + const Array & filter_elements) { \ + AKANTU_BOOST_KIND_ELEMENT_SWITCH(AKANTU_COMPUTE_SHAPES, kind); \ + } \ + }; + + AKANTU_BOOST_ALL_KIND_LIST(AKANTU_COMPUTE_SHAPES_KIND, + AKANTU_FE_ENGINE_LIST_LAGRANGE_BASE) + + } // namespace details +} // namespace shape_lagrange + /* -------------------------------------------------------------------------- */ void ShapeLagrangeBase::computeShapesOnIntegrationPoints( const Array & nodes, const Matrix & integration_points, Array & shapes, const ElementType & type, const GhostType & ghost_type, const Array & filter_elements) const { -#define AKANTU_COMPUTE_SHAPES(type) \ - this->computeShapesOnIntegrationPoints( \ - nodes, integration_points, shapes, ghost_type, filter_elements) -#define AKANTU_COMPUTE_SHAPES_KIND(kind) \ - AKANTU_BOOST_KIND_ELEMENT_SWITCH(AKANTU_COMPUTE_SHAPES, kind); + auto kind = Mesh::getKind(type); + +#define AKANTU_COMPUTE_SHAPES_KIND_SWITCH(kind) \ + shape_lagrange::details::Helper::call( \ + *this, nodes, integration_points, shapes, type, ghost_type, \ + filter_elements); - AKANTU_BOOST_ALL_KIND_LIST( - AKANTU_COMPUTE_SHAPES_KIND, - AKANTU_FE_ENGINE_LIST_LAGRANGE_BASE) + AKANTU_BOOST_LIST_SWITCH( + AKANTU_COMPUTE_SHAPES_KIND_SWITCH, + BOOST_PP_LIST_TO_SEQ(AKANTU_FE_ENGINE_LIST_LAGRANGE_BASE), kind); #undef AKANTU_COMPUTE_SHAPES #undef AKANTU_COMPUTE_SHAPES_KIND - //#undef AKANTU_LAGRANGE_ELEMENT_TYPE +#undef AKANTU_COMPUTE_SHAPES_KIND_SWITCH } /* -------------------------------------------------------------------------- */ void ShapeLagrangeBase::onElementsAdded(const Array & new_elements) { AKANTU_DEBUG_IN(); const auto & nodes = mesh.getNodes(); for (auto elements_range : MeshElementsByTypes(new_elements)) { auto type = elements_range.getType(); auto ghost_type = elements_range.getGhostType(); if (mesh.getKind(type) != _kind) continue; auto & elements = elements_range.getElements(); auto itp_type = FEEngine::getInterpolationType(type); if (not this->shapes_derivatives.exists(itp_type, ghost_type)) { auto size_of_shapesd = this->getShapeDerivativesSize(type); this->shapes_derivatives.alloc(0, size_of_shapesd, itp_type, ghost_type); } if (not shapes.exists(itp_type, ghost_type)) { auto size_of_shapes = this->getShapeSize(type); this->shapes.alloc(0, size_of_shapes, itp_type, ghost_type); } const auto & natural_coords = integration_points(type, ghost_type); computeShapesOnIntegrationPoints(nodes, natural_coords, shapes(itp_type, ghost_type), type, ghost_type, elements); computeShapeDerivativesOnIntegrationPoints( nodes, natural_coords, shapes_derivatives(itp_type, ghost_type), type, ghost_type, elements); } #undef INIT_SHAPE_FUNCTIONS AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ShapeLagrangeBase::onElementsRemoved( const Array &, const ElementTypeMapArray & new_numbering) { this->shapes.onElementsRemoved(new_numbering); this->shapes_derivatives.onElementsRemoved(new_numbering); } /* -------------------------------------------------------------------------- */ void ShapeLagrangeBase::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "Shapes Lagrange [" << std::endl; ShapeFunctions::printself(stream, indent + 1); shapes.printself(stream, indent + 1); shapes_derivatives.printself(stream, indent + 1); stream << space << "]" << std::endl; } } // namespace akantu diff --git a/src/fe_engine/shape_lagrange_base.hh b/src/fe_engine/shape_lagrange_base.hh index ca6e4759c..675215fb5 100644 --- a/src/fe_engine/shape_lagrange_base.hh +++ b/src/fe_engine/shape_lagrange_base.hh @@ -1,111 +1,114 @@ + /** * @file shape_lagrange_base.hh * * @author Nicolas Richart * * @date creation Thu Jul 27 2017 * * @brief Base class for the shape lagrange * * @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_functions.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SHAPE_LAGRANGE_BASE_HH__ #define __AKANTU_SHAPE_LAGRANGE_BASE_HH__ namespace akantu { class ShapeLagrangeBase : public ShapeFunctions { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: - ShapeLagrangeBase(const Mesh & mesh, const ElementKind &kind, const ID & id = "shape_lagrange", + ShapeLagrangeBase(const Mesh & mesh, const ElementKind & kind, + const ID & id = "shape_lagrange", const MemoryID & memory_id = 0); virtual ~ShapeLagrangeBase(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// computes the shape functions for given interpolation points virtual void computeShapesOnIntegrationPoints( const Array & nodes, const Matrix & integration_points, Array & shapes, const ElementType & type, const GhostType & ghost_type, const Array & filter_elements = empty_filter) const; /// computes the shape functions derivatives for given interpolation points virtual void computeShapeDerivativesOnIntegrationPoints( const Array & nodes, const Matrix & integration_points, Array & shape_derivatives, const ElementType & type, const GhostType & ghost_type, const Array & filter_elements = empty_filter) const = 0; /// function to print the containt of the class void printself(std::ostream & stream, int indent = 0) const override; template void computeShapesOnIntegrationPoints( - const Array &, const Matrix & integration_points, + const Array & nodes, const Matrix & integration_points, Array & shapes, const GhostType & ghost_type, const Array & filter_elements = empty_filter) const; public: void onElementsAdded(const Array & elements) override; void onElementsRemoved(const Array & elements, const ElementTypeMapArray & new_numbering) override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get a the shapes vector inline const Array & getShapes(const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get a the shapes derivatives vector inline const Array & getShapesDerivatives(const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; + /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// shape functions for all elements ElementTypeMapArray shapes; /// shape functions derivatives for all elements ElementTypeMapArray shapes_derivatives; /// The kind to consider ElementKind _kind; }; } // namespace akantu #include "shape_lagrange_base_inline_impl.cc" #endif /* __AKANTU_SHAPE_LAGRANGE_BASE_HH__ */ diff --git a/src/io/mesh_io/mesh_io_msh.cc b/src/io/mesh_io/mesh_io_msh.cc index 8532b0ee6..4fb0f54bc 100644 --- a/src/io/mesh_io/mesh_io_msh.cc +++ b/src/io/mesh_io/mesh_io_msh.cc @@ -1,975 +1,971 @@ /** * @file mesh_io_msh.cc * * @author Dana Christen * @author Mauro Corrado * @author David Simon Kammer * @author Nicolas Richart * * @date creation: Fri Jun 18 2010 * @date last modification: Thu Jan 21 2016 * * @brief Read/Write for MSH files generated by gmsh * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* ----------------------------------------------------------------------------- Version (Legacy) 1.0 $NOD number-of-nodes node-number x-coord y-coord z-coord ... $ENDNOD $ELM number-of-elements elm-number elm-type reg-phys reg-elem number-of-nodes node-number-list ... $ENDELM ----------------------------------------------------------------------------- Version 2.1 $MeshFormat version-number file-type data-size $EndMeshFormat $Nodes number-of-nodes node-number x-coord y-coord z-coord ... $EndNodes $Elements number-of-elements elm-number elm-type number-of-tags < tag > ... node-number-list ... $EndElements $PhysicalNames number-of-names physical-dimension physical-number "physical-name" ... $EndPhysicalNames $NodeData number-of-string-tags < "string-tag" > ... number-of-real-tags < real-tag > ... number-of-integer-tags < integer-tag > ... node-number value ... ... $EndNodeData $ElementData number-of-string-tags < "string-tag" > ... number-of-real-tags < real-tag > ... number-of-integer-tags < integer-tag > ... elm-number value ... ... $EndElementData $ElementNodeData number-of-string-tags < "string-tag" > ... number-of-real-tags < real-tag > ... number-of-integer-tags < integer-tag > ... elm-number number-of-nodes-per-element value ... ... $ElementEndNodeData ----------------------------------------------------------------------------- elem-type 1: 2-node line. 2: 3-node triangle. 3: 4-node quadrangle. 4: 4-node tetrahedron. 5: 8-node hexahedron. 6: 6-node prism. 7: 5-node pyramid. 8: 3-node second order line 9: 6-node second order triangle 10: 9-node second order quadrangle 11: 10-node second order tetrahedron 12: 27-node second order hexahedron 13: 18-node second order prism 14: 14-node second order pyramid 15: 1-node point. 16: 8-node second order quadrangle 17: 20-node second order hexahedron 18: 15-node second order prism 19: 13-node second order pyramid 20: 9-node third order incomplete triangle 21: 10-node third order triangle 22: 12-node fourth order incomplete triangle 23: 15-node fourth order triangle 24: 15-node fifth order incomplete triangle 25: 21-node fifth order complete triangle 26: 4-node third order edge 27: 5-node fourth order edge 28: 6-node fifth order edge 29: 20-node third order tetrahedron 30: 35-node fourth order tetrahedron 31: 56-node fifth order tetrahedron -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #include "mesh_io.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ // The boost spirit is a work on the way it does not compile so I kept the // current code. The current code does not handle files generated on Windows // // #include // #include // #include // #include // #include // #include // #include // #include // #include /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /* Methods Implentations */ /* -------------------------------------------------------------------------- */ MeshIOMSH::MeshIOMSH() { canReadSurface = true; canReadExtendedData = true; _msh_nodes_per_elem[_msh_not_defined] = 0; _msh_nodes_per_elem[_msh_segment_2] = 2; _msh_nodes_per_elem[_msh_triangle_3] = 3; _msh_nodes_per_elem[_msh_quadrangle_4] = 4; _msh_nodes_per_elem[_msh_tetrahedron_4] = 4; _msh_nodes_per_elem[_msh_hexahedron_8] = 8; _msh_nodes_per_elem[_msh_prism_1] = 6; _msh_nodes_per_elem[_msh_pyramid_1] = 1; _msh_nodes_per_elem[_msh_segment_3] = 3; _msh_nodes_per_elem[_msh_triangle_6] = 6; _msh_nodes_per_elem[_msh_quadrangle_9] = 9; _msh_nodes_per_elem[_msh_tetrahedron_10] = 10; _msh_nodes_per_elem[_msh_hexahedron_27] = 27; _msh_nodes_per_elem[_msh_hexahedron_20] = 20; _msh_nodes_per_elem[_msh_prism_18] = 18; _msh_nodes_per_elem[_msh_prism_15] = 15; _msh_nodes_per_elem[_msh_pyramid_14] = 14; _msh_nodes_per_elem[_msh_point] = 1; _msh_nodes_per_elem[_msh_quadrangle_8] = 8; _msh_to_akantu_element_types[_msh_not_defined] = _not_defined; _msh_to_akantu_element_types[_msh_segment_2] = _segment_2; _msh_to_akantu_element_types[_msh_triangle_3] = _triangle_3; _msh_to_akantu_element_types[_msh_quadrangle_4] = _quadrangle_4; _msh_to_akantu_element_types[_msh_tetrahedron_4] = _tetrahedron_4; _msh_to_akantu_element_types[_msh_hexahedron_8] = _hexahedron_8; _msh_to_akantu_element_types[_msh_prism_1] = _pentahedron_6; _msh_to_akantu_element_types[_msh_pyramid_1] = _not_defined; _msh_to_akantu_element_types[_msh_segment_3] = _segment_3; _msh_to_akantu_element_types[_msh_triangle_6] = _triangle_6; _msh_to_akantu_element_types[_msh_quadrangle_9] = _not_defined; _msh_to_akantu_element_types[_msh_tetrahedron_10] = _tetrahedron_10; _msh_to_akantu_element_types[_msh_hexahedron_27] = _not_defined; _msh_to_akantu_element_types[_msh_hexahedron_20] = _hexahedron_20; _msh_to_akantu_element_types[_msh_prism_18] = _not_defined; _msh_to_akantu_element_types[_msh_prism_15] = _pentahedron_15; _msh_to_akantu_element_types[_msh_pyramid_14] = _not_defined; _msh_to_akantu_element_types[_msh_point] = _point_1; _msh_to_akantu_element_types[_msh_quadrangle_8] = _quadrangle_8; _akantu_to_msh_element_types[_not_defined] = _msh_not_defined; _akantu_to_msh_element_types[_segment_2] = _msh_segment_2; _akantu_to_msh_element_types[_segment_3] = _msh_segment_3; _akantu_to_msh_element_types[_triangle_3] = _msh_triangle_3; _akantu_to_msh_element_types[_triangle_6] = _msh_triangle_6; _akantu_to_msh_element_types[_tetrahedron_4] = _msh_tetrahedron_4; _akantu_to_msh_element_types[_tetrahedron_10] = _msh_tetrahedron_10; _akantu_to_msh_element_types[_quadrangle_4] = _msh_quadrangle_4; _akantu_to_msh_element_types[_quadrangle_8] = _msh_quadrangle_8; _akantu_to_msh_element_types[_hexahedron_8] = _msh_hexahedron_8; _akantu_to_msh_element_types[_hexahedron_20] = _msh_hexahedron_20; _akantu_to_msh_element_types[_pentahedron_6] = _msh_prism_1; _akantu_to_msh_element_types[_pentahedron_15] = _msh_prism_15; _akantu_to_msh_element_types[_point_1] = _msh_point; #if defined(AKANTU_STRUCTURAL_MECHANICS) _akantu_to_msh_element_types[_bernoulli_beam_2] = _msh_segment_2; _akantu_to_msh_element_types[_bernoulli_beam_3] = _msh_segment_2; _akantu_to_msh_element_types[_kirchhoff_shell] = _msh_triangle_3; #endif std::map::iterator it; for (it = _akantu_to_msh_element_types.begin(); it != _akantu_to_msh_element_types.end(); ++it) { UInt nb_nodes = _msh_nodes_per_elem[it->second]; std::vector tmp(nb_nodes); for (UInt i = 0; i < nb_nodes; ++i) { tmp[i] = i; } switch (it->first) { case _tetrahedron_10: tmp[8] = 9; tmp[9] = 8; break; case _pentahedron_6: tmp[0] = 2; tmp[1] = 0; tmp[2] = 1; tmp[3] = 5; tmp[4] = 3; tmp[5] = 4; break; case _pentahedron_15: tmp[0] = 2; tmp[1] = 0; tmp[2] = 1; tmp[3] = 5; tmp[4] = 3; tmp[5] = 4; tmp[6] = 8; tmp[8] = 11; tmp[9] = 6; tmp[10] = 9; tmp[11] = 10; tmp[12] = 14; tmp[14] = 12; break; case _hexahedron_20: tmp[9] = 11; tmp[10] = 12; tmp[11] = 9; tmp[12] = 13; tmp[13] = 10; tmp[17] = 19; tmp[18] = 17; tmp[19] = 18; break; default: // nothing to change break; } _read_order[it->first] = tmp; } } /* -------------------------------------------------------------------------- */ MeshIOMSH::~MeshIOMSH() {} /* -------------------------------------------------------------------------- */ /* Spirit stuff */ /* -------------------------------------------------------------------------- */ // namespace _parser { // namespace spirit = ::boost::spirit; // namespace qi = ::boost::spirit::qi; // namespace ascii = ::boost::spirit::ascii; // namespace lbs = ::boost::spirit::qi::labels; // namespace phx = ::boost::phoenix; // /* ------------------------------------------------------------------------ // */ // /* Lazy functors */ // /* ------------------------------------------------------------------------ // */ // struct _Element { // int index; // std::vector tags; // std::vector connectivity; // ElementType type; // }; // /* ------------------------------------------------------------------------ // */ // struct lazy_get_nb_nodes_ { // template struct result { typedef int type; }; // template bool operator()(elem_type et) { // return MeshIOMSH::_msh_nodes_per_elem[et]; // } // }; // /* ------------------------------------------------------------------------ // */ // struct lazy_element_ { // template // struct result { // typedef _Element type; // }; // template // _Element operator()(id_t id, const elem_type & et, const tags_t & t, // const conn_t & c) { // _Element tmp_el; // tmp_el.index = id; // tmp_el.tags = t; // tmp_el.connectivity = c; // tmp_el.type = et; // return tmp_el; // } // }; // /* ------------------------------------------------------------------------ // */ // struct lazy_check_value_ { // template struct result { typedef void type; }; // template void operator()(T v1, T v2) { // if (v1 != v2) { // AKANTU_EXCEPTION("The msh parser expected a " // << v2 << " in the header bug got a " << v1); // } // } // }; // /* ------------------------------------------------------------------------ // */ // struct lazy_node_read_ { // template // struct result { // typedef bool type; // }; // template // bool operator()(Mesh & mesh, const ID & id, const V & pos, size max, // Map & nodes_mapping) const { // Vector tmp_pos(mesh.getSpatialDimension()); // UInt i = 0; // for (typename V::const_iterator it = pos.begin(); // it != pos.end() || i < mesh.getSpatialDimension(); ++it) // tmp_pos[i++] = *it; // nodes_mapping[id] = mesh.getNbNodes(); // mesh.getNodes().push_back(tmp_pos); // return (mesh.getNbNodes() < UInt(max)); // } // }; // /* ------------------------------------------------------------------------ // */ // struct lazy_element_read_ { // template // struct result { // typedef bool type; // }; // template // bool operator()(Mesh & mesh, const EL & element, size max, // const NodeMap & nodes_mapping, // ElemMap & elements_mapping) const { // Vector tmp_conn(Mesh::getNbNodesPerElement(element.type)); // AKANTU_DEBUG_ASSERT(element.connectivity.size() == tmp_conn.size(), // "The element " // << element.index // << "in the MSH file has too many nodes."); // mesh.addConnectivityType(element.type); // Array & connectivity = mesh.getConnectivity(element.type); // UInt i = 0; // for (std::vector::const_iterator it = // element.connectivity.begin(); // it != element.connectivity.end(); ++it) { // typename NodeMap::const_iterator nit = nodes_mapping.find(*it); // AKANTU_DEBUG_ASSERT(nit != nodes_mapping.end(), // "There is an unknown node in the connectivity."); // tmp_conn[i++] = nit->second; // } // ::akantu::Element el(element.type, connectivity.size()); // elements_mapping[element.index] = el; // connectivity.push_back(tmp_conn); // for (UInt i = 0; i < element.tags.size(); ++i) { // std::stringstream tag_sstr; // tag_sstr << "tag_" << i; // Array * data = // mesh.template getDataPointer(tag_sstr.str(), element.type, // _not_ghost); // data->push_back(element.tags[i]); // } // return (mesh.getNbElement() < UInt(max)); // } // }; // /* ------------------------------------------------------------------------ // */ // template // struct MshMeshGrammar : qi::grammar { // public: // MshMeshGrammar(Mesh & mesh) // : MshMeshGrammar::base_type(start, "msh_mesh_reader"), mesh(mesh) { // phx::function lazy_element; // phx::function lazy_get_nb_nodes; // phx::function lazy_check_value; // phx::function lazy_node_read; // phx::function lazy_element_read; // clang-format off // start // = *( known_section | unknown_section // ) // ; // known_section // = qi::char_("$") // >> sections [ lbs::_a = lbs::_1 ] // >> qi::lazy(*lbs::_a) // >> qi::lit("$End") // //>> qi::lit(phx::ref(lbs::_a)) // ; // unknown_section // = qi::char_("$") // >> qi::char_("") [ lbs::_a = lbs::_1 ] // >> ignore_section // >> qi::lit("$End") // >> qi::lit(phx::val(lbs::_a)) // ; // mesh_format // version followed by 0 or 1 for ascii or binary // = version >> ( // ( qi::char_("0") // >> qi::int_ [ lazy_check_value(lbs::_1, 8) ] // ) // | ( qi::char_("1") // >> qi::int_ [ lazy_check_value(lbs::_1, 8) ] // >> qi::dword [ lazy_check_value(lbs::_1, 1) ] // ) // ) // ; // nodes // = nodes_ // ; // nodes_ // = qi::int_ [ lbs::_a = lbs::_1 ] // > *( // ( qi::int_ >> position ) [ lazy_node_read(phx::ref(mesh), // lbs::_1, // phx::cref(lbs::_2), // lbs::_a, // phx::ref(this->msh_nodes_to_akantu)) ] // ) // ; // element // = elements_ // ; // elements_ // = qi::int_ [ lbs::_a = lbs::_1 ] // > qi::repeat(phx::ref(lbs::_a))[ element [ lazy_element_read(phx::ref(mesh), // lbs::_1, // phx::cref(lbs::_a), // phx::cref(this->msh_nodes_to_akantu), // phx::ref(this->msh_elemt_to_akantu)) ]] // ; // ignore_section // = *(qi::char_ - qi::char_('$')) // ; // interpolation_scheme = ignore_section; // element_data = ignore_section; // node_data = ignore_section; // version // = qi::int_ [ phx::push_back(lbs::_val, lbs::_1) ] // >> *( qi::char_(".") >> qi::int_ [ phx::push_back(lbs::_val, lbs::_1) ] ) // ; // position // = real [ phx::push_back(lbs::_val, lbs::_1) ] // > real [ phx::push_back(lbs::_val, lbs::_1) ] // > real [ phx::push_back(lbs::_val, lbs::_1) ] // ; // tags // = qi::int_ [ lbs::_a = lbs::_1 ] // > qi::repeat(phx::val(lbs::_a))[ qi::int_ [ phx::push_back(lbs::_val, // lbs::_1) ] ] // ; // element // = ( qi::int_ [ lbs::_a = lbs::_1 ] // > msh_element_type [ lbs::_b = lazy_get_nb_nodes(lbs::_1) ] // > tags [ lbs::_c = lbs::_1 ] // > connectivity(lbs::_a) [ lbs::_d = lbs::_1 ] // ) [ lbs::_val = lazy_element(lbs::_a, // phx::cref(lbs::_b), // phx::cref(lbs::_c), // phx::cref(lbs::_d)) ] // ; // connectivity // = qi::repeat(lbs::_r1)[ qi::int_ [ phx::push_back(lbs::_val, // lbs::_1) ] ] // ; // sections.add // ("MeshFormat", &mesh_format) // ("Nodes", &nodes) // ("Elements", &elements) // ("PhysicalNames", &physical_names) // ("InterpolationScheme", &interpolation_scheme) // ("ElementData", &element_data) // ("NodeData", &node_data); // msh_element_type.add // ("0" , _not_defined ) // ("1" , _segment_2 ) // ("2" , _triangle_3 ) // ("3" , _quadrangle_4 ) // ("4" , _tetrahedron_4 ) // ("5" , _hexahedron_8 ) // ("6" , _pentahedron_6 ) // ("7" , _not_defined ) // ("8" , _segment_3 ) // ("9" , _triangle_6 ) // ("10", _not_defined ) // ("11", _tetrahedron_10) // ("12", _not_defined ) // ("13", _not_defined ) // ("14", _hexahedron_20 ) // ("15", _pentahedron_15) // ("16", _not_defined ) // ("17", _point_1 ) // ("18", _quadrangle_8 ); // mesh_format .name("MeshFormat" ); // nodes .name("Nodes" ); // elements .name("Elements" ); // physical_names .name("PhysicalNames" ); // interpolation_scheme.name("InterpolationScheme"); // element_data .name("ElementData" ); // node_data .name("NodeData" ); // clang-format on // } // /* ---------------------------------------------------------------------- // */ // /* Rules */ // /* ---------------------------------------------------------------------- // */ // private: // qi::symbols msh_element_type; // qi::symbols *> sections; // qi::rule start; // qi::rule > // unknown_section; // qi::rule *> > known_section; // qi::rule mesh_format, nodes, elements, // physical_names, ignore_section, // interpolation_scheme, element_data, node_data, any_line; // qi::rule > nodes_; // qi::rule, // vector > > elements_; // qi::rule(), Skipper> version; // qi::rule > // element; // qi::rule(), Skipper, qi::locals > tags; // qi::rule(int), Skipper> connectivity; // qi::rule(), Skipper> position; // qi::real_parser > real; // /* ---------------------------------------------------------------------- // */ // /* Members */ // /* ---------------------------------------------------------------------- // */ // private: // /// reference to the mesh to read // Mesh & mesh; // /// correspondance between the numbering of nodes in the abaqus file and // in // /// the akantu mesh // std::map msh_nodes_to_akantu; // /// correspondance between the element number in the abaqus file and the // /// Element in the akantu mesh // std::map msh_elemt_to_akantu; // }; // } // /* -------------------------------------------------------------------------- // */ // void MeshIOAbaqus::read(const std::string& filename, Mesh& mesh) { // namespace qi = boost::spirit::qi; // namespace ascii = boost::spirit::ascii; // std::ifstream infile; // infile.open(filename.c_str()); // if(!infile.good()) { // AKANTU_DEBUG_ERROR("Cannot open file " << filename); // } // std::string storage; // We will read the contents here. // infile.unsetf(std::ios::skipws); // No white space skipping! // std::copy(std::istream_iterator(infile), // std::istream_iterator(), // std::back_inserter(storage)); // typedef std::string::const_iterator iterator_t; // typedef ascii::space_type skipper; // typedef _parser::MshMeshGrammar grammar; // grammar g(mesh); // skipper ws; // iterator_t iter = storage.begin(); // iterator_t end = storage.end(); // qi::phrase_parse(iter, end, g, ws); // this->setNbGlobalNodes(mesh, mesh.getNodes().size()); // MeshUtils::fillElementToSubElementsData(mesh); // } static void my_getline(std::ifstream & infile, std::string & str) { std::string tmp_str; std::getline(infile, tmp_str); str = trim(tmp_str); } /* -------------------------------------------------------------------------- */ void MeshIOMSH::read(const std::string & filename, Mesh & mesh) { MeshAccessor mesh_accessor(mesh); std::ifstream infile; infile.open(filename.c_str()); std::string line; UInt first_node_number = std::numeric_limits::max(), last_node_number = 0, file_format = 1, current_line = 0; bool has_physical_names = false; if (!infile.good()) { AKANTU_DEBUG_ERROR("Cannot open file " << filename); } while (infile.good()) { my_getline(infile, line); current_line++; /// read the header if (line == "$MeshFormat") { my_getline(infile, line); /// the format line std::stringstream sstr(line); std::string version; sstr >> version; Int format; sstr >> format; if (format != 0) AKANTU_DEBUG_ERROR("This reader can only read ASCII files."); my_getline(infile, line); /// the end of block line current_line += 2; file_format = 2; } /// read the physical names if (line == "$PhysicalNames") { has_physical_names = true; my_getline(infile, line); /// the format line std::stringstream sstr(line); UInt num_of_phys_names; sstr >> num_of_phys_names; for (UInt k(0); k < num_of_phys_names; k++) { my_getline(infile, line); std::stringstream sstr_phys_name(line); UInt phys_name_id; UInt phys_dim; sstr_phys_name >> phys_dim >> phys_name_id; std::size_t b = line.find("\""); std::size_t e = line.rfind("\""); std::string phys_name = line.substr(b + 1, e - b - 1); phys_name_map[phys_name_id] = phys_name; } } /// read all nodes if (line == "$Nodes" || line == "$NOD") { UInt nb_nodes; my_getline(infile, line); std::stringstream sstr(line); sstr >> nb_nodes; current_line++; Array & nodes = mesh_accessor.getNodes(); nodes.resize(nb_nodes); mesh_accessor.setNbGlobalNodes(nb_nodes); UInt index; Real coord[3]; UInt spatial_dimension = nodes.getNbComponent(); /// for each node, read the coordinates for (UInt i = 0; i < nb_nodes; ++i) { UInt offset = i * spatial_dimension; my_getline(infile, line); std::stringstream sstr_node(line); sstr_node >> index >> coord[0] >> coord[1] >> coord[2]; current_line++; first_node_number = std::min(first_node_number, index); last_node_number = std::max(last_node_number, index); /// read the coordinates for (UInt j = 0; j < spatial_dimension; ++j) nodes.storage()[offset + j] = coord[j]; } my_getline(infile, line); /// the end of block line } /// read all elements if (line == "$Elements" || line == "$ELM") { UInt nb_elements; std::vector read_order; my_getline(infile, line); std::stringstream sstr(line); sstr >> nb_elements; current_line++; Int index; UInt msh_type; ElementType akantu_type, akantu_type_old = _not_defined; Array * connectivity = NULL; UInt node_per_element = 0; for (UInt i = 0; i < nb_elements; ++i) { my_getline(infile, line); std::stringstream sstr_elem(line); current_line++; sstr_elem >> index; sstr_elem >> msh_type; /// get the connectivity vector depending on the element type akantu_type = this->_msh_to_akantu_element_types[(MSHElementType)msh_type]; if (akantu_type == _not_defined) { AKANTU_DEBUG_WARNING("Unsuported element kind " << msh_type << " at line " << current_line); continue; } if (akantu_type != akantu_type_old) { connectivity = &mesh_accessor.getConnectivity(akantu_type); // connectivity->resize(0); node_per_element = connectivity->getNbComponent(); akantu_type_old = akantu_type; read_order = this->_read_order[akantu_type]; } /// read tags informations if (file_format == 2) { UInt nb_tags; sstr_elem >> nb_tags; for (UInt j = 0; j < nb_tags; ++j) { Int tag; sstr_elem >> tag; std::stringstream sstr_tag_name; sstr_tag_name << "tag_" << j; Array & data = mesh.getDataPointer( sstr_tag_name.str(), akantu_type, _not_ghost); data.push_back(tag); } } else if (file_format == 1) { Int tag; sstr_elem >> tag; // reg-phys std::string tag_name = "tag_0"; Array * data = &mesh.getDataPointer(tag_name, akantu_type, _not_ghost); data->push_back(tag); sstr_elem >> tag; // reg-elem tag_name = "tag_1"; data = &mesh.getDataPointer(tag_name, akantu_type, _not_ghost); data->push_back(tag); sstr_elem >> tag; // number-of-nodes } Vector local_connect(node_per_element); for (UInt j = 0; j < node_per_element; ++j) { UInt node_index; sstr_elem >> node_index; AKANTU_DEBUG_ASSERT(node_index <= last_node_number, "Node number not in range : line " << current_line); node_index -= first_node_number; local_connect(read_order[j]) = node_index; } connectivity->push_back(local_connect); } my_getline(infile, line); /// the end of block line } if ((line[0] == '$') && (line.find("End") == std::string::npos)) { AKANTU_DEBUG_WARNING("Unsuported block_kind " << line << " at line " << current_line); } } // mesh.updateTypesOffsets(_not_ghost); infile.close(); this->constructPhysicalNames("tag_0", mesh); if (has_physical_names) mesh.createGroupsFromMeshData("physical_names"); MeshUtils::fillElementToSubElementsData(mesh); } /* -------------------------------------------------------------------------- */ void MeshIOMSH::write(const std::string & filename, const Mesh & mesh) { std::ofstream outfile; const Array & nodes = mesh.getNodes(); outfile.open(filename.c_str()); outfile << "$MeshFormat" << std::endl; outfile << "2.1 0 8" << std::endl; outfile << "$EndMeshFormat" << std::endl; outfile << std::setprecision(std::numeric_limits::digits10); outfile << "$Nodes" << std::endl; outfile << nodes.size() << std::endl; outfile << std::uppercase; for (UInt i = 0; i < nodes.size(); ++i) { Int offset = i * nodes.getNbComponent(); outfile << i + 1; for (UInt j = 0; j < nodes.getNbComponent(); ++j) { outfile << " " << nodes.storage()[offset + j]; } for (UInt p = nodes.getNbComponent(); p < 3; ++p) outfile << " " << 0.; outfile << std::endl; ; } outfile << std::nouppercase; outfile << "$EndNodes" << std::endl; ; outfile << "$Elements" << std::endl; ; Int nb_elements = 0; for (auto && type : mesh.elementTypes(_all_dimensions, _not_ghost, _ek_not_defined)) { const Array & connectivity = mesh.getConnectivity(type, _not_ghost); nb_elements += connectivity.size(); } outfile << nb_elements << std::endl; UInt element_idx = 1; for (auto && type : mesh.elementTypes(_all_dimensions, _not_ghost, _ek_not_defined)) { const auto & connectivity = mesh.getConnectivity(type, _not_ghost); UInt * tag[2] = {nullptr, nullptr}; - try { + if (mesh.hasData("tag_0", type, _not_ghost)) { const auto & data_tag_0 = mesh.getData("tag_0", type, _not_ghost); tag[0] = data_tag_0.storage(); - } catch (...) { - tag[0] = nullptr; } - try { + if (mesh.hasData("tag_1", type, _not_ghost)) { const auto & data_tag_1 = mesh.getData("tag_1", type, _not_ghost); tag[1] = data_tag_1.storage(); - } catch (...) { - tag[1] = nullptr; } for (UInt i = 0; i < connectivity.size(); ++i) { UInt offset = i * connectivity.getNbComponent(); outfile << element_idx << " " << _akantu_to_msh_element_types[type] << " 2"; /// \todo write the real data in the file for (UInt t = 0; t < 2; ++t) if (tag[t]) outfile << " " << tag[t][i]; else outfile << " 0"; for (UInt j = 0; j < connectivity.getNbComponent(); ++j) { outfile << " " << connectivity.storage()[offset + j] + 1; } outfile << std::endl; element_idx++; } } outfile << "$EndElements" << std::endl; ; outfile.close(); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/mesh/element_type_map.hh b/src/mesh/element_type_map.hh index 438683f5c..cee03fd5a 100644 --- a/src/mesh/element_type_map.hh +++ b/src/mesh/element_type_map.hh @@ -1,391 +1,393 @@ /** * @file element_type_map.hh * * @author Nicolas Richart * * @date creation: Wed Aug 31 2011 * @date last modification: Fri Oct 02 2015 * * @brief storage class by element type * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_memory.hh" #include "aka_named_argument.hh" +#include "element.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_TYPE_MAP_HH__ #define __AKANTU_ELEMENT_TYPE_MAP_HH__ namespace akantu { class FEEngine; } // namespace akantu namespace akantu { template class ElementTypeMap; /* -------------------------------------------------------------------------- */ /* ElementTypeMapBase */ /* -------------------------------------------------------------------------- */ /// Common non templated base class for the ElementTypeMap class class ElementTypeMapBase { public: virtual ~ElementTypeMapBase(){}; }; /* -------------------------------------------------------------------------- */ /* ElementTypeMap */ /* -------------------------------------------------------------------------- */ template class ElementTypeMap : public ElementTypeMapBase { public: ElementTypeMap(); ~ElementTypeMap(); inline static std::string printType(const SupportType & type, const GhostType & ghost_type); /*! Tests whether a type is present in the object * @param type the type to check for * @param ghost_type optional: by default, the data map for non-ghost * elements is searched * @return true if the type is present. */ inline bool exists(const SupportType & type, const GhostType & ghost_type = _not_ghost) const; /*! get the stored data corresponding to a type * @param type the type to check for * @param ghost_type optional: by default, the data map for non-ghost * elements is searched * @return stored data corresponding to type. */ inline const Stored & operator()(const SupportType & type, const GhostType & ghost_type = _not_ghost) const; /*! get the stored data corresponding to a type * @param type the type to check for * @param ghost_type optional: by default, the data map for non-ghost * elements is searched * @return stored data corresponding to type. */ inline Stored & operator()(const SupportType & type, const GhostType & ghost_type = _not_ghost); /*! insert data of a new type (not yet present) into the map. THIS METHOD IS * NOT ARRAY SAFE, when using ElementTypeMapArray, use setArray instead * @param data to insert * @param type type of data (if this type is already present in the map, * an exception is thrown). * @param ghost_type optional: by default, the data map for non-ghost * elements is searched * @return stored data corresponding to type. */ inline Stored & operator()(const Stored & insert, const SupportType & type, const GhostType & ghost_type = _not_ghost); /// print helper virtual void printself(std::ostream & stream, int indent = 0) const; /* ------------------------------------------------------------------------ */ /* Element type Iterator */ /* ------------------------------------------------------------------------ */ /*! iterator allows to iterate over type-data pairs of the map. The interface * expects the SupportType to be ElementType. */ typedef std::map DataMap; class type_iterator : private std::iterator { public: typedef const SupportType value_type; typedef const SupportType * pointer; typedef const SupportType & reference; protected: typedef typename ElementTypeMap::DataMap::const_iterator DataMapIterator; public: type_iterator(DataMapIterator & list_begin, DataMapIterator & list_end, UInt dim, ElementKind ek); type_iterator(const type_iterator & it); type_iterator() {} inline reference operator*(); inline reference operator*() const; inline type_iterator & operator++(); type_iterator operator++(int); inline bool operator==(const type_iterator & other) const; inline bool operator!=(const type_iterator & other) const; type_iterator & operator=(const type_iterator & other); private: DataMapIterator list_begin; DataMapIterator list_end; UInt dim; ElementKind kind; }; /// helper class to use in range for constructions class ElementTypesIteratorHelper { public: using Container = ElementTypeMap; using iterator = typename Container::type_iterator; ElementTypesIteratorHelper(const Container & container, UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) : container(std::cref(container)), dim(dim), ghost_type(ghost_type), kind(kind) {} ElementTypesIteratorHelper(const ElementTypesIteratorHelper &) = default; ElementTypesIteratorHelper & operator=(const ElementTypesIteratorHelper &) = default; ElementTypesIteratorHelper & operator=(ElementTypesIteratorHelper &&) = default; iterator begin() { return container.get().firstType(dim, ghost_type, kind); } iterator end() { return container.get().lastType(dim, ghost_type, kind); } private: std::reference_wrapper container; UInt dim; GhostType ghost_type; ElementKind kind; }; /// method to create the helper class to use in range for constructs ElementTypesIteratorHelper elementTypes(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) const; /*! Get an iterator to the beginning of a subset datamap. This method expects * the SupportType to be ElementType. * @param dim optional: iterate over data of dimension dim (e.g. when * iterating over (surface) facets of a 3D mesh, dim would be 2). * by default, all dimensions are considered. * @param ghost_type optional: by default, the data map for non-ghost * elements is iterated over. * @param kind optional: the kind of element to search for (see * aka_common.hh), by default all kinds are considered * @return an iterator to the first stored data matching the filters * or an iterator to the end of the map if none match*/ inline type_iterator firstType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_not_defined) const; /*! Get an iterator to the end of a subset datamap. This method expects * the SupportType to be ElementType. * @param dim optional: iterate over data of dimension dim (e.g. when * iterating over (surface) facets of a 3D mesh, dim would be 2). * by default, all dimensions are considered. * @param ghost_type optional: by default, the data map for non-ghost * elements is iterated over. * @param kind optional: the kind of element to search for (see * aka_common.hh), by default all kinds are considered * @return an iterator to the last stored data matching the filters * or an iterator to the end of the map if none match */ inline type_iterator lastType(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_not_defined) const; protected: /*! Direct access to the underlying data map. for internal use by daughter * classes only * @param ghost_type whether to return the data map or the ghost_data map * @return the raw map */ inline DataMap & getData(GhostType ghost_type); /*! Direct access to the underlying data map. for internal use by daughter * classes only * @param ghost_type whether to return the data map or the ghost_data map * @return the raw map */ inline const DataMap & getData(GhostType ghost_type) const; /* ------------------------------------------------------------------------ */ protected: DataMap data; DataMap ghost_data; }; /* -------------------------------------------------------------------------- */ /* Some typedefs */ /* -------------------------------------------------------------------------- */ template class ElementTypeMapArray : public ElementTypeMap *, SupportType>, public Memory { public: - typedef T type; - typedef Array array_type; + using type = T; + using array_type = Array; protected: - typedef ElementTypeMap *, SupportType> parent; - typedef typename parent::DataMap DataMap; - -private: -private: - /// standard assigment (copy) operator - void operator=(const ElementTypeMap &){}; + using parent = ElementTypeMap *, SupportType>; + using DataMap = typename parent::DataMap; public: using type_iterator = typename parent::type_iterator; + /// standard assigment (copy) operator + void operator=(const ElementTypeMapArray &) = delete; + ElementTypeMapArray(const ElementTypeMapArray &) = delete; + /*! Constructor * @param id optional: identifier (string) * @param parent_id optional: parent identifier. for organizational purposes * only * @param memory_id optional: choose a specific memory, defaults to memory 0 */ ElementTypeMapArray(const ID & id = "by_element_type_array", const ID & parent_id = "no_parent", const MemoryID & memory_id = 0) : parent(), Memory(parent_id + ":" + id, memory_id), name(id){}; /*! allocate memory for a new array * @param size number of tuples of the new array * @param nb_component tuple size * @param type the type under which the array is indexed in the map * @param ghost_type whether to add the field to the data map or the * ghost_data map * @return a reference to the allocated array */ inline Array & alloc(UInt size, UInt nb_component, const SupportType & type, const GhostType & ghost_type, const T & default_value = T()); /*! allocate memory for a new array in both the data and the ghost_data map * @param size number of tuples of the new array * @param nb_component tuple size * @param type the type under which the array is indexed in the map*/ inline void alloc(UInt size, UInt nb_component, const SupportType & type, const T & default_value = T()); /* get a reference to the array of certain type * @param type data filed under type is returned * @param ghost_type optional: by default the non-ghost map is searched * @return a reference to the array */ inline const Array & operator()(const SupportType & type, const GhostType & ghost_type = _not_ghost) const; + /// access the data of an element, this combine the map and array accessor + inline const T & operator()(const Element & element) const; + + /// access the data of an element, this combine the map and array accessor + inline T & operator()(const Element & element); + /* get a reference to the array of certain type * @param type data filed under type is returned * @param ghost_type optional: by default the non-ghost map is searched * @return a const reference to the array */ inline Array & operator()(const SupportType & type, const GhostType & ghost_type = _not_ghost); /*! insert data of a new type (not yet present) into the map. * @param type type of data (if this type is already present in the map, * an exception is thrown). * @param ghost_type optional: by default, the data map for non-ghost * elements is searched * @param vect the vector to include into the map * @return stored data corresponding to type. */ inline void setArray(const SupportType & type, const GhostType & ghost_type, const Array & vect); /*! frees all memory related to the data*/ inline void free(); /*! set all values in the ElementTypeMap to zero*/ inline void clear(); /*! deletes and reorders entries in the stored arrays * @param new_numbering a ElementTypeMapArray of new indices. UInt(-1) * indicates * deleted entries. */ inline void onElementsRemoved(const ElementTypeMapArray & new_numbering); /// text output helper virtual void printself(std::ostream & stream, int indent = 0) const; /*! set the id * @param id the new name */ inline void setID(const ID & id) { this->id = id; } ElementTypeMap getNbComponents(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_not_defined) const { ElementTypeMap nb_components; for (auto & type : this->elementTypes(dim, ghost_type, kind)) { UInt nb_comp = (*this)(type, ghost_type).getNbComponent(); nb_components(type, ghost_type) = nb_comp; } return nb_components; } /* ------------------------------------------------------------------------ */ /* more evolved allocators */ /* ------------------------------------------------------------------------ */ public: /// initialize the arrays in accordance to a functor template void initialize(const Func & f, const T & default_value = T()); /// initialize with sizes and number of components in accordance of a mesh /// content template void initialize(const Mesh & mesh, pack &&... _pack); /// initialize with sizes and number of components in accordance of a fe /// engine content (aka integration points) template void initialize(const FEEngine & fe_engine, pack &&... _pack); /* ------------------------------------------------------------------------ */ /* Accesssors */ /* ------------------------------------------------------------------------ */ public: /// get the name of the internal field AKANTU_GET_MACRO(Name, name, ID); -private: - ElementTypeMapArray operator=(__attribute__((unused)) - const ElementTypeMapArray & other){}; - /// name of the elment type map: e.g. connectivity, grad_u ID name; }; /// to store data Array by element type -typedef ElementTypeMapArray ElementTypeMapReal; +using ElementTypeMapReal = ElementTypeMapArray; /// to store data Array by element type -typedef ElementTypeMapArray ElementTypeMapInt; +using ElementTypeMapInt = ElementTypeMapArray; /// to store data Array by element type -typedef ElementTypeMapArray ElementTypeMapUInt; +using ElementTypeMapUInt = ElementTypeMapArray; /// Map of data of type UInt stored in a mesh -typedef std::map *> UIntDataMap; -typedef ElementTypeMap ElementTypeMapUIntDataMap; +using UIntDataMap = std::map *>; +using ElementTypeMapUIntDataMap = ElementTypeMap; } // namespace akantu #endif /* __AKANTU_ELEMENT_TYPE_MAP_HH__ */ diff --git a/src/mesh/element_type_map_tmpl.hh b/src/mesh/element_type_map_tmpl.hh index 5152fbbeb..e045aa0e3 100644 --- a/src/mesh/element_type_map_tmpl.hh +++ b/src/mesh/element_type_map_tmpl.hh @@ -1,632 +1,633 @@ /** * @file element_type_map_tmpl.hh * * @author Nicolas Richart * * @date creation: Wed Aug 31 2011 * @date last modification: Fri Oct 02 2015 * * @brief implementation of template functions of the ElementTypeMap and * ElementTypeMapArray classes * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "element_type_map.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #include "element_type_conversion.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_TYPE_MAP_TMPL_HH__ #define __AKANTU_ELEMENT_TYPE_MAP_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ /* ElementTypeMap */ /* -------------------------------------------------------------------------- */ template inline std::string ElementTypeMap::printType(const SupportType & type, const GhostType & ghost_type) { std::stringstream sstr; sstr << "(" << ghost_type << ":" << type << ")"; return sstr.str(); } /* -------------------------------------------------------------------------- */ template inline bool ElementTypeMap::exists( const SupportType & type, const GhostType & ghost_type) const { return this->getData(ghost_type).find(type) != this->getData(ghost_type).end(); } /* -------------------------------------------------------------------------- */ template inline const Stored & ElementTypeMap:: operator()(const SupportType & type, const GhostType & ghost_type) const { - typename DataMap::const_iterator it = this->getData(ghost_type).find(type); + auto it = this->getData(ghost_type).find(type); if (it == this->getData(ghost_type).end()) AKANTU_SILENT_EXCEPTION("No element of type " << ElementTypeMap::printType(type, ghost_type) << " in this ElementTypeMap<" << debug::demangle(typeid(Stored).name()) << "> class"); return it->second; } /* -------------------------------------------------------------------------- */ template inline Stored & ElementTypeMap:: operator()(const SupportType & type, const GhostType & ghost_type) { return this->getData(ghost_type)[type]; } /* -------------------------------------------------------------------------- */ template inline Stored & ElementTypeMap:: operator()(const Stored & insert, const SupportType & type, const GhostType & ghost_type) { - typename DataMap::iterator it = this->getData(ghost_type).find(type); + auto it = this->getData(ghost_type).find(type); if (it != this->getData(ghost_type).end()) { AKANTU_SILENT_EXCEPTION("Element of type " << ElementTypeMap::printType(type, ghost_type) << " already in this ElementTypeMap<" << debug::demangle(typeid(Stored).name()) << "> class"); } else { - DataMap & data = this->getData(ghost_type); - const std::pair & res = + auto & data = this->getData(ghost_type); + const auto & res = data.insert(std::pair(type, insert)); it = res.first; } return it->second; } /* -------------------------------------------------------------------------- */ template inline typename ElementTypeMap::DataMap & ElementTypeMap::getData(GhostType ghost_type) { if (ghost_type == _not_ghost) return data; - else - return ghost_data; + + return ghost_data; } /* -------------------------------------------------------------------------- */ template inline const typename ElementTypeMap::DataMap & ElementTypeMap::getData(GhostType ghost_type) const { if (ghost_type == _not_ghost) return data; - else - return ghost_data; + + return ghost_data; } /* -------------------------------------------------------------------------- */ /// Works only if stored is a pointer to a class with a printself method template void ElementTypeMap::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "ElementTypeMap<" << debug::demangle(typeid(Stored).name()) << "> [" << std::endl; for (auto gt : ghost_types) { const DataMap & data = getData(gt); for (auto & pair : data) { stream << space << space << ElementTypeMap::printType(pair.first, gt) << std::endl; } } + stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ template -ElementTypeMap::ElementTypeMap() { - AKANTU_DEBUG_IN(); - - // std::stringstream sstr; - // if(parent_id != "") sstr << parent_id << ":"; - // sstr << id; - - // this->id = sstr.str(); - - AKANTU_DEBUG_OUT(); -} +ElementTypeMap::ElementTypeMap() = default; /* -------------------------------------------------------------------------- */ template -ElementTypeMap::~ElementTypeMap() {} +ElementTypeMap::~ElementTypeMap() = default; /* -------------------------------------------------------------------------- */ /* ElementTypeMapArray */ /* -------------------------------------------------------------------------- */ template inline Array & ElementTypeMapArray::alloc( UInt size, UInt nb_component, const SupportType & type, const GhostType & ghost_type, const T & default_value) { std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; Array * tmp; - typename ElementTypeMapArray::DataMap::iterator it = - this->getData(ghost_type).find(type); + auto it = this->getData(ghost_type).find(type); if (it == this->getData(ghost_type).end()) { std::stringstream sstr; sstr << this->id << ":" << type << ghost_id; tmp = &(Memory::alloc(sstr.str(), size, nb_component, default_value)); std::stringstream sstrg; sstrg << ghost_type; // tmp->setTag(sstrg.str()); this->getData(ghost_type)[type] = tmp; } else { AKANTU_DEBUG_INFO( "The vector " << this->id << this->printType(type, ghost_type) << " already exists, it is resized instead of allocated."); tmp = it->second; it->second->resize(size); } return *tmp; } /* -------------------------------------------------------------------------- */ template inline void ElementTypeMapArray::alloc(UInt size, UInt nb_component, const SupportType & type, const T & default_value) { this->alloc(size, nb_component, type, _not_ghost, default_value); this->alloc(size, nb_component, type, _ghost, default_value); } /* -------------------------------------------------------------------------- */ template inline void ElementTypeMapArray::free() { AKANTU_DEBUG_IN(); - for (auto gt : ghost_types) { - DataMap & data = this->getData(gt); + for (auto && gt : ghost_types) { + auto & data = this->getData(gt); for (auto & pair : data) { dealloc(pair.second->getID()); } data.clear(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template inline void ElementTypeMapArray::clear() { for (auto gt : ghost_types) { - DataMap & data = this->getData(gt); + auto & data = this->getData(gt); for (auto & vect : data) { vect.second->clear(); } } } /* -------------------------------------------------------------------------- */ template inline const Array & ElementTypeMapArray:: operator()(const SupportType & type, const GhostType & ghost_type) const { - typename ElementTypeMapArray::DataMap::const_iterator it = - this->getData(ghost_type).find(type); + auto it = this->getData(ghost_type).find(type); if (it == this->getData(ghost_type).end()) AKANTU_SILENT_EXCEPTION("No element of type " << ElementTypeMapArray::printType(type, ghost_type) << " in this const ElementTypeMapArray<" << debug::demangle(typeid(T).name()) << "> class(\"" << this->id << "\")"); return *(it->second); } /* -------------------------------------------------------------------------- */ template inline Array & ElementTypeMapArray:: operator()(const SupportType & type, const GhostType & ghost_type) { - typename ElementTypeMapArray::DataMap::iterator it = - this->getData(ghost_type).find(type); + auto it = this->getData(ghost_type).find(type); if (it == this->getData(ghost_type).end()) AKANTU_SILENT_EXCEPTION("No element of type " << ElementTypeMapArray::printType(type, ghost_type) << " in this ElementTypeMapArray<" << debug::demangle(typeid(T).name()) << "> class (\"" << this->id << "\")"); return *(it->second); } /* -------------------------------------------------------------------------- */ template inline void ElementTypeMapArray::setArray(const SupportType & type, const GhostType & ghost_type, const Array & vect) { - typename ElementTypeMapArray::DataMap::iterator it = - this->getData(ghost_type).find(type); + auto it = this->getData(ghost_type).find(type); if (AKANTU_DEBUG_TEST(dblWarning) && it != this->getData(ghost_type).end() && it->second != &vect) { AKANTU_DEBUG_WARNING( "The Array " << this->printType(type, ghost_type) << " is already registred, this call can lead to a memory leak."); } this->getData(ghost_type)[type] = &(const_cast &>(vect)); } /* -------------------------------------------------------------------------- */ template inline void ElementTypeMapArray::onElementsRemoved( const ElementTypeMapArray & new_numbering) { for (auto gt : ghost_types) { for (auto & type : new_numbering.elementTypes(_all_dimensions, gt, _ek_not_defined)) { SupportType support_type = convertType(type); if (this->exists(support_type, gt)) { const auto & renumbering = new_numbering(type, gt); if (renumbering.size() == 0) continue; auto & vect = this->operator()(support_type, gt); auto nb_component = vect.getNbComponent(); Array tmp(renumbering.size(), nb_component); UInt new_size = 0; for (UInt i = 0; i < vect.size(); ++i) { UInt new_i = renumbering(i); if (new_i != UInt(-1)) { memcpy(tmp.storage() + new_i * nb_component, vect.storage() + i * nb_component, nb_component * sizeof(T)); ++new_size; } } tmp.resize(new_size); vect.copy(tmp); } } } } /* -------------------------------------------------------------------------- */ template void ElementTypeMapArray::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "ElementTypeMapArray<" << debug::demangle(typeid(T).name()) << "> [" << std::endl; for (UInt g = _not_ghost; g <= _ghost; ++g) { GhostType gt = (GhostType)g; const DataMap & data = this->getData(gt); typename DataMap::const_iterator it; for (it = data.begin(); it != data.end(); ++it) { stream << space << space << ElementTypeMapArray::printType(it->first, gt) << " [" << std::endl; it->second->printself(stream, indent + 3); stream << space << space << " ]" << std::endl; } } stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ /* SupportType Iterator */ /* -------------------------------------------------------------------------- */ template ElementTypeMap::type_iterator::type_iterator( DataMapIterator & list_begin, DataMapIterator & list_end, UInt dim, ElementKind ek) : list_begin(list_begin), list_end(list_end), dim(dim), kind(ek) {} /* -------------------------------------------------------------------------- */ template ElementTypeMap::type_iterator::type_iterator( const type_iterator & it) : list_begin(it.list_begin), list_end(it.list_end), dim(it.dim), kind(it.kind) {} /* -------------------------------------------------------------------------- */ template typename ElementTypeMap::type_iterator & ElementTypeMap::type_iterator:: operator=(const type_iterator & it) { if (this != &it) { list_begin = it.list_begin; list_end = it.list_end; dim = it.dim; kind = it.kind; } return *this; } /* -------------------------------------------------------------------------- */ template inline typename ElementTypeMap::type_iterator::reference ElementTypeMap::type_iterator::operator*() { return list_begin->first; } /* -------------------------------------------------------------------------- */ template inline typename ElementTypeMap::type_iterator::reference ElementTypeMap::type_iterator::operator*() const { return list_begin->first; } /* -------------------------------------------------------------------------- */ template inline typename ElementTypeMap::type_iterator & ElementTypeMap::type_iterator::operator++() { ++list_begin; while ((list_begin != list_end) && (((dim != _all_dimensions) && (dim != Mesh::getSpatialDimension(list_begin->first))) || ((kind != _ek_not_defined) && (kind != Mesh::getKind(list_begin->first))))) ++list_begin; return *this; } /* -------------------------------------------------------------------------- */ template typename ElementTypeMap::type_iterator ElementTypeMap::type_iterator::operator++(int) { type_iterator tmp(*this); operator++(); return tmp; } /* -------------------------------------------------------------------------- */ template inline bool ElementTypeMap::type_iterator:: operator==(const type_iterator & other) const { return this->list_begin == other.list_begin; } /* -------------------------------------------------------------------------- */ template inline bool ElementTypeMap::type_iterator:: operator!=(const type_iterator & other) const { return this->list_begin != other.list_begin; } /* -------------------------------------------------------------------------- */ template typename ElementTypeMap::ElementTypesIteratorHelper ElementTypeMap::elementTypes(UInt dim, GhostType ghost_type, ElementKind kind) const { return ElementTypesIteratorHelper(*this, dim, ghost_type, kind); } /* -------------------------------------------------------------------------- */ template inline typename ElementTypeMap::type_iterator ElementTypeMap::firstType(UInt dim, GhostType ghost_type, ElementKind kind) const { typename DataMap::const_iterator b, e; b = getData(ghost_type).begin(); e = getData(ghost_type).end(); // loop until the first valid type while ((b != e) && (((dim != _all_dimensions) && (dim != Mesh::getSpatialDimension(b->first))) || ((kind != _ek_not_defined) && (kind != Mesh::getKind(b->first))))) ++b; return typename ElementTypeMap::type_iterator(b, e, dim, kind); } /* -------------------------------------------------------------------------- */ template inline typename ElementTypeMap::type_iterator ElementTypeMap::lastType(UInt dim, GhostType ghost_type, ElementKind kind) const { typename DataMap::const_iterator e; e = getData(ghost_type).end(); return typename ElementTypeMap::type_iterator(e, e, dim, kind); } /* -------------------------------------------------------------------------- */ /// standard output stream operator template inline std::ostream & operator<<(std::ostream & stream, const ElementTypeMap & _this) { _this.printself(stream); return stream; } /* -------------------------------------------------------------------------- */ class ElementTypeMapArrayInializer { public: ElementTypeMapArrayInializer(UInt spatial_dimension = _all_dimensions, UInt nb_component = 1, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_regular) : spatial_dimension(spatial_dimension), nb_component(nb_component), ghost_type(ghost_type), element_kind(element_kind) {} const GhostType & ghostType() const { return ghost_type; } protected: UInt spatial_dimension; UInt nb_component; GhostType ghost_type; ElementKind element_kind; }; /* -------------------------------------------------------------------------- */ class MeshElementTypeMapArrayInializer : public ElementTypeMapArrayInializer { public: MeshElementTypeMapArrayInializer( const Mesh & mesh, UInt nb_component = 1, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_regular, bool with_nb_element = false, bool with_nb_nodes_per_element = false) : ElementTypeMapArrayInializer(spatial_dimension, nb_component, ghost_type, element_kind), mesh(mesh), with_nb_element(with_nb_element), with_nb_nodes_per_element(with_nb_nodes_per_element) {} decltype(auto) elementTypes() const { return mesh.elementTypes(this->spatial_dimension, this->ghost_type, this->element_kind); } virtual UInt size(const ElementType & type) const { if (with_nb_element) return mesh.getNbElement(type, this->ghost_type); return 0; } UInt nbComponent(const ElementType & type) const { if (with_nb_nodes_per_element) return (this->nb_component * mesh.getNbNodesPerElement(type)); return this->nb_component; } protected: const Mesh & mesh; bool with_nb_element; bool with_nb_nodes_per_element; }; /* -------------------------------------------------------------------------- */ class FEEngineElementTypeMapArrayInializer : public MeshElementTypeMapArrayInializer { public: FEEngineElementTypeMapArrayInializer( const FEEngine & fe_engine, UInt nb_component = 1, UInt spatial_dimension = _all_dimensions, const GhostType & ghost_type = _not_ghost, const ElementKind & element_kind = _ek_regular); UInt size(const ElementType & type) const override; using ElementTypesIteratorHelper = ElementTypeMapArray::ElementTypesIteratorHelper; ElementTypesIteratorHelper elementTypes() const; protected: const FEEngine & fe_engine; }; /* -------------------------------------------------------------------------- */ template template void ElementTypeMapArray::initialize(const Func & f, const T & default_value) { for (auto & type : f.elementTypes()) { if (not this->exists(type, f.ghostType())) this->alloc(f.size(type), f.nbComponent(type), type, f.ghostType(), default_value); } } namespace { DECLARE_NAMED_ARGUMENT(all_ghost_types); DECLARE_NAMED_ARGUMENT(default_value); DECLARE_NAMED_ARGUMENT(element_kind); DECLARE_NAMED_ARGUMENT(ghost_type); DECLARE_NAMED_ARGUMENT(nb_component); DECLARE_NAMED_ARGUMENT(with_nb_element); DECLARE_NAMED_ARGUMENT(with_nb_nodes_per_element); DECLARE_NAMED_ARGUMENT(spatial_dimension); } // namespace /* -------------------------------------------------------------------------- */ template template void ElementTypeMapArray::initialize(const Mesh & mesh, pack &&... _pack) { GhostType requested_ghost_type = OPTIONAL_NAMED_ARG(ghost_type, _casper); bool all_ghost_types = requested_ghost_type == _casper; for (auto ghost_type : ghost_types) { if ((not(ghost_type == requested_ghost_type)) and (not all_ghost_types)) continue; this->initialize( MeshElementTypeMapArrayInializer( mesh, OPTIONAL_NAMED_ARG(nb_component, 1), OPTIONAL_NAMED_ARG(spatial_dimension, mesh.getSpatialDimension()), ghost_type, OPTIONAL_NAMED_ARG(element_kind, _ek_regular), OPTIONAL_NAMED_ARG(with_nb_element, false), OPTIONAL_NAMED_ARG(with_nb_nodes_per_element, false)), OPTIONAL_NAMED_ARG(default_value, T())); } } /* -------------------------------------------------------------------------- */ template template void ElementTypeMapArray::initialize(const FEEngine & fe_engine, pack &&... _pack) { bool all_ghost_types = OPTIONAL_NAMED_ARG(all_ghost_types, true); GhostType requested_ghost_type = OPTIONAL_NAMED_ARG(ghost_type, _not_ghost); for (auto ghost_type : ghost_types) { if ((not(ghost_type == requested_ghost_type)) and (not all_ghost_types)) continue; this->initialize(FEEngineElementTypeMapArrayInializer( fe_engine, OPTIONAL_NAMED_ARG(nb_component, 1), OPTIONAL_NAMED_ARG(spatial_dimension, UInt(-2)), ghost_type, OPTIONAL_NAMED_ARG(element_kind, _ek_regular)), OPTIONAL_NAMED_ARG(default_value, T())); } } +/* -------------------------------------------------------------------------- */ +template +inline T & ElementTypeMapArray:: +operator()(const Element & element) { + return this->operator()(element.type, element.ghost_type)(element.element); +} + +/* -------------------------------------------------------------------------- */ +template +inline const T & ElementTypeMapArray:: +operator()(const Element & element) const { + return this->operator()(element.type, element.ghost_type)(element.element); +} + } // namespace akantu #endif /* __AKANTU_ELEMENT_TYPE_MAP_TMPL_HH__ */ diff --git a/src/mesh/mesh.cc b/src/mesh/mesh.cc index 2f6c5d2fc..4ecde762f 100644 --- a/src/mesh/mesh.cc +++ b/src/mesh/mesh.cc @@ -1,445 +1,476 @@ /** * @file mesh.cc * * @author Guillaume Anciaux * @author David Simon Kammer * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Fri Jun 18 2010 * @date last modification: Fri Jan 22 2016 * * @brief class handling meshes * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include #include "aka_config.hh" /* -------------------------------------------------------------------------- */ #include "element_class.hh" #include "group_manager_inline_impl.cc" #include "mesh.hh" #include "mesh_io.hh" /* -------------------------------------------------------------------------- */ #include "element_synchronizer.hh" #include "mesh_utils_distribution.hh" #include "node_synchronizer.hh" #include "static_communicator.hh" /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER #include "dumper_field.hh" #include "dumper_internal_material_field.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { const Element ElementNull(_not_defined, 0); /* -------------------------------------------------------------------------- */ void Element::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "Element [" << type << ", " << element << ", " << ghost_type << "]"; } /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, const ID & id, const MemoryID & memory_id, StaticCommunicator & communicator) : Memory(id, memory_id), GroupManager(*this, id + ":group_manager", memory_id), nodes_type(0, 1, id + ":nodes_type"), connectivities("connectivities", id, memory_id), + ghosts_counters("ghosts_counters", id, memory_id), normals("normals", id, memory_id), spatial_dimension(spatial_dimension), lower_bounds(spatial_dimension, 0.), upper_bounds(spatial_dimension, 0.), size(spatial_dimension, 0.), local_lower_bounds(spatial_dimension, 0.), local_upper_bounds(spatial_dimension, 0.), mesh_data("mesh_data", id, memory_id), communicator(&communicator) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, StaticCommunicator & communicator, const ID & id, const MemoryID & memory_id) : Mesh(spatial_dimension, id, memory_id, communicator) { AKANTU_DEBUG_IN(); this->nodes = std::make_shared>(0, spatial_dimension, id + ":coordinates"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, const ID & id, const MemoryID & memory_id) : Mesh(spatial_dimension, StaticCommunicator::getStaticCommunicator(), id, memory_id) {} -// /* -------------------------------------------------------------------------- -// */ Mesh::Mesh(UInt spatial_dimension, const ID & nodes_id, const ID & id, -// const MemoryID & memory_id) -// : Mesh(spatial_dimension, id, memory_id, -// StaticCommunicator::getStaticCommunicator()) { -// this->nodes = &(this->getArray(nodes_id)); -// this->nb_global_nodes = this->nodes->size(); -// this->computeBoundingBox(); -// } - /* -------------------------------------------------------------------------- */ Mesh::Mesh(UInt spatial_dimension, std::shared_ptr> nodes, const ID & id, const MemoryID & memory_id) : Mesh(spatial_dimension, id, memory_id, StaticCommunicator::getStaticCommunicator()) { this->nodes = nodes; this->nb_global_nodes = this->nodes->size(); this->nodes_to_elements.resize(nodes->size()); for (auto & node_set : nodes_to_elements) { node_set = std::make_unique>(); } this->computeBoundingBox(); } /* -------------------------------------------------------------------------- */ Mesh & Mesh::initMeshFacets(const ID & id) { AKANTU_DEBUG_IN(); if (!mesh_facets) { mesh_facets = std::make_unique(spatial_dimension, this->nodes, getID() + ":" + id, getMemoryID()); mesh_facets->mesh_parent = this; mesh_facets->is_mesh_facets = true; } AKANTU_DEBUG_OUT(); return *mesh_facets; } /* -------------------------------------------------------------------------- */ void Mesh::defineMeshParent(const Mesh & mesh) { AKANTU_DEBUG_IN(); this->mesh_parent = &mesh; this->is_mesh_facets = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Mesh::~Mesh() = default; /* -------------------------------------------------------------------------- */ void Mesh::read(const std::string & filename, const MeshIOType & mesh_io_type) { MeshIO mesh_io; mesh_io.read(filename, *this, mesh_io_type); type_iterator it = this->firstType(spatial_dimension, _not_ghost, _ek_not_defined); type_iterator last = this->lastType(spatial_dimension, _not_ghost, _ek_not_defined); if (it == last) AKANTU_EXCEPTION( "The mesh contained in the file " << filename << " does not seem to be of the good dimension." << " No element of dimension " << spatial_dimension << " where read."); this->nb_global_nodes = this->nodes->size(); this->computeBoundingBox(); this->nodes_to_elements.resize(nodes->size()); for (auto & node_set : nodes_to_elements) { node_set = std::make_unique>(); } } /* -------------------------------------------------------------------------- */ void Mesh::write(const std::string & filename, const MeshIOType & mesh_io_type) { MeshIO mesh_io; mesh_io.write(filename, *this, mesh_io_type); } /* -------------------------------------------------------------------------- */ void Mesh::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "Mesh [" << std::endl; stream << space << " + id : " << getID() << std::endl; stream << space << " + spatial dimension : " << this->spatial_dimension << std::endl; stream << space << " + nodes [" << std::endl; nodes->printself(stream, indent + 2); stream << space << " + connectivities [" << std::endl; connectivities.printself(stream, indent + 2); stream << space << " ]" << std::endl; GroupManager::printself(stream, indent + 1); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ void Mesh::computeBoundingBox() { AKANTU_DEBUG_IN(); for (UInt k = 0; k < spatial_dimension; ++k) { local_lower_bounds(k) = std::numeric_limits::max(); local_upper_bounds(k) = -std::numeric_limits::max(); } for (UInt i = 0; i < nodes->size(); ++i) { // if(!isPureGhostNode(i)) for (UInt k = 0; k < spatial_dimension; ++k) { local_lower_bounds(k) = std::min(local_lower_bounds[k], (*nodes)(i, k)); local_upper_bounds(k) = std::max(local_upper_bounds[k], (*nodes)(i, k)); } } if (this->is_distributed) { StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Matrix reduce_bounds(spatial_dimension, 2); for (UInt k = 0; k < spatial_dimension; ++k) { reduce_bounds(k, 0) = local_lower_bounds(k); reduce_bounds(k, 1) = -local_upper_bounds(k); } comm.allReduce(reduce_bounds, _so_min); for (UInt k = 0; k < spatial_dimension; ++k) { lower_bounds(k) = reduce_bounds(k, 0); upper_bounds(k) = -reduce_bounds(k, 1); } } else { this->lower_bounds = this->local_lower_bounds; this->upper_bounds = this->local_upper_bounds; } size = upper_bounds - lower_bounds; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Mesh::initNormals() { normals.initialize(*this, _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension, _element_kind = _ek_not_defined); } /* -------------------------------------------------------------------------- */ void Mesh::getGlobalConnectivity( ElementTypeMapArray & global_connectivity, UInt dimension, GhostType ghost_type) { AKANTU_DEBUG_IN(); for (auto type : elementTypes(dimension, ghost_type)) { auto & local_conn = connectivities(type, ghost_type); auto & g_connectivity = global_connectivity(type, ghost_type); UInt nb_nodes = local_conn.size() * local_conn.getNbComponent(); if (!nodes_global_ids && is_mesh_facets) { std::transform( local_conn.begin_reinterpret(nb_nodes), local_conn.end_reinterpret(nb_nodes), g_connectivity.begin_reinterpret(nb_nodes), [& node_ids = *mesh_parent->nodes_global_ids](UInt l)->UInt { return node_ids(l); }); } else { std::transform(local_conn.begin_reinterpret(nb_nodes), local_conn.end_reinterpret(nb_nodes), g_connectivity.begin_reinterpret(nb_nodes), [& node_ids = *nodes_global_ids](UInt l)->UInt { return node_ids(l); }); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ DumperIOHelper & Mesh::getGroupDumper(const std::string & dumper_name, const std::string & group_name) { if (group_name == "all") return this->getDumper(dumper_name); else return element_groups[group_name]->getDumper(dumper_name); } /* -------------------------------------------------------------------------- */ template ElementTypeMap Mesh::getNbDataPerElem(ElementTypeMapArray & arrays, const ElementKind & element_kind) { ElementTypeMap nb_data_per_elem; for (auto type : elementTypes(spatial_dimension, _not_ghost, element_kind)) { UInt nb_elements = this->getNbElement(type); auto & array = arrays(type); nb_data_per_elem(type) = array.getNbComponent() * array.size(); nb_data_per_elem(type) /= nb_elements; } return nb_data_per_elem; } /* -------------------------------------------------------------------------- */ template ElementTypeMap Mesh::getNbDataPerElem(ElementTypeMapArray & array, const ElementKind & element_kind); template ElementTypeMap Mesh::getNbDataPerElem(ElementTypeMapArray & array, const ElementKind & element_kind); /* -------------------------------------------------------------------------- */ #ifdef AKANTU_USE_IOHELPER template dumper::Field * Mesh::createFieldFromAttachedData(const std::string & field_id, const std::string & group_name, const ElementKind & element_kind) { dumper::Field * field = nullptr; ElementTypeMapArray * internal = nullptr; try { internal = &(this->getData(field_id)); } catch (...) { return nullptr; } ElementTypeMap nb_data_per_elem = this->getNbDataPerElem(*internal, element_kind); field = this->createElementalField( *internal, group_name, this->spatial_dimension, element_kind, nb_data_per_elem); return field; } template dumper::Field * Mesh::createFieldFromAttachedData(const std::string & field_id, const std::string & group_name, const ElementKind & element_kind); template dumper::Field * Mesh::createFieldFromAttachedData(const std::string & field_id, const std::string & group_name, const ElementKind & element_kind); #endif /* -------------------------------------------------------------------------- */ void Mesh::distribute() { this->distribute(StaticCommunicator::getStaticCommunicator()); } /* -------------------------------------------------------------------------- */ void Mesh::distribute(StaticCommunicator & communicator) { AKANTU_DEBUG_ASSERT(is_distributed == false, "This mesh is already distribute"); this->communicator = &communicator; this->element_synchronizer = std::make_unique( *this, this->getID() + ":element_synchronizer", this->getMemoryID(), true); this->node_synchronizer = std::make_unique( *this, this->getID() + ":node_synchronizer", this->getMemoryID(), true); Int psize = this->communicator->getNbProc(); #ifdef AKANTU_USE_SCOTCH Int prank = this->communicator->whoAmI(); if (prank == 0) { MeshPartitionScotch partition(*this, spatial_dimension); partition.partitionate(psize); MeshUtilsDistribution::distributeMeshCentralized(*this, 0, partition); } else { MeshUtilsDistribution::distributeMeshCentralized(*this, 0); } #else if (!(psize == 1)) { AKANTU_DEBUG_ERROR("Cannot distribute a mesh without a partitioning tool"); } #endif this->is_distributed = true; this->element_synchronizer->buildPrankToElement(); this->computeBoundingBox(); } /* -------------------------------------------------------------------------- */ void Mesh::getAssociatedElements(const Array & node_list, Array & elements) { for (const auto & node : node_list) for (const auto & element : *nodes_to_elements[node]) elements.push_back(element); } /* -------------------------------------------------------------------------- */ void Mesh::fillNodesToElements() { Element e; UInt nb_nodes = nodes->size(); for (UInt n = 0; n < nb_nodes; ++n) { - this->nodes_to_elements[n]->clear(); + if(this->nodes_to_elements[n]) + this->nodes_to_elements[n]->clear(); + else + this->nodes_to_elements[n] = std::make_unique>(); } for (auto ghost_type : ghost_types) { e.ghost_type = ghost_type; for (const auto & type : elementTypes(spatial_dimension, ghost_type, _ek_not_defined)) { e.type = type; e.kind = getKind(type); UInt nb_element = this->getNbElement(type, ghost_type); Array::const_iterator> conn_it = connectivities(type, ghost_type) .begin(Mesh::getNbNodesPerElement(type)); for (UInt el = 0; el < nb_element; ++el, ++conn_it) { e.element = el; const Vector & conn = *conn_it; for (UInt n = 0; n < conn.size(); ++n) nodes_to_elements[conn(n)]->insert(e); } } } } +/* -------------------------------------------------------------------------- */ +void Mesh::eraseElements(const Array & elements) { + ElementTypeMap last_element; + + RemovedElementsEvent event(*this); + auto & remove_list = event.getList(); + auto & new_numbering = event.getNewNumbering(); + + for(auto && el : elements) { + if(el.ghost_type != _not_ghost) { + auto & count = ghosts_counters(el); + --count; + if (count > 0) continue; + } + + remove_list.push_back(el); + if (not last_element.exists(el.type, el.ghost_type)) { + UInt nb_element = mesh.getNbElement(el.type, el.ghost_type); + last_element(nb_element - 1, el.type, el.ghost_type); + auto & numbering = new_numbering.alloc(nb_element, 1, el.type, el.ghost_type); + for (auto && pair : enumerate(numbering)) { + std::get<1>(pair) = std::get<0>(pair); + } + } + + UInt & pos = last_element(el.type, el.ghost_type); + auto & numbering = new_numbering(el.type, el.ghost_type); + + numbering(el.element) = UInt(-1); + numbering(pos) = el.element; + --pos; + } + + this->sendEvent(event); +} + + } // namespace akantu diff --git a/src/mesh/mesh.hh b/src/mesh/mesh.hh index c23eb8552..f595fe475 100644 --- a/src/mesh/mesh.hh +++ b/src/mesh/mesh.hh @@ -1,595 +1,612 @@ /** * @file mesh.hh * * @author Guillaume Anciaux * @author Dana Christen * @author David Simon Kammer * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Fri Jun 18 2010 * @date last modification: Thu Jan 14 2016 * * @brief the class representing the meshes * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_HH__ #define __AKANTU_MESH_HH__ /* -------------------------------------------------------------------------- */ #include "aka_array.hh" #include "aka_event_handler_manager.hh" #include "aka_memory.hh" #include "dumpable.hh" #include "element.hh" #include "element_class.hh" #include "element_type_map.hh" #include "group_manager.hh" #include "mesh_data.hh" #include "mesh_events.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ namespace akantu { class StaticCommunicator; class ElementSynchronizer; class NodeSynchronizer; } // namespace akantu namespace akantu { /* -------------------------------------------------------------------------- */ /* 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. * * 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, public Dumpable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ private: /// default constructor used for chaining, the last parameter is just to /// differentiate constructors Mesh(UInt spatial_dimension, const ID & id, const MemoryID & memory_id, StaticCommunicator & communicator); public: /// constructor that create nodes coordinates array Mesh(UInt spatial_dimension, const ID & id = "mesh", const MemoryID & memory_id = 0); /// mesh not distributed and not using the default communicator Mesh(UInt spatial_dimension, StaticCommunicator & communicator, 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 = 0); /** * constructor that use an existing nodes coordinates * array, by getting the vector of coordinates */ - Mesh(UInt spatial_dimension, std::shared_ptr> nodes, const ID & id = "mesh", - const MemoryID & memory_id = 0); + Mesh(UInt spatial_dimension, std::shared_ptr> 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(); /// function that computes the bounding box (fills xmin, xmax) void computeBoundingBox(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// patitionate the mesh among the processors involved in their computation virtual void distribute(StaticCommunicator & communicator); virtual void distribute(); /// function to print the containt of the class virtual void printself(std::ostream & stream, int indent = 0) const; /// 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); + // 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().size() != 0) EventHandlerManager::sendEvent(event); } + /// prepare the event to remove the elements listed + void eraseElements(const Array & elements); + /* ------------------------------------------------------------------------ */ template inline void removeNodesFromArray(Array & vect, const Array & new_numbering); /// initialize normals void initNormals(); /// init facets' mesh Mesh & initMeshFacets(const ID & id = "mesh_facets"); /// define parent mesh void defineMeshParent(const Mesh & mesh); /// get global connectivity array void getGlobalConnectivity(ElementTypeMapArray & global_connectivity, UInt dimension, GhostType ghost_type); public: void getAssociatedElements(const Array & node_list, Array & elements); private: /// fills the nodes_to_elements structure void fillNodesToElements(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the id of the mesh AKANTU_GET_MACRO(ID, Memory::id, const ID &); /// get the id of the mesh AKANTU_GET_MACRO(MemoryID, Memory::memory_id, const MemoryID &); /// 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->size(), UInt); /// get the Array of global ids of the nodes (only used in parallel) AKANTU_GET_MACRO(GlobalNodesIds, *nodes_global_ids, const Array &); AKANTU_GET_MACRO_NOT_CONST(GlobalNodesIds, *nodes_global_ids, Array &); /// get the global id of a node inline UInt getNodeGlobalId(UInt local_id) const; /// get the global id of a node inline UInt getNodeLocalId(UInt global_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 &); protected: AKANTU_GET_MACRO_NOT_CONST(NodesType, nodes_type, Array &); public: inline NodeType 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(LowerBounds, lower_bounds, const Vector &); AKANTU_GET_MACRO(UpperBounds, upper_bounds, const Vector &); AKANTU_GET_MACRO(LocalLowerBounds, local_lower_bounds, const Vector &); AKANTU_GET_MACRO(LocalUpperBounds, local_upper_bounds, const Vector &); /// 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 ElementTypeMapArray &); /// 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 ElementKind & kind = _ek_not_defined) 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> & getElementToSubelement(const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; /// get the element connected to a subelement Array> & 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); + /// register a new ElementalTypeMap in the MeshData + template + inline ElementTypeMapArray & registerData(const std::string & data_name); + + template + inline bool hasData(const ID & data_name, const ElementType & el_type, + const GhostType & ghost_type = _not_ghost) const; + /// get a name field associated to the mesh template inline const Array & - getData(const std::string & data_name, const ElementType & el_type, + getData(const ID & 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, + inline Array & getData(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost); - /// register a new ElementalTypeMap in the MeshData - template - inline ElementTypeMapArray & registerData(const std::string & data_name); - /// get a name field associated to the mesh template - inline const ElementTypeMapArray & - getData(const std::string & data_name) const; + inline const ElementTypeMapArray & getData(const ID & data_name) const; /// get a name field associated to the mesh template - inline ElementTypeMapArray & getData(const std::string & data_name); + inline ElementTypeMapArray & getData(const ID & data_name); template ElementTypeMap getNbDataPerElem(ElementTypeMapArray & array, const ElementKind & element_kind); template dumper::Field * createFieldFromAttachedData(const std::string & field_id, const std::string & group_name, const ElementKind & element_kind); /// 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, bool size_to_nb_element = true, bool resize_with_parent = false); /// Facets mesh accessor inline const Mesh & getMeshFacets() const; inline Mesh & getMeshFacets(); /// Parent mesh accessor inline const Mesh & getMeshParent() const; inline bool isMeshFacets() const { return this->is_mesh_facets; } /// defines is the mesh is distributed or not inline bool isDistributed() const { return this->is_distributed; } #ifndef SWIG /// return the dumper from a group and and a dumper name DumperIOHelper & getGroupDumper(const std::string & dumper_name, const std::string & group_name); #endif /* ------------------------------------------------------------------------ */ /* 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 number of facets of a given element type static inline UInt getNbFacetsPerElement(const ElementType & type, UInt t); /// get local connectivity of a facet for a given facet type static inline MatrixProxy getFacetLocalConnectivity(const ElementType & type, UInt t = 0); /// get connectivity of facets for a given element inline Matrix getFacetConnectivity(const Element & element, UInt t = 0) const; /// get the number of type of the surface element associated to a given /// element type static inline UInt getNbFacetTypes(const ElementType & type, UInt t = 0); /// get the type of the surface element associated to a given element static inline ElementType getFacetType(const ElementType & type, UInt t = 0); /// get all the type of the surface element associated to a given element static inline VectorProxy getAllFacetTypes(const ElementType & type); /// get the number of nodes in the given element list static inline UInt getNbNodesPerElementList(const Array & elements); /* ------------------------------------------------------------------------ */ /* Element type Iterator */ /* ------------------------------------------------------------------------ */ using type_iterator = ElementTypeMapArray::type_iterator; using ElementTypesIteratorHelper = ElementTypeMapArray::ElementTypesIteratorHelper; inline ElementTypesIteratorHelper elementTypes(UInt dim = _all_dimensions, GhostType ghost_type = _not_ghost, ElementKind kind = _ek_regular) const { return connectivities.elementTypes(dim, ghost_type, kind); } 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); } AKANTU_GET_MACRO(ElementSynchronizer, *element_synchronizer, const ElementSynchronizer &); AKANTU_GET_MACRO_NOT_CONST(ElementSynchronizer, *element_synchronizer, ElementSynchronizer &); AKANTU_GET_MACRO(NodeSynchronizer, *node_synchronizer, const NodeSynchronizer &); AKANTU_GET_MACRO_NOT_CONST(NodeSynchronizer, *node_synchronizer, NodeSynchronizer &); // AKANTU_GET_MACRO_NOT_CONST(Communicator, *communicator, StaticCommunicator // &); AKANTU_GET_MACRO(Communicator, *communicator, const StaticCommunicator &); /* ------------------------------------------------------------------------ */ /* Private methods for friends */ /* ------------------------------------------------------------------------ */ private: friend class MeshAccessor; //#if defined(AKANTU_COHESIVE_ELEMENT) // friend class CohesiveElementInserter; //#endif //#if defined(AKANTU_IGFEM) // template friend class MeshIgfemSphericalGrowingGel; //#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 the ghost element counter + inline Array & + getGhostsCounters(const ElementType & type, + const GhostType & ghost_type = _ghost) { + AKANTU_DEBUG_ASSERT(ghost_type != _not_ghost, + "No ghost counter for _not_ghost elements"); + return ghosts_counters(type, ghost_type); + } + /// get a pointer to the element_to_subelement Array for the given type and /// create it if necessary inline Array> & 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 std::shared_ptr> nodes; /// global node ids std::unique_ptr> 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{0}; /// all class of elements present in this mesh (for heterogenous meshes) ElementTypeMapArray connectivities; + /// count the references on ghost elements + ElementTypeMapArray ghosts_counters; + /// map to normals for all class of elements present in this mesh ElementTypeMapArray normals; /// list of all existing types in the mesh // ConnectivityTypeList type_set; /// the spatial dimension of this mesh UInt spatial_dimension{0}; /// 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 Vector lower_bounds; /// max of coordinates Vector upper_bounds; /// size covered by the mesh on each direction Vector size; /// local min of coordinates Vector local_lower_bounds; /// local max of coordinates Vector local_upper_bounds; /// Extra data loaded from the mesh file MeshData mesh_data; /// facets' mesh std::unique_ptr mesh_facets; /// parent mesh (this is set for mesh_facets meshes) const Mesh * mesh_parent{nullptr}; /// defines if current mesh is mesh_facets or not bool is_mesh_facets{false}; /// defines if the mesh is centralized or distributed bool is_distributed{false}; /// Communicator on which mesh is distributed const StaticCommunicator * communicator; /// Element synchronizer std::unique_ptr element_synchronizer; /// Node synchronizer std::unique_ptr node_synchronizer; using NodesToElements = std::vector>>; /// This info is stored to simplify the dynamic changes NodesToElements nodes_to_elements; }; /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const Element & _this) { _this.printself(stream); return stream; } /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const Mesh & _this) { _this.printself(stream); return stream; } } // namespace akantu /* -------------------------------------------------------------------------- */ /* Inline functions */ /* -------------------------------------------------------------------------- */ #include "element_type_map_tmpl.hh" #include "mesh_inline_impl.cc" #endif /* __AKANTU_MESH_HH__ */ diff --git a/src/mesh/mesh_accessor.cc b/src/mesh/mesh_accessor.cc index cd369dfe6..bc3f4d39a 100644 --- a/src/mesh/mesh_accessor.cc +++ b/src/mesh/mesh_accessor.cc @@ -1,46 +1,39 @@ /** * @file mesh_accessor.cc * * @author Nicolas Richart * * @date Fri Sep 23 11:53:44 2016 * * @brief Implementation of the accessor (the only class that should be "friend" * with a mesh) * * @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_accessor.hh" //#include "node_synchronizer.hh" /* -------------------------------------------------------------------------- */ namespace akantu { -NodeSynchronizer & MeshAccessor::getNodeSynchronizer() { - return *this->_mesh.node_synchronizer; -} - -ElementSynchronizer & MeshAccessor::getElementSynchronizer() { - return *this->_mesh.element_synchronizer; -} } // akantu diff --git a/src/mesh/mesh_accessor.hh b/src/mesh/mesh_accessor.hh index 061f20a3b..402286b60 100644 --- a/src/mesh/mesh_accessor.hh +++ b/src/mesh/mesh_accessor.hh @@ -1,132 +1,135 @@ /** * @file mesh_accessor.hh * * @author Nicolas Richart * * @date creation: Tue Jun 30 2015 * * @brief this class allow to access some private member of mesh it is used for * IO for examples * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "mesh.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_ACCESSOR_HH__ #define __AKANTU_MESH_ACCESSOR_HH__ namespace akantu { class NodeSynchronizer; class ElementSynchronizer; } // namespace akantu namespace akantu { class MeshAccessor { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: - explicit MeshAccessor(Mesh & mesh) : _mesh(mesh){}; + explicit MeshAccessor(Mesh & mesh) : _mesh(mesh) {} virtual ~MeshAccessor() = default; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the global number of nodes - inline UInt getNbGlobalNodes() const { return this->_mesh.nb_global_nodes; }; + inline UInt getNbGlobalNodes() const { return this->_mesh.nb_global_nodes; } /// set the global number of nodes inline void setNbGlobalNodes(UInt nb_global_nodes) { this->_mesh.nb_global_nodes = nb_global_nodes; - }; + } /// set the mesh as being distributed inline void setDistributed() { this->_mesh.is_distributed = true; } /// get a pointer to the nodes_global_ids Array and create it if /// necessary - inline Array & getNodesGlobalIds() { + inline auto & getNodesGlobalIds() { return this->_mesh.getNodesGlobalIdsPointer(); } /// get a pointer to the nodes_type Array and create it if necessary - inline Array & getNodesType() { - return this->_mesh.getNodesTypePointer(); - } + inline auto & getNodesType() { return this->_mesh.getNodesTypePointer(); } /// get a pointer to the coordinates Array - inline Array & getNodes() { return this->_mesh.getNodesPointer(); } + inline auto & getNodes() { return this->_mesh.getNodesPointer(); } /// get a pointer to the coordinates Array - inline std::shared_ptr> getNodesSharedPtr() { return this->_mesh.nodes; } + inline auto getNodesSharedPtr() { return this->_mesh.nodes; } /// get a pointer to the connectivity Array for the given type and create it /// if necessary - inline Array & - getConnectivity(const ElementType & type, - const GhostType & ghost_type = _not_ghost) { + inline auto & getConnectivity(const ElementType & type, + const GhostType & ghost_type = _not_ghost) { return this->_mesh.getConnectivityPointer(type, ghost_type); } + /// get the ghost element counter + inline auto & getGhostsCounters(const ElementType & type, + const GhostType & ghost_type = _ghost) { + return this->_mesh.getGhostsCounters(type, ghost_type); + } + /// get a pointer to the element_to_subelement Array for the given type and /// create it if necessary - inline Array> & + inline auto & getElementToSubelement(const ElementType & type, const GhostType & ghost_type = _not_ghost) { return this->_mesh.getElementToSubelementPointer(type, ghost_type); } /// get a pointer to the subelement_to_element Array for the given type and /// create it if necessary - inline Array & + inline auto & getSubelementToElement(const ElementType & type, const GhostType & ghost_type = _not_ghost) { return this->_mesh.getSubelementToElementPointer(type, ghost_type); } template - inline Array & + inline auto & getData(const std::string & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost, UInt nb_component = 1, bool size_to_nb_element = true, bool resize_with_parent = false) { return this->_mesh.getDataPointer(data_name, el_type, ghost_type, nb_component, size_to_nb_element, resize_with_parent); } - MeshData & getMeshData() { return this->_mesh.getMeshData(); } + auto & getMeshData() { return this->_mesh.getMeshData(); } /// get the node synchonizer - NodeSynchronizer & getNodeSynchronizer(); + auto & getNodeSynchronizer() { return *this->_mesh.node_synchronizer; } /// get the element synchonizer - ElementSynchronizer & getElementSynchronizer(); + auto & getElementSynchronizer() { return *this->_mesh.element_synchronizer; } private: Mesh & _mesh; }; } // namespace akantu #endif /* __AKANTU_MESH_ACCESSOR_HH__ */ diff --git a/src/mesh/mesh_data.hh b/src/mesh/mesh_data.hh index c2b943cc8..92f634eb6 100644 --- a/src/mesh/mesh_data.hh +++ b/src/mesh/mesh_data.hh @@ -1,145 +1,150 @@ /** * @file mesh_data.hh * * @author Dana Christen * @author Nicolas Richart * * @date creation: Fri May 03 2013 * @date last modification: Thu Nov 05 2015 * * @brief Stores generic data loaded from the mesh file * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_DATA_HH__ #define __AKANTU_MESH_DATA_HH__ /* -------------------------------------------------------------------------- */ -#include "element_type_map.hh" #include "aka_memory.hh" +#include "element_type_map.hh" #include #include /* -------------------------------------------------------------------------- */ namespace akantu { -#define AKANTU_MESH_DATA_TYPES \ - ((_tc_int, Int)) \ - ((_tc_uint, UInt)) \ - ((_tc_real, Real)) \ - ((_tc_element, Element)) \ - ((_tc_std_string, std::string)) \ - ((_tc_std_vector_element, std::vector)) \ +#define AKANTU_MESH_DATA_TYPES \ + ((_tc_int, Int))((_tc_uint, UInt))((_tc_real, Real))( \ + (_tc_element, Element))((_tc_std_string, std::string))( \ + (_tc_std_vector_element, std::vector)) -#define AKANTU_MESH_DATA_TUPLE_FIRST_ELEM(s, data, elem) BOOST_PP_TUPLE_ELEM(2, 0, elem) +#define AKANTU_MESH_DATA_TUPLE_FIRST_ELEM(s, data, elem) \ + BOOST_PP_TUPLE_ELEM(2, 0, elem) enum MeshDataTypeCode : int { - BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(AKANTU_MESH_DATA_TUPLE_FIRST_ELEM, , AKANTU_MESH_DATA_TYPES)), + BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(AKANTU_MESH_DATA_TUPLE_FIRST_ELEM, , + AKANTU_MESH_DATA_TYPES)), _tc_unknown }; class MeshData : public Memory { /* ------------------------------------------------------------------------ */ /* Typedefs */ /* ------------------------------------------------------------------------ */ private: typedef MeshDataTypeCode TypeCode; typedef std::map ElementalDataMap; typedef std::vector StringVector; typedef std::map TypeCodeMap; /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: - MeshData(const ID & id = "mesh_data", const ID & parent_id = "", const MemoryID & memory_id = 0); + MeshData(const ID & id = "mesh_data", const ID & parent_id = "", + const MemoryID & memory_id = 0); ~MeshData(); /* ------------------------------------------------------------------------ */ /* Methods and accessors */ /* ------------------------------------------------------------------------ */ public: - /// Register new elemental data (and alloc data) with check if the name is new - template - void registerElementalData(const std::string & name); - inline void registerElementalData(const std::string & name, TypeCode type); + /// Register new elemental data (and alloc data) with check if the name is + /// new + template void registerElementalData(const ID & name); + inline void registerElementalData(const ID & name, TypeCode type); + + /// Get an existing elemental data array + template + bool hasDataArray(const ID & data_name, const ElementType & el_type, + const GhostType & ghost_type = _not_ghost) const; /// Get an existing elemental data array - template - const Array & getElementalDataArray(const std::string & data_name, - const ElementType & el_type, - const GhostType & ghost_type = _not_ghost) const; - template - Array & getElementalDataArray(const std::string & data_name, + template + const Array & + getElementalDataArray(const ID & data_name, const ElementType & el_type, + const GhostType & ghost_type = _not_ghost) const; + template + Array & getElementalDataArray(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost); /// Get an elemental data array, if it does not exist: allocate it - template - Array & getElementalDataArrayAlloc(const std::string & data_name, - const ElementType & el_type, - const GhostType & ghost_type = _not_ghost, - UInt nb_component = 1); + template + Array & + getElementalDataArrayAlloc(const ID & data_name, const ElementType & el_type, + const GhostType & ghost_type = _not_ghost, + UInt nb_component = 1); /// get the names of the data stored in elemental_data - inline void getTagNames(StringVector & tags, const ElementType & type, const GhostType & ghost_type = _not_ghost) const; + inline void getTagNames(StringVector & tags, const ElementType & type, + const GhostType & ghost_type = _not_ghost) const; /// get the type of the data stored in elemental_data - template - TypeCode getTypeCode() const; - inline TypeCode getTypeCode(const std::string name) const; + template TypeCode getTypeCode() const; + inline TypeCode getTypeCode(const ID & name) const; - template - inline UInt getNbComponentTemplated(const std::string, const ElementType & el_type, const GhostType & ghost_type) const; - inline UInt getNbComponent(const std::string name, const ElementType & el_type, const GhostType & ghost_type = _not_ghost) const; + template + inline UInt getNbComponentTemplated(const ID & name, + const ElementType & el_type, + const GhostType & ghost_type) const; + inline UInt getNbComponent(const ID & name, const ElementType & el_type, + const GhostType & ghost_type = _not_ghost) const; /// Get an existing elemental data - template - const ElementTypeMapArray & getElementalData(const std::string & name) const; - template - ElementTypeMapArray & getElementalData(const std::string & name); - + template + const ElementTypeMapArray & getElementalData(const ID & name) const; + template + ElementTypeMapArray & getElementalData(const ID & name); private: /// Register new elemental data (add alloc data) - template - ElementTypeMapArray * allocElementalData(const std::string & name); + template + ElementTypeMapArray * allocElementalData(const ID & name); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// Map when elemental data is stored as ElementTypeMap ElementalDataMap elemental_data; /// Map when elementalType of the data stored in elemental_data TypeCodeMap typecode_map; }; +} // akantu + #include "mesh_data_tmpl.hh" #undef AKANTU_MESH_DATA_TUPLE_FIRST_ELEM -} // akantu - #endif /* __AKANTU_MESH_DATA_HH__ */ - - diff --git a/src/mesh/mesh_data_tmpl.hh b/src/mesh/mesh_data_tmpl.hh index 17fb098ac..887e3f680 100644 --- a/src/mesh/mesh_data_tmpl.hh +++ b/src/mesh/mesh_data_tmpl.hh @@ -1,218 +1,273 @@ /** * @file mesh_data_tmpl.hh * * @author Dana Christen * @author Nicolas Richart * * @date creation: Fri May 03 2013 * @date last modification: Thu Nov 05 2015 * * @brief Stores generic data loaded from the mesh file * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ +/* -------------------------------------------------------------------------- */ +#include "mesh_data.hh" +/* -------------------------------------------------------------------------- */ -} // akantu - -#include - -#define MESH_DATA_GET_TYPE(r, data, type) \ -template<> \ -inline MeshDataTypeCode MeshData::getTypeCode() const { \ - return BOOST_PP_TUPLE_ELEM(2, 0, type); \ -} +#ifndef __AKANTU_MESH_DATA_TMPL_HH__ +#define __AKANTU_MESH_DATA_TMPL_HH__ namespace akantu { +#define MESH_DATA_GET_TYPE(r, data, type) \ + template <> \ + inline MeshDataTypeCode \ + MeshData::getTypeCode() const { \ + return BOOST_PP_TUPLE_ELEM(2, 0, type); \ + } + /* -------------------------------------------------------------------------- */ // get the type of the data stored in elemental_data -template -inline MeshDataTypeCode MeshData::getTypeCode() const { - AKANTU_DEBUG_ERROR("Type " << debug::demangle(typeid(T).name()) << "not implemented by MeshData."); +template inline MeshDataTypeCode MeshData::getTypeCode() const { + AKANTU_DEBUG_ERROR("Type " << debug::demangle(typeid(T).name()) + << "not implemented by MeshData."); } /* -------------------------------------------------------------------------- */ BOOST_PP_SEQ_FOR_EACH(MESH_DATA_GET_TYPE, void, AKANTU_MESH_DATA_TYPES) #undef MESH_DATA_GET_TYPE -inline MeshDataTypeCode MeshData::getTypeCode(const std::string name) const { +inline MeshDataTypeCode MeshData::getTypeCode(const ID & name) const { TypeCodeMap::const_iterator it = typecode_map.find(name); - if(it == typecode_map.end()) AKANTU_EXCEPTION("No dataset named " << name << " found."); + if (it == typecode_map.end()) + AKANTU_EXCEPTION("No dataset named " << name << " found."); return it->second; } /* -------------------------------------------------------------------------- */ - // Register new elemental data templated (and alloc data) with check if the name is new -template -void MeshData::registerElementalData(const std::string & name) { +// Register new elemental data templated (and alloc data) with check if the +// name is new +template void MeshData::registerElementalData(const ID & name) { ElementalDataMap::iterator it = elemental_data.find(name); - if(it == elemental_data.end()) { + if (it == elemental_data.end()) { allocElementalData(name); - } else{ + } else { AKANTU_DEBUG_INFO("Data named " << name << " already registered."); } } /* -------------------------------------------------------------------------- */ - // Register new elemental data of a given MeshDataTypeCode with check if the name is new -#define AKANTU_MESH_DATA_CASE_MACRO(r, name, elem) \ - case BOOST_PP_TUPLE_ELEM(2, 0, elem) : { registerElementalData(name); break; } + // Register new elemental data of a given MeshDataTypeCode with check if the + // name is new +#define AKANTU_MESH_DATA_CASE_MACRO(r, name, elem) \ + case BOOST_PP_TUPLE_ELEM(2, 0, elem): { \ + registerElementalData(name); \ + break; \ + } -inline void MeshData::registerElementalData(const std::string & name, MeshDataTypeCode type) { - switch(type) { - BOOST_PP_SEQ_FOR_EACH(AKANTU_MESH_DATA_CASE_MACRO, name, AKANTU_MESH_DATA_TYPES) - default : AKANTU_DEBUG_ERROR("Type " << type << "not implemented by MeshData."); +inline void MeshData::registerElementalData(const ID & name, + MeshDataTypeCode type) { + switch (type) { + BOOST_PP_SEQ_FOR_EACH(AKANTU_MESH_DATA_CASE_MACRO, name, + AKANTU_MESH_DATA_TYPES) + default: + AKANTU_DEBUG_ERROR("Type " << type << "not implemented by MeshData."); } } #undef AKANTU_MESH_DATA_CASE_MACRO + /* -------------------------------------------------------------------------- */ - /// Register new elemental data (and alloc data) -template -ElementTypeMapArray * MeshData::allocElementalData(const std::string & name) { - ElementTypeMapArray * dataset = new ElementTypeMapArray(name, id, memory_id); +/// Register new elemental data (and alloc data) +template +ElementTypeMapArray * MeshData::allocElementalData(const ID & name) { + ElementTypeMapArray * dataset = + new ElementTypeMapArray(name, id, memory_id); elemental_data[name] = dataset; typecode_map[name] = getTypeCode(); return dataset; } /* -------------------------------------------------------------------------- */ -template -const ElementTypeMapArray & MeshData::getElementalData(const std::string & name) const { +template +const ElementTypeMapArray & +MeshData::getElementalData(const ID & name) const { ElementalDataMap::const_iterator it = elemental_data.find(name); - if(it == elemental_data.end()) AKANTU_EXCEPTION("No dataset named " << name << " found."); + if (it == elemental_data.end()) + AKANTU_EXCEPTION("No dataset named " << name << " found."); return dynamic_cast &>(*(it->second)); } /* -------------------------------------------------------------------------- */ // Get an existing elemental data -template -ElementTypeMapArray & MeshData::getElementalData(const std::string & name) { +template +ElementTypeMapArray & MeshData::getElementalData(const ID & name) { ElementalDataMap::iterator it = elemental_data.find(name); - if(it == elemental_data.end()) AKANTU_EXCEPTION("No dataset named " << name << " found."); + if (it == elemental_data.end()) + AKANTU_EXCEPTION("No dataset named " << name << " found."); return dynamic_cast &>(*(it->second)); } /* -------------------------------------------------------------------------- */ // Get an existing elemental data array for an element type -template -const Array & MeshData::getElementalDataArray(const std::string & name, - const ElementType & elem_type, - const GhostType & ghost_type) const { +template +bool MeshData::hasDataArray(const ID & name, const ElementType & elem_type, + const GhostType & ghost_type) const { + auto it = elemental_data.find(name); + if (it == elemental_data.end()) + return false; + + auto & elem_map = dynamic_cast &>(*(it->second)); + return elem_map.exists(elem_type, ghost_type); +} + +/* -------------------------------------------------------------------------- */ +// Get an existing elemental data array for an element type +template +const Array & +MeshData::getElementalDataArray(const ID & name, const ElementType & elem_type, + const GhostType & ghost_type) const { ElementalDataMap::const_iterator it = elemental_data.find(name); - if(it == elemental_data.end()) { - AKANTU_EXCEPTION("Data named " << name << " not registered for type: " << elem_type << " - ghost_type:" << ghost_type << "!"); + if (it == elemental_data.end()) { + AKANTU_EXCEPTION("Data named " << name + << " not registered for type: " << elem_type + << " - ghost_type:" << ghost_type << "!"); } - return dynamic_cast &>(*(it->second))(elem_type, ghost_type); + return dynamic_cast &>(*(it->second))( + elem_type, ghost_type); } -template -Array & MeshData::getElementalDataArray(const std::string & name, +template +Array & MeshData::getElementalDataArray(const ID & name, const ElementType & elem_type, const GhostType & ghost_type) { ElementalDataMap::iterator it = elemental_data.find(name); - if(it == elemental_data.end()) { - AKANTU_EXCEPTION("Data named " << name << " not registered for type: " << elem_type << " - ghost_type:" << ghost_type << "!"); + if (it == elemental_data.end()) { + AKANTU_EXCEPTION("Data named " << name + << " not registered for type: " << elem_type + << " - ghost_type:" << ghost_type << "!"); } - return dynamic_cast &>(*(it->second))(elem_type, ghost_type); + return dynamic_cast &>(*(it->second))(elem_type, + ghost_type); } /* -------------------------------------------------------------------------- */ // Get an elemental data array, if it does not exist: allocate it -template -Array & MeshData::getElementalDataArrayAlloc(const std::string & name, - const ElementType & elem_type, - const GhostType & ghost_type, - UInt nb_component) { +template +Array & MeshData::getElementalDataArrayAlloc(const ID & name, + const ElementType & elem_type, + const GhostType & ghost_type, + UInt nb_component) { ElementalDataMap::iterator it = elemental_data.find(name); ElementTypeMapArray * dataset; - if(it == elemental_data.end()) { + if (it == elemental_data.end()) { dataset = allocElementalData(name); } else { dataset = dynamic_cast *>(it->second); } - AKANTU_DEBUG_ASSERT(getTypeCode() == typecode_map.find(name)->second, "Function getElementalDataArrayAlloc called with the wrong type!"); - if(!(dataset->exists(elem_type, ghost_type))) { + AKANTU_DEBUG_ASSERT( + getTypeCode() == typecode_map.find(name)->second, + "Function getElementalDataArrayAlloc called with the wrong type!"); + if (!(dataset->exists(elem_type, ghost_type))) { dataset->alloc(0, nb_component, elem_type, ghost_type); } return (*dataset)(elem_type, ghost_type); } - /* -------------------------------------------------------------------------- */ -#define AKANTU_MESH_DATA_CASE_MACRO(r, name, elem) \ - case BOOST_PP_TUPLE_ELEM(2, 0, elem) : { \ - nb_comp = getNbComponentTemplated(name, el_type, ghost_type); \ - break; \ - } \ +#define AKANTU_MESH_DATA_CASE_MACRO(r, name, elem) \ + case BOOST_PP_TUPLE_ELEM(2, 0, elem): { \ + nb_comp = getNbComponentTemplated( \ + name, el_type, ghost_type); \ + break; \ + } -inline UInt MeshData::getNbComponent(const std::string name, const ElementType & el_type, const GhostType & ghost_type) const { +inline UInt MeshData::getNbComponent(const ID & name, + const ElementType & el_type, + const GhostType & ghost_type) const { TypeCodeMap::const_iterator it = typecode_map.find(name); UInt nb_comp(0); - if(it == typecode_map.end()) { - AKANTU_EXCEPTION("Could not determine the type held in dataset " << name << " for type: " << el_type << " - ghost_type:" << ghost_type << "."); + if (it == typecode_map.end()) { + AKANTU_EXCEPTION("Could not determine the type held in dataset " + << name << " for type: " << el_type + << " - ghost_type:" << ghost_type << "."); } MeshDataTypeCode type = it->second; - switch(type) { - BOOST_PP_SEQ_FOR_EACH(AKANTU_MESH_DATA_CASE_MACRO, name, AKANTU_MESH_DATA_TYPES) - default : AKANTU_DEBUG_ERROR("Could not call the correct instance of getNbComponentTemplated."); break; + switch (type) { + BOOST_PP_SEQ_FOR_EACH(AKANTU_MESH_DATA_CASE_MACRO, name, + AKANTU_MESH_DATA_TYPES) + default: + AKANTU_DEBUG_ERROR( + "Could not call the correct instance of getNbComponentTemplated."); + break; } return nb_comp; } #undef AKANTU_MESH_DATA_CASE_MACRO /* -------------------------------------------------------------------------- */ -template -inline UInt MeshData::getNbComponentTemplated(const std::string name, const ElementType & el_type, const GhostType & ghost_type) const { +template +inline UInt +MeshData::getNbComponentTemplated(const ID & name, const ElementType & el_type, + const GhostType & ghost_type) const { return getElementalDataArray(name, el_type, ghost_type).getNbComponent(); } /* -------------------------------------------------------------------------- */ // get the names of the data stored in elemental_data -#define AKANTU_MESH_DATA_CASE_MACRO(r, name, elem) \ - case BOOST_PP_TUPLE_ELEM(2, 0, elem) : { \ - ElementTypeMapArray * dataset; \ - dataset = dynamic_cast< ElementTypeMapArray * >(it->second); \ - exists = dataset->exists(el_type, ghost_type); \ - break; \ - } \ - -inline void MeshData::getTagNames(StringVector & tags, const ElementType & el_type, const GhostType & ghost_type) const { +#define AKANTU_MESH_DATA_CASE_MACRO(r, name, elem) \ + case BOOST_PP_TUPLE_ELEM(2, 0, elem): { \ + ElementTypeMapArray * dataset; \ + dataset = \ + dynamic_cast *>( \ + it->second); \ + exists = dataset->exists(el_type, ghost_type); \ + break; \ + } + +inline void MeshData::getTagNames(StringVector & tags, + const ElementType & el_type, + const GhostType & ghost_type) const { tags.clear(); bool exists(false); - ElementalDataMap::const_iterator it = elemental_data.begin(); + ElementalDataMap::const_iterator it = elemental_data.begin(); ElementalDataMap::const_iterator it_end = elemental_data.end(); - for(; it != it_end; ++it) { + for (; it != it_end; ++it) { MeshDataTypeCode type = getTypeCode(it->first); - switch(type) { - BOOST_PP_SEQ_FOR_EACH(AKANTU_MESH_DATA_CASE_MACRO, , AKANTU_MESH_DATA_TYPES) - default : AKANTU_DEBUG_ERROR("Could not determine the proper type to (dynamic-)cast."); break; + switch (type) { + BOOST_PP_SEQ_FOR_EACH(AKANTU_MESH_DATA_CASE_MACRO, , + AKANTU_MESH_DATA_TYPES) + default: + AKANTU_DEBUG_ERROR( + "Could not determine the proper type to (dynamic-)cast."); + break; } - if(exists) { + if (exists) { tags.push_back(it->first); } } } #undef AKANTU_MESH_DATA_CASE_MACRO /* -------------------------------------------------------------------------- */ +} // namespace akantu - - +#endif /* __AKANTU_MESH_DATA_TMPL_HH__ */ diff --git a/src/mesh/mesh_inline_impl.cc b/src/mesh/mesh_inline_impl.cc index c0d88a5b2..c2caf4b06 100644 --- a/src/mesh/mesh_inline_impl.cc +++ b/src/mesh/mesh_inline_impl.cc @@ -1,685 +1,621 @@ /** * @file mesh_inline_impl.cc * * @author Guillaume Anciaux * @author Dana Christen * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Thu Jul 15 2010 * @date last modification: Thu Jan 21 2016 * * @brief Implementation of the inline functions of the mesh class * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_iterators.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #if defined(AKANTU_COHESIVE_ELEMENT) #include "cohesive_element.hh" #endif #ifndef __AKANTU_MESH_INLINE_IMPL_CC__ #define __AKANTU_MESH_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline RemovedNodesEvent::RemovedNodesEvent(const Mesh & mesh) : new_numbering(mesh.getNbNodes(), 1, "new_numbering") {} /* -------------------------------------------------------------------------- */ inline RemovedElementsEvent::RemovedElementsEvent(const Mesh & mesh, ID new_numbering_id) : new_numbering(new_numbering_id, mesh.getID(), mesh.getMemoryID()) {} /* -------------------------------------------------------------------------- */ template <> inline void Mesh::sendEvent(NewElementsEvent & event) { this->nodes_to_elements.resize(nodes->size()); for (const auto & elem : event.getList()) { const Array & conn = connectivities(elem.type, elem.ghost_type); UInt nb_nodes_per_elem = this->getNbNodesPerElement(elem.type); for (UInt n = 0; n < nb_nodes_per_elem; ++n) { UInt node = conn(elem.element, n); if (not nodes_to_elements[node]) nodes_to_elements[node] = std::make_unique>(); nodes_to_elements[node]->insert(elem); } } EventHandlerManager::sendEvent(event); } /* -------------------------------------------------------------------------- */ template <> inline void Mesh::sendEvent(NewNodesEvent & event) { this->computeBoundingBox(); EventHandlerManager::sendEvent(event); } /* -------------------------------------------------------------------------- */ template <> inline void Mesh::sendEvent(RemovedElementsEvent & event) { this->connectivities.onElementsRemoved(event.getNewNumbering()); this->fillNodesToElements(); this->computeBoundingBox(); EventHandlerManager::sendEvent(event); } /* -------------------------------------------------------------------------- */ template <> inline void Mesh::sendEvent(RemovedNodesEvent & event) { const auto & new_numbering = event.getNewNumbering(); this->removeNodesFromArray(*nodes, new_numbering); if (nodes_global_ids) this->removeNodesFromArray(*nodes_global_ids, new_numbering); if (nodes_type.size() != 0) this->removeNodesFromArray(nodes_type, new_numbering); if (not nodes_to_elements.empty()) { std::vector>> tmp( nodes_to_elements.size()); auto it = nodes_to_elements.begin(); UInt new_nb_nodes = 0; for (auto new_i : new_numbering) { if (new_i != UInt(-1)) { tmp[new_i] = std::move(*it); ++new_nb_nodes; } ++it; } tmp.resize(new_nb_nodes); std::move(tmp.begin(), tmp.end(), nodes_to_elements.begin()); } computeBoundingBox(); EventHandlerManager::sendEvent(event); } /* -------------------------------------------------------------------------- */ template inline void Mesh::removeNodesFromArray(Array & vect, const Array & new_numbering) { Array tmp(vect.size(), vect.getNbComponent()); UInt nb_component = vect.getNbComponent(); UInt new_nb_nodes = 0; for (UInt i = 0; i < new_numbering.size(); ++i) { UInt new_i = new_numbering(i); if (new_i != UInt(-1)) { T * to_copy = vect.storage() + i * nb_component; std::uninitialized_copy(to_copy, to_copy + nb_component, tmp.storage() + new_i * nb_component); ++new_nb_nodes; } } tmp.resize(new_nb_nodes); vect.copy(tmp); } -/* -------------------------------------------------------------------------- */ -// inline UInt Mesh::elementToLinearized(const Element & elem) const { -// AKANTU_DEBUG_ASSERT(elem.type < _max_element_type && -// elem.element < types_offsets.storage()[elem.type + -// 1], -// "The element " << elem << "does not exists in the mesh -// " -// << getID()); - -// return types_offsets.storage()[elem.type] + elem.element; -// } - -// /* -------------------------------------------------------------------------- -// */ inline Element Mesh::linearizedToElement(UInt linearized_element) const { - -// UInt t; - -// for (t = _not_defined; -// t != _max_element_type && linearized_element >= types_offsets(t); ++t) -// ; - -// AKANTU_DEBUG_ASSERT(linearized_element < types_offsets(t), -// "The linearized element " -// << linearized_element -// << "does not exists in the mesh " << getID()); - -// --t; -// ElementType type = ElementType(t); -// return Element(type, linearized_element - types_offsets.storage()[t], -// _not_ghost, getKind(type)); -// } - -// /* -------------------------------------------------------------------------- -// */ inline void Mesh::updateTypesOffsets(const GhostType & ghost_type) { -// Array * types_offsets_ptr = &this->types_offsets; -// if (ghost_type == _ghost) -// types_offsets_ptr = &this->ghost_types_offsets; -// Array & types_offsets = *types_offsets_ptr; - -// types_offsets.clear(); -// for (auto type : elementTypes(_all_dimensions, ghost_type, -// _ek_not_defined)) -// types_offsets(type) = connectivities(type, ghost_type).size(); - -// for (UInt t = _not_defined + 1; t < _max_element_type; ++t) -// types_offsets(t) += types_offsets(t - 1); -// for (UInt t = _max_element_type; t > _not_defined; --t) -// types_offsets(t) = types_offsets(t - 1); -// types_offsets(0) = 0; -// } - -// /* -------------------------------------------------------------------------- -// */ inline const Mesh::ConnectivityTypeList & -// Mesh::getConnectivityTypeList(const GhostType & ghost_type) const { -// if (ghost_type == _not_ghost) -// return type_set; -// else -// return ghost_type_set; -// } - /* -------------------------------------------------------------------------- */ inline Array & Mesh::getNodesGlobalIdsPointer() { AKANTU_DEBUG_IN(); if (not nodes_global_ids) { nodes_global_ids = std::make_unique>( nodes->size(), 1, getID() + ":nodes_global_ids"); for (auto && global_ids : enumerate(*nodes_global_ids)) { std::get<1>(global_ids) = std::get<0>(global_ids); } } AKANTU_DEBUG_OUT(); return *nodes_global_ids; } /* -------------------------------------------------------------------------- */ inline Array & Mesh::getNodesTypePointer() { AKANTU_DEBUG_IN(); if (nodes_type.size() == 0) { nodes_type.resize(nodes->size()); nodes_type.set(_nt_normal); } AKANTU_DEBUG_OUT(); return nodes_type; } /* -------------------------------------------------------------------------- */ inline Array & Mesh::getConnectivityPointer(const ElementType & type, const GhostType & ghost_type) { - AKANTU_DEBUG_IN(); - - Array * tmp; - if (!connectivities.exists(type, ghost_type)) { - UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); + if (connectivities.exists(type, ghost_type)) + return connectivities(type, ghost_type); - tmp = &(connectivities.alloc(0, nb_nodes_per_element, type, ghost_type)); - - AKANTU_DEBUG_INFO("The connectivity vector for the type " << type - << " created"); - // if (ghost_type == _not_ghost) - // type_set.insert(type); - // else - // ghost_type_set.insert(type); - - // updateTypesOffsets(ghost_type); - } else { - tmp = &connectivities(type, ghost_type); + if (ghost_type != _not_ghost) { + ghosts_counters.alloc(0, 1, type, ghost_type, 1); } - AKANTU_DEBUG_OUT(); - return *tmp; + AKANTU_DEBUG_INFO("The connectivity vector for the type " << type + << " created"); + + UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); + return connectivities.alloc(0, nb_nodes_per_element, type, ghost_type); } /* -------------------------------------------------------------------------- */ inline Array> & Mesh::getElementToSubelementPointer(const ElementType & type, const GhostType & ghost_type) { return getDataPointer>("element_to_subelement", type, ghost_type, 1, true); } /* -------------------------------------------------------------------------- */ inline Array & Mesh::getSubelementToElementPointer(const ElementType & type, const GhostType & ghost_type) { return getDataPointer("subelement_to_element", type, ghost_type, getNbFacetsPerElement(type), true, is_mesh_facets); } /* -------------------------------------------------------------------------- */ inline const Array> & Mesh::getElementToSubelement(const ElementType & type, const GhostType & ghost_type) const { return getData>("element_to_subelement", type, ghost_type); } /* -------------------------------------------------------------------------- */ inline Array> & Mesh::getElementToSubelement(const ElementType & type, const GhostType & ghost_type) { return getData>("element_to_subelement", type, ghost_type); } /* -------------------------------------------------------------------------- */ inline const Array & Mesh::getSubelementToElement(const ElementType & type, const GhostType & ghost_type) const { return getData("subelement_to_element", type, ghost_type); } /* -------------------------------------------------------------------------- */ inline Array & Mesh::getSubelementToElement(const ElementType & type, const GhostType & ghost_type) { return getData("subelement_to_element", type, ghost_type); } /* -------------------------------------------------------------------------- */ template inline Array & -Mesh::getDataPointer(const std::string & data_name, const ElementType & el_type, +Mesh::getDataPointer(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type, UInt nb_component, bool size_to_nb_element, bool resize_with_parent) { Array & tmp = mesh_data.getElementalDataArrayAlloc( data_name, el_type, ghost_type, nb_component); if (size_to_nb_element) { if (resize_with_parent) tmp.resize(mesh_parent->getNbElement(el_type, ghost_type)); else tmp.resize(this->getNbElement(el_type, ghost_type)); } else { tmp.resize(0); } return tmp; } /* -------------------------------------------------------------------------- */ template -inline const Array & Mesh::getData(const std::string & data_name, +inline bool Mesh::hasData(const ID & data_name, const ElementType & el_type, + const GhostType & ghost_type) const { + return mesh_data.hasDataArray(data_name, el_type, ghost_type); +} + +/* -------------------------------------------------------------------------- */ +template +inline const Array & Mesh::getData(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type) const { return mesh_data.getElementalDataArray(data_name, el_type, ghost_type); } /* -------------------------------------------------------------------------- */ template -inline Array & Mesh::getData(const std::string & data_name, +inline Array & Mesh::getData(const ID & data_name, const ElementType & el_type, const GhostType & ghost_type) { return mesh_data.getElementalDataArray(data_name, el_type, ghost_type); } /* -------------------------------------------------------------------------- */ template inline const ElementTypeMapArray & -Mesh::getData(const std::string & data_name) const { +Mesh::getData(const ID & data_name) const { return mesh_data.getElementalData(data_name); } /* -------------------------------------------------------------------------- */ template -inline ElementTypeMapArray & Mesh::getData(const std::string & data_name) { +inline ElementTypeMapArray & Mesh::getData(const ID & data_name) { return mesh_data.getElementalData(data_name); } /* -------------------------------------------------------------------------- */ template -inline ElementTypeMapArray & -Mesh::registerData(const std::string & data_name) { +inline ElementTypeMapArray & Mesh::registerData(const ID & data_name) { this->mesh_data.registerElementalData(data_name); return this->getData(data_name); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbElement(const ElementType & type, const GhostType & ghost_type) const { try { const Array & conn = connectivities(type, ghost_type); return conn.size(); } catch (...) { return 0; } } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbElement(const UInt spatial_dimension, const GhostType & ghost_type, const ElementKind & kind) const { AKANTU_DEBUG_ASSERT(spatial_dimension <= 3 || spatial_dimension == UInt(-1), "spatial_dimension is " << spatial_dimension << " and is greater than 3 !"); UInt nb_element = 0; for (auto type : elementTypes(spatial_dimension, ghost_type, kind)) nb_element += getNbElement(type, ghost_type); return nb_element; } /* -------------------------------------------------------------------------- */ inline void Mesh::getBarycenter(UInt element, const ElementType & type, Real * barycenter, GhostType ghost_type) const { UInt * conn_val = getConnectivity(type, ghost_type).storage(); UInt nb_nodes_per_element = getNbNodesPerElement(type); Real * local_coord = new Real[spatial_dimension * nb_nodes_per_element]; UInt offset = element * nb_nodes_per_element; for (UInt n = 0; n < nb_nodes_per_element; ++n) { memcpy(local_coord + n * spatial_dimension, nodes->storage() + conn_val[offset + n] * spatial_dimension, spatial_dimension * sizeof(Real)); } Math::barycenter(local_coord, nb_nodes_per_element, spatial_dimension, barycenter); delete[] local_coord; } /* -------------------------------------------------------------------------- */ inline void Mesh::getBarycenter(const Element & element, Vector & barycenter) const { getBarycenter(element.element, element.type, barycenter.storage(), element.ghost_type); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbNodesPerElement(const ElementType & type) { UInt nb_nodes_per_element = 0; #define GET_NB_NODES_PER_ELEMENT(type) \ nb_nodes_per_element = ElementClass::getNbNodesPerElement() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NB_NODES_PER_ELEMENT); #undef GET_NB_NODES_PER_ELEMENT return nb_nodes_per_element; } /* -------------------------------------------------------------------------- */ inline ElementType Mesh::getP1ElementType(const ElementType & type) { ElementType p1_type = _not_defined; #define GET_P1_TYPE(type) p1_type = ElementClass::getP1ElementType() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_P1_TYPE); #undef GET_P1_TYPE return p1_type; } /* -------------------------------------------------------------------------- */ inline ElementKind Mesh::getKind(const ElementType & type) { ElementKind kind = _ek_not_defined; #define GET_KIND(type) kind = ElementClass::getKind() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_KIND); #undef GET_KIND return kind; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getSpatialDimension(const ElementType & type) { UInt spatial_dimension = 0; #define GET_SPATIAL_DIMENSION(type) \ spatial_dimension = ElementClass::getSpatialDimension() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_SPATIAL_DIMENSION); #undef GET_SPATIAL_DIMENSION return spatial_dimension; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbFacetTypes(const ElementType & type, __attribute__((unused)) UInt t) { UInt nb = 0; #define GET_NB_FACET_TYPE(type) nb = ElementClass::getNbFacetTypes() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NB_FACET_TYPE); #undef GET_NB_FACET_TYPE return nb; } /* -------------------------------------------------------------------------- */ inline ElementType Mesh::getFacetType(const ElementType & type, UInt t) { ElementType surface_type = _not_defined; #define GET_FACET_TYPE(type) surface_type = ElementClass::getFacetType(t) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_FACET_TYPE); #undef GET_FACET_TYPE return surface_type; } /* -------------------------------------------------------------------------- */ inline VectorProxy Mesh::getAllFacetTypes(const ElementType & type) { #define GET_FACET_TYPE(type) \ UInt nb = ElementClass::getNbFacetTypes(); \ ElementType * elt_ptr = \ const_cast(ElementClass::getFacetTypeInternal()); \ return VectorProxy(elt_ptr, nb); AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_FACET_TYPE); #undef GET_FACET_TYPE } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbFacetsPerElement(const ElementType & type) { AKANTU_DEBUG_IN(); UInt n_facet = 0; #define GET_NB_FACET(type) n_facet = ElementClass::getNbFacetsPerElement() AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NB_FACET); #undef GET_NB_FACET AKANTU_DEBUG_OUT(); return n_facet; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbFacetsPerElement(const ElementType & type, UInt t) { AKANTU_DEBUG_IN(); UInt n_facet = 0; #define GET_NB_FACET(type) \ n_facet = ElementClass::getNbFacetsPerElement(t) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_NB_FACET); #undef GET_NB_FACET AKANTU_DEBUG_OUT(); return n_facet; } /* -------------------------------------------------------------------------- */ inline MatrixProxy Mesh::getFacetLocalConnectivity(const ElementType & type, UInt t) { AKANTU_DEBUG_IN(); #define GET_FACET_CON(type) \ AKANTU_DEBUG_OUT(); \ return ElementClass::getFacetLocalConnectivityPerElement(t) AKANTU_BOOST_ALL_ELEMENT_SWITCH(GET_FACET_CON); #undef GET_FACET_CON AKANTU_DEBUG_OUT(); return MatrixProxy( nullptr, 0, 0); // This avoid a compilation warning but will certainly // also cause a segfault if reached } /* -------------------------------------------------------------------------- */ inline Matrix Mesh::getFacetConnectivity(const Element & element, UInt t) const { AKANTU_DEBUG_IN(); Matrix local_facets(getFacetLocalConnectivity(element.type, t), false); Matrix facets(local_facets.rows(), local_facets.cols()); const Array & conn = connectivities(element.type, element.ghost_type); for (UInt f = 0; f < facets.rows(); ++f) { for (UInt n = 0; n < facets.cols(); ++n) { facets(f, n) = conn(element.element, local_facets(f, n)); } } AKANTU_DEBUG_OUT(); return facets; } /* -------------------------------------------------------------------------- */ template inline void Mesh::extractNodalValuesFromElement( const Array & nodal_values, T * local_coord, UInt * connectivity, UInt n_nodes, UInt nb_degree_of_freedom) const { for (UInt n = 0; n < n_nodes; ++n) { memcpy(local_coord + n * nb_degree_of_freedom, nodal_values.storage() + connectivity[n] * nb_degree_of_freedom, nb_degree_of_freedom * sizeof(T)); } } /* -------------------------------------------------------------------------- */ inline void Mesh::addConnectivityType(const ElementType & type, const GhostType & ghost_type) { getConnectivityPointer(type, ghost_type); } /* -------------------------------------------------------------------------- */ inline bool Mesh::isPureGhostNode(UInt n) const { return nodes_type.size() ? (nodes_type(n) == _nt_pure_gost) : false; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isLocalOrMasterNode(UInt n) const { return nodes_type.size() ? (nodes_type(n) == _nt_master) || (nodes_type(n) == _nt_normal) : true; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isLocalNode(UInt n) const { return nodes_type.size() ? nodes_type(n) == _nt_normal : true; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isMasterNode(UInt n) const { return nodes_type.size() ? nodes_type(n) == _nt_master : false; } /* -------------------------------------------------------------------------- */ inline bool Mesh::isSlaveNode(UInt n) const { return nodes_type.size() ? nodes_type(n) >= 0 : false; } /* -------------------------------------------------------------------------- */ inline NodeType Mesh::getNodeType(UInt local_id) const { return nodes_type.size() ? nodes_type(local_id) : _nt_normal; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNodeGlobalId(UInt local_id) const { return nodes_global_ids ? (*nodes_global_ids)(local_id) : local_id; } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNodeLocalId(UInt global_id) const { AKANTU_DEBUG_ASSERT(nodes_global_ids != NULL, "The global ids are note set."); return nodes_global_ids->find(global_id); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbGlobalNodes() const { return nodes_global_ids ? nb_global_nodes : nodes->size(); } /* -------------------------------------------------------------------------- */ inline UInt Mesh::getNbNodesPerElementList(const Array & elements) { 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 Mesh & Mesh::getMeshFacets() { if (!this->mesh_facets) AKANTU_EXCEPTION( "No facet mesh is defined yet! check the buildFacets functions"); return *this->mesh_facets; } /* -------------------------------------------------------------------------- */ inline const Mesh & Mesh::getMeshFacets() const { if (!this->mesh_facets) AKANTU_EXCEPTION( "No facet mesh is defined yet! check the buildFacets functions"); return *this->mesh_facets; } /* -------------------------------------------------------------------------- */ inline const Mesh & Mesh::getMeshParent() const { if (!this->mesh_parent) AKANTU_EXCEPTION( "No parent mesh is defined! This is only valid in a mesh_facets"); return *this->mesh_parent; } /* -------------------------------------------------------------------------- */ } // namespace akantu #endif /* __AKANTU_MESH_INLINE_IMPL_CC__ */ diff --git a/src/mesh_utils/mesh_partition.cc b/src/mesh_utils/mesh_partition.cc index 51d33e0f3..7ea859330 100644 --- a/src/mesh_utils/mesh_partition.cc +++ b/src/mesh_utils/mesh_partition.cc @@ -1,421 +1,421 @@ /** * @file mesh_partition.cc * * @author David Simon Kammer * @author Nicolas Richart * * @date creation: Tue Aug 17 2010 * @date last modification: Fri Jan 22 2016 * * @brief implementation of common part of all partitioner * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "mesh_partition.hh" #include "aka_iterators.hh" #include "aka_types.hh" +#include "mesh_accessor.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ MeshPartition::MeshPartition(const Mesh & mesh, UInt spatial_dimension, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), mesh(mesh), spatial_dimension(spatial_dimension), partitions("partition", id, memory_id), ghost_partitions("ghost_partition", id, memory_id), ghost_partitions_offset("ghost_partition_offset", id, memory_id), saved_connectivity("saved_connectivity", id, memory_id), - lin_to_element(mesh.getNbElement(spatial_dimension)){ + lin_to_element(mesh.getNbElement(spatial_dimension)) { AKANTU_DEBUG_IN(); - Element elem; elem.ghost_type = _not_ghost; lin_to_element.resize(0); for (auto && type : mesh.elementTypes(spatial_dimension, _not_ghost, _ek_not_defined)) { elem.type = type; for (auto && i : arange(mesh.getNbElement(elem.type))) { elem.element = i; lin_to_element.push_back(elem); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ MeshPartition::~MeshPartition() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * TODO this function should most probably be rewritten in a more modern way * conversion in c++ of the GENDUALMETIS (mesh.c) function wrote by George in * Metis (University of Minnesota) */ void MeshPartition::buildDualGraph(Array & dxadj, Array & dadjncy, Array & edge_loads, const EdgeLoadFunctor & edge_load_func) { AKANTU_DEBUG_IN(); // tweak mesh; UInt nb_good_types = 0; std::vector nb_nodes_per_element_p1; std::vector magic_number; std::vector nb_element; std::vector *> connectivities; Element elem; elem.ghost_type = _not_ghost; UInt spatial_dimension = mesh.getSpatialDimension(); for (auto & type : mesh.elementTypes(spatial_dimension, _not_ghost, _ek_not_defined)) { elem.type = type; ElementType type_p1 = Mesh::getP1ElementType(type); connectivities.push_back( &const_cast &>(mesh.getConnectivity(type, _not_ghost))); nb_nodes_per_element_p1.push_back(Mesh::getNbNodesPerElement(type_p1)); nb_element.push_back(connectivities.back()->size()); magic_number.push_back( Mesh::getNbNodesPerElement(Mesh::getFacetType(type_p1))); ++nb_good_types; } CSR node_to_elem; MeshUtils::buildNode2Elements(mesh, node_to_elem); UInt nb_total_element = std::accumulate(nb_element.begin(), nb_element.end(), 0); dxadj.resize(nb_total_element + 1); /// initialize the dxadj array auto dxadj_it = dxadj.begin(); for (auto && t : arange(nb_good_types)) { std::fill_n(dxadj_it, nb_element[t], nb_nodes_per_element_p1[t]); dxadj_it += nb_element[t]; } /// convert the dxadj_val array in a csr one for (UInt i = 1; i < nb_total_element; ++i) dxadj(i) += dxadj(i - 1); for (UInt i = nb_total_element; i > 0; --i) dxadj(i) = dxadj(i - 1); dxadj(0) = 0; dadjncy.resize(2 * dxadj(nb_total_element)); edge_loads.resize(2 * dxadj(nb_total_element)); /// weight map to determine adjacency std::unordered_map weight_map; for (UInt t = 0, linerized_el = 0; t < nb_good_types; ++t) { - auto conn_it = connectivities[t]->begin(connectivities[t]->getNbComponent()); + auto conn_it = + connectivities[t]->begin(connectivities[t]->getNbComponent()); auto conn_end = connectivities[t]->end(connectivities[t]->getNbComponent()); for (; conn_it != conn_end; ++conn_it, ++linerized_el) { /// fill the weight map const auto & conn = *conn_it; for (UInt n : arange(nb_nodes_per_element_p1[t])) { auto && node = conn(n); for (auto k = node_to_elem.rbegin(node); k != node_to_elem.rend(node); --k) { auto && current_element = *k; auto && current_el = lin_to_element.find(current_element); if (current_el <= linerized_el) break; auto && weight_map_insert = weight_map.insert(std::make_pair(current_el, 1)); if (not weight_map_insert.second) (weight_map_insert.first->second)++; } } /// each element with a weight of the size of a facet are adjacent for (auto && weight_pair : weight_map) { UInt magic, adjacent_el; std::tie(adjacent_el, magic) = weight_pair; if (magic == magic_number[t]) { #if defined(AKANTU_COHESIVE_ELEMENT) /// Patch in order to prevent neighboring cohesive elements /// from detecting each other ElementKind linearized_el_kind = lin_to_element(linerized_el).kind; ElementKind adjacent_el_kind = lin_to_element(adjacent_el).kind; if (linearized_el_kind == adjacent_el_kind && linearized_el_kind == _ek_cohesive) continue; #endif UInt index_adj = dxadj(adjacent_el)++; UInt index_lin = dxadj(linerized_el)++; dadjncy(index_lin) = adjacent_el; dadjncy(index_adj) = linerized_el; } } weight_map.clear(); } } Int k_start = 0; for (UInt t = 0, linerized_el = 0, j = 0; t < nb_good_types; ++t) for (UInt el = 0; el < nb_element[t]; ++el, ++linerized_el) { for (Int k = k_start; k < dxadj(linerized_el); ++k, ++j) dadjncy(j) = dadjncy(k); dxadj(linerized_el) = j; k_start += nb_nodes_per_element_p1[t]; } for (UInt i = nb_total_element; i > 0; --i) dxadj(i) = dxadj(i - 1); dxadj(0) = 0; UInt adj = 0; for (UInt i = 0; i < nb_total_element; ++i) { UInt nb_adj = dxadj(i + 1) - dxadj(i); for (UInt j = 0; j < nb_adj; ++j, ++adj) { Int el_adj_id = dadjncy(dxadj(i) + j); Element el = lin_to_element(i); Element el_adj = lin_to_element(el_adj_id); Int load = edge_load_func(el, el_adj); edge_loads(adj) = load; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshPartition::fillPartitionInformation( const Mesh & mesh, const Int * linearized_partitions) { AKANTU_DEBUG_IN(); CSR node_to_elem; MeshUtils::buildNode2Elements(mesh, node_to_elem); UInt linearized_el = 0; for (auto & type : mesh.elementTypes(spatial_dimension, _not_ghost, _ek_not_defined)) { UInt nb_element = mesh.getNbElement(type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); partitions.alloc(nb_element, 1, type, _not_ghost); auto & ghost_part_csr = ghost_partitions_csr(type, _not_ghost); ghost_part_csr.resizeRows(nb_element); ghost_partitions_offset.alloc(nb_element + 1, 1, type, _ghost); ghost_partitions.alloc(0, 1, type, _ghost); const Array & connectivity = mesh.getConnectivity(type, _not_ghost); for (UInt el = 0; el < nb_element; ++el, ++linearized_el) { UInt part = linearized_partitions[linearized_el]; partitions(type, _not_ghost)(el) = part; std::list list_adj_part; for (UInt n = 0; n < nb_nodes_per_element; ++n) { UInt node = connectivity.storage()[el * nb_nodes_per_element + n]; CSR::iterator ne; for (ne = node_to_elem.begin(node); ne != node_to_elem.end(node); ++ne) { const Element & adj_element = *ne; UInt adj_el = lin_to_element.find(adj_element); UInt adj_part = linearized_partitions[adj_el]; if (part != adj_part) { list_adj_part.push_back(adj_part); } } } list_adj_part.sort(); list_adj_part.unique(); for (auto & adj_part : list_adj_part) { ghost_part_csr.getRows().push_back(adj_part); ghost_part_csr.rowOffset(el)++; ghost_partitions(type, _ghost).push_back(adj_part); ghost_partitions_offset(type, _ghost)(el)++; } } ghost_part_csr.countToCSR(); /// convert the ghost_partitions_offset array in an offset array Array & ghost_partitions_offset_ptr = ghost_partitions_offset(type, _ghost); for (UInt i = 1; i < nb_element; ++i) ghost_partitions_offset_ptr(i) += ghost_partitions_offset_ptr(i - 1); for (UInt i = nb_element; i > 0; --i) ghost_partitions_offset_ptr(i) = ghost_partitions_offset_ptr(i - 1); ghost_partitions_offset_ptr(0) = 0; } // All Facets for (Int sp = spatial_dimension - 1; sp >= 0; --sp) { for (auto & type : mesh.elementTypes(sp, _not_ghost, _ek_not_defined)) { UInt nb_element = mesh.getNbElement(type); partitions.alloc(nb_element, 1, type, _not_ghost); AKANTU_DEBUG_INFO("Allocating partitions for " << type); auto & ghost_part_csr = ghost_partitions_csr(type, _not_ghost); ghost_part_csr.resizeRows(nb_element); ghost_partitions_offset.alloc(nb_element + 1, 1, type, _ghost); ghost_partitions.alloc(0, 1, type, _ghost); AKANTU_DEBUG_INFO("Allocating ghost_partitions for " << type); const Array> & elem_to_subelem = mesh.getElementToSubelement(type, _not_ghost); for (UInt i(0); i < mesh.getNbElement(type, _not_ghost); ++i) { // Facet loop const std::vector & adjacent_elems = elem_to_subelem(i); if (!adjacent_elems.empty()) { Element min_elem; UInt min_part(std::numeric_limits::max()); std::set adjacent_parts; for (UInt j(0); j < adjacent_elems.size(); ++j) { UInt adjacent_elem_id = adjacent_elems[j].element; UInt adjacent_elem_part = partitions(adjacent_elems[j].type, adjacent_elems[j].ghost_type)(adjacent_elem_id); if (adjacent_elem_part < min_part) { min_part = adjacent_elem_part; min_elem = adjacent_elems[j]; } adjacent_parts.insert(adjacent_elem_part); } partitions(type, _not_ghost)(i) = min_part; auto git = ghost_partitions_csr(min_elem.type, _not_ghost) .begin(min_elem.element); auto gend = ghost_partitions_csr(min_elem.type, _not_ghost) .end(min_elem.element); for (; git != gend; ++git) { adjacent_parts.insert(min_part); } adjacent_parts.erase(min_part); for (auto & part : adjacent_parts) { ghost_part_csr.getRows().push_back(part); ghost_part_csr.rowOffset(i)++; ghost_partitions(type, _ghost).push_back(part); } ghost_partitions_offset(type, _ghost)(i + 1) = ghost_partitions_offset(type, _ghost)(i + 1) + adjacent_elems.size(); } else { partitions(type, _not_ghost)(i) = 0; } } ghost_part_csr.countToCSR(); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshPartition::tweakConnectivity(const Array & pairs) { AKANTU_DEBUG_IN(); if (pairs.size() == 0) return; 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); for (; it != end; ++it) { ElementType type = *it; Array & conn = const_cast &>(mesh.getConnectivity(type, _not_ghost)); UInt nb_nodes_per_element = conn.getNbComponent(); UInt nb_element = conn.size(); Array & saved_conn = saved_connectivity.alloc( nb_element, nb_nodes_per_element, type, _not_ghost); saved_conn.copy(conn); for (UInt i = 0; i < pairs.size(); ++i) { for (UInt el = 0; el < nb_element; ++el) { for (UInt n = 0; n < nb_nodes_per_element; ++n) { if (pairs(i, 1) == conn(el, n)) conn(el, n) = pairs(i, 0); } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshPartition::restoreConnectivity() { AKANTU_DEBUG_IN(); - - ElementTypeMapArray::type_iterator it = saved_connectivity.firstType( - spatial_dimension, _not_ghost, _ek_not_defined); - ElementTypeMapArray::type_iterator end = saved_connectivity.lastType( - spatial_dimension, _not_ghost, _ek_not_defined); - for (; it != end; ++it) { - ElementType type = *it; - - Array & conn = - const_cast &>(mesh.getConnectivity(type, _not_ghost)); - Array & saved_conn = saved_connectivity(type, _not_ghost); + MeshAccessor mesh_accessor(const_cast(mesh)); + for (auto && type : saved_connectivity.elementTypes( + spatial_dimension, _not_ghost, _ek_not_defined)) { + auto & conn = mesh_accessor.getConnectivity(type, _not_ghost); + auto & saved_conn = saved_connectivity(type, _not_ghost); conn.copy(saved_conn); } - AKANTU_DEBUG_OUT(); } +/* -------------------------------------------------------------------------- */ +bool MeshPartition::hasPartitions(const ElementType & type, + const GhostType & ghost_type) { + return partitions.exists(type, ghost_type); +} + /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/mesh_utils/mesh_partition.hh b/src/mesh_utils/mesh_partition.hh index 6e9909bb1..7f834ce03 100644 --- a/src/mesh_utils/mesh_partition.hh +++ b/src/mesh_utils/mesh_partition.hh @@ -1,150 +1,151 @@ /** * @file mesh_partition.hh * * @author David Simon Kammer * @author Nicolas Richart * * @date creation: Fri Jun 18 2010 * @date last modification: Tue Sep 01 2015 * * @brief tools to partitionate a mesh * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MESH_PARTITION_HH__ #define __AKANTU_MESH_PARTITION_HH__ /* -------------------------------------------------------------------------- */ #include "aka_csr.hh" #include "aka_memory.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class MeshPartition : protected Memory { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: MeshPartition(const Mesh & mesh, UInt spatial_dimension, const ID & id = "MeshPartitioner", const MemoryID & memory_id = 0); virtual ~MeshPartition(); class EdgeLoadFunctor { public: virtual Int operator()(const Element & el1, const Element & el2) const noexcept = 0; }; class ConstEdgeLoadFunctor : public EdgeLoadFunctor { public: virtual inline Int operator()(const Element &, const Element &) const noexcept { return 1; } }; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// define a partition of the mesh virtual void partitionate(UInt nb_part, const EdgeLoadFunctor & edge_load_func = ConstEdgeLoadFunctor(), const Array & pairs = Array()) = 0; /// reorder the nodes to reduce the filling during the factorization of a /// matrix that has a profil based on the connectivity of the mesh virtual void reorder() = 0; /// fill the partitions array with a given linearized partition information void fillPartitionInformation(const Mesh & mesh, const Int * linearized_partitions); protected: /// build the dual graph of the mesh, for all element of spatial_dimension void buildDualGraph(Array & dxadj, Array & dadjncy, Array & edge_loads, const EdgeLoadFunctor & edge_load_func); /// tweak the mesh to handle the PBC pairs void tweakConnectivity(const Array & pairs); /// restore the mesh that has been tweaked void restoreConnectivity(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: + bool hasPartitions(const ElementType & type, const GhostType & ghost_type); AKANTU_GET_MACRO(Partitions, partitions, const ElementTypeMapArray &); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Partition, partitions, UInt); AKANTU_GET_MACRO(GhostPartitionCSR, ghost_partitions_csr, const ElementTypeMap> &); AKANTU_GET_MACRO(NbPartition, nb_partitions, UInt); AKANTU_SET_MACRO(NbPartition, nb_partitions, UInt); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// id std::string id; /// the mesh to partition const Mesh & mesh; /// dimension of the elements to consider in the mesh UInt spatial_dimension; /// number of partitions UInt nb_partitions; /// partition numbers ElementTypeMapArray partitions; ElementTypeMap> ghost_partitions_csr; ElementTypeMapArray ghost_partitions; ElementTypeMapArray ghost_partitions_offset; Array * permutation; ElementTypeMapArray saved_connectivity; Array lin_to_element; }; } // namespace akantu #ifdef AKANTU_USE_SCOTCH #include "mesh_partition_scotch.hh" #endif #endif /* __AKANTU_MESH_PARTITION_HH__ */ diff --git a/src/mesh_utils/mesh_utils.cc b/src/mesh_utils/mesh_utils.cc index f54677e50..a6f1693e7 100644 --- a/src/mesh_utils/mesh_utils.cc +++ b/src/mesh_utils/mesh_utils.cc @@ -1,2342 +1,2342 @@ /** * @file mesh_utils.cc * * @author Guillaume Anciaux * @author Dana Christen * @author David Simon Kammer * @author Nicolas Richart * @author Leonardo Snozzi * @author Marco Vocialta * * @date creation: Fri Aug 20 2010 * @date last modification: Fri Jan 22 2016 * * @brief All mesh utils necessary for various tasks * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "mesh_utils.hh" #include "element_synchronizer.hh" #include "fe_engine.hh" #include "mesh_accessor.hh" /* -------------------------------------------------------------------------- */ #include #include #include #include /* -------------------------------------------------------------------------- */ namespace 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, _ek_not_defined); Mesh::type_iterator last = mesh.lastType(spatial_dimension, *gt, _ek_not_defined); for (; first != last; ++first) { ElementType type = *first; UInt nb_element = mesh.getNbElement(type, *gt); Array::const_iterator> 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, _ek_not_defined); Mesh::type_iterator last = mesh.lastType(spatial_dimension, *gt, _ek_not_defined); e.ghost_type = *gt; for (; first != last; ++first) { ElementType type = *first; e.type = type; e.kind = Mesh::getKind(type); UInt nb_element = mesh.getNbElement(type, *gt); Array::const_iterator> 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 (used in mesh partitioning) */ // 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; // Vector nb_nodes_per_element(nb_types); // UInt ** conn_val = new UInt *[nb_types]; // Vector 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).storage(); // nb_element[nb_good_types] = // mesh.getConnectivity(type, _not_ghost).size(); // 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(); // delete[] conn_val; // AKANTU_DEBUG_OUT(); // } /* -------------------------------------------------------------------------- */ void MeshUtils::buildNode2ElementsElementTypeMap(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).size(); 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(); 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); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt to_dimension) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); buildAllFacets(mesh, mesh_facets, spatial_dimension, to_dimension); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildAllFacets(const Mesh & mesh, Mesh & mesh_facets, UInt from_dimension, UInt to_dimension) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT( mesh_facets.isMeshFacets(), "The mesh_facets should be initialized with initMeshFacets"); const ElementTypeMapArray * prank_to_element = nullptr; if (mesh.isDistributed()) { prank_to_element = &(mesh.getElementSynchronizer().getPrankToElement()); } /// generate facets buildFacetsDimension(mesh, mesh_facets, false, from_dimension, prank_to_element); /// copy nodes type MeshAccessor mesh_accessor_facets(mesh_facets); mesh_accessor_facets.getNodesType().copy(mesh.getNodesType()); /// sort facets and generate sub-facets for (UInt i = from_dimension - 1; i > to_dimension; --i) { buildFacetsDimension(mesh_facets, mesh_facets, false, i, prank_to_element); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::buildFacetsDimension( const Mesh & mesh, Mesh & mesh_facets, bool boundary_only, UInt dimension, const ElementTypeMapArray * prank_to_element) { AKANTU_DEBUG_IN(); // save the current parent of mesh_facets and set it temporarly to mesh since // mesh is the one containing the elements for which mesh_facets has the // sub-elements // example: if the function is called with mesh = mesh_facets const Mesh * mesh_facets_parent = nullptr; try { mesh_facets_parent = &mesh_facets.getMeshParent(); } catch (...) { } mesh_facets.defineMeshParent(mesh); MeshAccessor mesh_accessor(mesh_facets); UInt spatial_dimension = mesh.getSpatialDimension(); const Array & mesh_facets_nodes = mesh_facets.getNodes(); const Array::const_vector_iterator mesh_facets_nodes_it = mesh_facets_nodes.begin(spatial_dimension); CSR node_to_elem; buildNode2Elements(mesh, node_to_elem, dimension); Array counter; std::vector connected_elements; // init the SubelementToElement data to improve performance 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; mesh_accessor.getSubelementToElement(type, ghost_type); Vector facet_types = mesh.getAllFacetTypes(type); for (UInt ft = 0; ft < facet_types.size(); ++ft) { ElementType facet_type = facet_types(ft); mesh_accessor.getElementToSubelement(facet_type, ghost_type); mesh_accessor.getConnectivity(facet_type, ghost_type); } } } 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; Vector facet_types = mesh.getAllFacetTypes(type); current_element.type = type; for (UInt ft = 0; ft < facet_types.size(); ++ft) { ElementType facet_type = facet_types(ft); UInt nb_element = mesh.getNbElement(type, ghost_type); Array> * element_to_subelement = &mesh_facets.getElementToSubelement(facet_type, ghost_type); Array * connectivity_facets = &mesh_facets.getConnectivity(facet_type, ghost_type); UInt nb_facet_per_element = mesh.getNbFacetsPerElement(type, ft); const Array & element_connectivity = mesh.getConnectivity(type, ghost_type); const Matrix facet_local_connectivity = mesh.getFacetLocalConnectivity(type, ft); UInt nb_nodes_per_facet = connectivity_facets->getNbComponent(); Vector facet(nb_nodes_per_facet); for (UInt el = 0; el < nb_element; ++el) { current_element.element = el; for (UInt f = 0; f < nb_facet_per_element; ++f) { for (UInt n = 0; n < nb_nodes_per_facet; ++n) facet(n) = element_connectivity(el, facet_local_connectivity(f, n)); UInt first_node_nb_elements = node_to_elem.getNbCols(facet(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; connected_elements.clear(); 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] = {_not_ghost, _not_ghost}; for (UInt el = 0; el < connected_elements.size(); ++el) gt[el] = connected_elements[el].ghost_type; if (gt[0] + gt[1] == 1) { if (prank_to_element) { 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; const 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); } } } /// 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->size() - 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(loc_el.type, loc_el.ghost_type); UInt nb_facet_per_loc_element = subelement_to_element.getNbComponent(); for (UInt f_in = 0; f_in < nb_facet_per_loc_element; ++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_accessor.getConnectivity( facet_type, facet_ghost_type); element_to_subelement = &mesh_accessor.getElementToSubelement(facet_type, facet_ghost_type); } } } } } } } } } // restore the parent of mesh_facet if (mesh_facets_parent) mesh_facets.defineMeshParent(*mesh_facets_parent); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::renumberMeshNodes(Mesh & mesh, Array & 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.size(); ++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; + for (auto & renumber_pair : renumbering_map) { + old_nodes_numbers(renumber_pair.second) = renumber_pair.first; } renumbering_map.clear(); MeshAccessor mesh_accessor(mesh); /// copy the renumbered connectivity to the right place - Array & local_conn = mesh_accessor.getConnectivity(type); + auto & local_conn = mesh_accessor.getConnectivity(type); local_conn.resize(nb_local_element); memcpy(local_conn.storage(), local_connectivities.storage(), nb_local_element * nb_nodes_per_element * sizeof(UInt)); - Array & ghost_conn = mesh_accessor.getConnectivity(type, _ghost); + auto & ghost_conn = mesh_accessor.getConnectivity(type, _ghost); ghost_conn.resize(nb_ghost_element); - memcpy(ghost_conn.storage(), - local_connectivities.storage() + - nb_local_element * nb_nodes_per_element, - nb_ghost_element * nb_nodes_per_element * sizeof(UInt)); + std::memcpy(ghost_conn.storage(), + local_connectivities.storage() + + nb_local_element * nb_nodes_per_element, + nb_ghost_element * nb_nodes_per_element * sizeof(UInt)); + auto & ghost_counter = mesh_accessor.getGhostsCounters(type, _ghost); + ghost_counter.resize(nb_ghost_element, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MeshUtils::renumberNodesInConnectivity( Array & list_nodes, UInt nb_nodes, std::map & renumbering_map) { AKANTU_DEBUG_IN(); UInt * connectivity = list_nodes.storage(); 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); Array & connectivity = mesh.getConnectivity(type, ghost_type); UInt nb_element(connectivity.size()); 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.size(); ++i) { if (new_numbering(i) == UInt(-1)) nodes_removed.push_back(i); } mesh.sendEvent(remove_nodes); AKANTU_DEBUG_OUT(); } #if defined(AKANTU_COHESIVE_ELEMENT) /* -------------------------------------------------------------------------- */ UInt MeshUtils::insertCohesiveElements( Mesh & mesh, Mesh & mesh_facets, const ElementTypeMapArray & facet_insertion, Array & doubled_nodes, Array & new_elements, bool only_double_facets) { UInt spatial_dimension = mesh.getSpatialDimension(); UInt elements_to_insert = updateFacetToDouble(mesh_facets, facet_insertion); if (elements_to_insert > 0) { 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); } } if (!only_double_facets) updateCohesiveData(mesh, mesh_facets, new_elements); } return elements_to_insert; } #endif /* -------------------------------------------------------------------------- */ void MeshUtils::doubleNodes(Mesh & mesh, const std::vector & old_nodes, Array & doubled_nodes) { AKANTU_DEBUG_IN(); Array & position = mesh.getNodes(); UInt spatial_dimension = mesh.getSpatialDimension(); UInt old_nb_nodes = position.size(); UInt new_nb_nodes = old_nb_nodes + old_nodes.size(); UInt old_nb_doubled_nodes = doubled_nodes.size(); UInt new_nb_doubled_nodes = old_nb_doubled_nodes + old_nodes.size(); 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.size(); ++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.size(); 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.size(); 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(); } /* -------------------------------------------------------------------------- */ UInt MeshUtils::updateFacetToDouble( Mesh & mesh_facets, const ElementTypeMapArray & facet_insertion) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); UInt nb_facets_to_double = 0.; 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> & 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.size(); ++f) { if (f_insertion(f) == false) continue; ++nb_facets_to_double; if (element_to_facet(f)[1].type == _not_defined #if defined(AKANTU_COHESIVE_ELEMENT) || element_to_facet(f)[1].kind == _ek_cohesive #endif ) { 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.size() - 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 nb_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, false); mesh_facets.getDataPointer>( "facets_to_subfacet_double", type, gt, 1, false); mesh_facets.getDataPointer>( "elements_to_subfacet_double", type, gt, 1, false); mesh_facets.getDataPointer>( "subfacets_to_subsubfacet_double", type, gt, 1, false); } } 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.size(); 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> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); Array * subsubfacet_to_subfacet = NULL; UInt old_nb_facet = subfacet_to_facet.size() - 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> * 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(); } /* -------------------------------------------------------------------------- */ #if defined(AKANTU_COHESIVE_ELEMENT) void MeshUtils::updateCohesiveData(Mesh & mesh, Mesh & mesh_facets, Array & new_elements) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); bool third_dimension = spatial_dimension == 3; MeshAccessor mesh_facets_accessor(mesh_facets); for (auto gt_facet : ghost_types) { for (auto type_facet : mesh_facets.elementTypes(spatial_dimension - 1, gt_facet)) { Array & f_to_double = mesh_facets.getData("facet_to_double", type_facet, gt_facet); UInt nb_facet_to_double = f_to_double.size(); if (nb_facet_to_double == 0) continue; ElementType type_cohesive = FEEngine::getCohesiveElementType(type_facet); auto & facet_to_coh_element = mesh_facets_accessor.getSubelementToElement(type_cohesive, gt_facet); auto & conn_facet = mesh_facets.getConnectivity(type_facet, gt_facet); auto & conn_cohesive = mesh.getConnectivity(type_cohesive, gt_facet); UInt nb_nodes_per_facet = Mesh::getNbNodesPerElement(type_facet); Array> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); UInt old_nb_cohesive_elements = conn_cohesive.size(); UInt new_nb_cohesive_elements = conn_cohesive.size() + nb_facet_to_double; UInt old_nb_facet = element_to_facet.size() - nb_facet_to_double; facet_to_coh_element.resize(new_nb_cohesive_elements); conn_cohesive.resize(new_nb_cohesive_elements); UInt new_elements_old_size = new_elements.size(); 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 new_elements(new_elements_old_size + facet) = c_element; } } } AKANTU_DEBUG_OUT(); } #endif /* -------------------------------------------------------------------------- */ 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> & 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.size(); UInt old_nb_facet = element_to_facet.size() - nb_facet_to_double; UInt new_nb_facet = element_to_facet.size(); UInt old_nb_nodes = position.size(); 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.size(); 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.size(); 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> & element_to_facet = mesh_facets.getElementToSubelement(type_facet, gt_facet); /// this ones matter only for segments in 3D Array> * el_to_subfacet_double = NULL; Array> * 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); } std::vector middle_nodes; 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); } UInt n = doubled_nodes.size(); doubleNodes(mesh, middle_nodes, doubled_nodes); for (UInt facet = 0; facet < nb_facet_to_double; ++facet) { UInt old_facet = f_to_double(facet); UInt old_node = conn_facet(old_facet, 2); if (mesh.isPureGhostNode(old_node)) continue; UInt new_node = doubled_nodes(n, 1); UInt new_facet = old_nb_facet + facet; 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)(facet), &(*f_to_subfacet_double)(facet)); } else { updateElementalConnectivity(mesh, old_node, new_node, element_to_facet(new_facet)); } ++n; } 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.size(); /// 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.size(); Array> & facet_to_subfacet = mesh_facets.getElementToSubelement(type_subfacet, gt_subfacet); Array> * 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); } UInt old_nb_subfacet = facet_to_subfacet.size(); facet_to_subfacet.resize(old_nb_subfacet + nb_subfacet_to_double); for (UInt sf = 0; sf < nb_subfacet_to_double; ++sf) facet_to_subfacet(old_nb_subfacet + sf) = (*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.size(); 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.size(); UInt new_nb_subfacet = old_nb_subfacet + nb_subfacet_to_double; conn_subfacet.resize(new_nb_subfacet); std::vector nodes_to_double; UInt old_nb_doubled_nodes = doubled_nodes.size(); /// 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 ElementTypeMapArray & global_connectivity, GhostType gt_facet) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh_facets.getSpatialDimension(); /// get global connectivity for local mesh ElementTypeMapArray global_connectivity_tmp("global_connectivity_tmp", mesh_facets.getID(), mesh_facets.getMemoryID()); global_connectivity_tmp.initialize( mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_nodes_per_element = true, _with_nb_element = true); // mesh_facets.initElementTypeMapArray(global_connectivity_tmp, 1, // spatial_dimension - 1, gt_facet, // true, _ek_regular, true); mesh_facets.getGlobalConnectivity(global_connectivity_tmp, spatial_dimension - 1, gt_facet); /// loop on every facet for (auto type_facet : mesh_facets.elementTypes(spatial_dimension - 1, gt_facet)) { auto & connectivity = mesh_facets.getConnectivity(type_facet, gt_facet); const auto & g_connectivity = global_connectivity(type_facet, gt_facet); auto & el_to_f = mesh_facets.getElementToSubelement(type_facet, gt_facet); auto & 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.size(); UInt nb_nodes_per_P1_facet = Mesh::getNbNodesPerElement(Mesh::getP1ElementType(type_facet)); auto & global_conn_tmp = global_connectivity_tmp(type_facet, gt_facet); auto conn_it = connectivity.begin(nb_nodes_per_facet); auto gconn_tmp_it = global_conn_tmp.begin(nb_nodes_per_facet); auto conn_glob_it = g_connectivity.begin(nb_nodes_per_facet); auto 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_INFO("There are not facets, add them in the mesh file or call " "the buildFacet method."); return; } UInt spatial_dimension = mesh.getSpatialDimension(); ElementTypeMapArray barycenters("barycenter_tmp", mesh.getID(), mesh.getMemoryID()); barycenters.initialize(mesh, _nb_component = spatial_dimension, _spatial_dimension = _all_dimensions); // mesh.initElementTypeMapArray(barycenters, spatial_dimension, // _all_dimensions); Element element; for (auto ghost_type : ghost_types) { element.ghost_type = ghost_type; for (auto & type : mesh.elementTypes(_all_dimensions, ghost_type)) { element.type = type; UInt nb_element = mesh.getNbElement(type, ghost_type); Array & barycenters_arr = barycenters(type, ghost_type); barycenters_arr.resize(nb_element); auto bary = barycenters_arr.begin(spatial_dimension); auto bary_end = barycenters_arr.end(spatial_dimension); for (UInt el = 0; bary != bary_end; ++bary, ++el) { element.element = el; mesh.getBarycenter(element, *bary); } } } MeshAccessor mesh_accessor(mesh); for (Int sp(spatial_dimension); sp >= 1; --sp) { if (mesh.getNbElement(sp) == 0) continue; for (auto ghost_type : ghost_types) { for (auto & type : mesh.elementTypes(sp, ghost_type)) { mesh_accessor.getSubelementToElement(type, ghost_type) .resize(mesh.getNbElement(type, ghost_type)); mesh_accessor.getSubelementToElement(type, ghost_type).clear(); } for (auto & type : mesh.elementTypes(sp - 1, ghost_type)) { mesh_accessor.getElementToSubelement(type, ghost_type) .resize(mesh.getNbElement(type, ghost_type)); mesh.getElementToSubelement(type, ghost_type).clear(); } } CSR nodes_to_elements; buildNode2Elements(mesh, nodes_to_elements, sp); Element facet_element; for (auto ghost_type : ghost_types) { facet_element.ghost_type = ghost_type; for (auto & type : mesh.elementTypes(sp - 1, ghost_type)) { facet_element.type = type; auto & element_to_subelement = mesh.getElementToSubelement(type, ghost_type); const auto & connectivity = mesh.getConnectivity(type, ghost_type); auto fit = connectivity.begin(mesh.getNbNodesPerElement(type)); auto fend = connectivity.end(mesh.getNbNodesPerElement(type)); 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(type)); for (UInt n(0); n < nb_nodes_per_facet; ++n) { auto eit = nodes_to_elements.begin(facet(n)); auto eend = nodes_to_elements.end(facet(n)); for (; eit != eend; ++eit) { auto & elem = *eit; auto cit = element_seen_counter.find(elem); if (cit != element_seen_counter.end()) { cit->second++; } else { element_seen_counter[elem] = 1; } } } std::vector connected_elements; auto cit = element_seen_counter.begin(); auto cend = element_seen_counter.end(); for (; cit != cend; ++cit) { if (cit->second == nb_nodes_per_facet) connected_elements.push_back(cit->first); } auto ceit = connected_elements.begin(); auto 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_accessor.getSubelementToElement(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!! (" << f << " < " << mesh.getNbFacetsPerElement(elem.type) << ")"); 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.clear(); facet_list.clear(); if (third_dim_points) subfacet_list->clear(); 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> * element_to_facet = NULL; const Element * opposing_el = NULL; std::queue elements_to_check; elements_to_check.push(starting_element); /// keep going until there are elements to check while (!elements_to_check.empty()) { /// check current element Element & current_el = elements_to_check.front(); 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(*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.pop(); } AKANTU_DEBUG_OUT(); return facet_matched; } /* -------------------------------------------------------------------------- */ // void MeshUtils::buildSegmentToNodeType(const Mesh & mesh, Mesh & mesh_facets) { // buildAllFacets(mesh, mesh_facets, 1); // UInt spatial_dimension = mesh.getSpatialDimension(); // const ElementTypeMapArray & element_to_rank = // mesh.getElementSynchronizer().getPrankToElement(); // Int local_rank = StaticCommunicator::getStaticCommunicator().whoAmI(); // 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(1, ghost_type); // Mesh::type_iterator end = mesh_facets.lastType(1, ghost_type); // for (; it != end; ++it) { // ElementType type = *it; // UInt nb_segments = mesh_facets.getNbElement(type, ghost_type); // // allocate the data // Array & segment_to_nodetype = *(mesh_facets.getDataPointer( // "segment_to_nodetype", type, ghost_type)); // std::set connected_elements; // const Array> & segment_to_2Delement = // mesh_facets.getElementToSubelement(type, ghost_type); // // loop over segments // for (UInt s = 0; s < nb_segments; ++s) { // // determine the elements connected to the segment // connected_elements.clear(); // const std::vector & twoD_elements = segment_to_2Delement(s); // if (spatial_dimension == 2) { // // if 2D just take the elements connected to the segments // connected_elements.insert(twoD_elements.begin(), twoD_elements.end()); // } else if (spatial_dimension == 3) { // // if 3D a second loop is needed to get to the 3D elements // std::vector::const_iterator facet = twoD_elements.begin(); // for (; facet != twoD_elements.end(); ++facet) { // const std::vector & threeD_elements = // mesh_facets.getElementToSubelement( // facet->type, facet->ghost_type)(facet->element); // connected_elements.insert(threeD_elements.begin(), // threeD_elements.end()); // } // } // // get the minimum processor rank associated to the connected // // elements and verify if ghost and not ghost elements are // // found // Int minimum_rank = std::numeric_limits::max(); // // two booleans saying if not ghost and ghost elements are found in the // // loop // bool ghost_found[2]; // ghost_found[0] = false; // ghost_found[1] = false; // std::set::iterator connected_elements_it = // connected_elements.begin(); // for (; connected_elements_it != connected_elements.end(); // ++connected_elements_it) { // if (*connected_elements_it == ElementNull) // continue; // ghost_found[connected_elements_it->ghost_type] = true; // const Array & el_to_rank_array = element_to_rank( // connected_elements_it->type, connected_elements_it->ghost_type); // minimum_rank = // std::min(minimum_rank, // Int(el_to_rank_array(connected_elements_it->element))); // } // // if no ghost elements are found the segment is local // if (!ghost_found[1]) // segment_to_nodetype(s) = -1; // // if no not ghost elements are found the segment is pure ghost // else if (!ghost_found[0]) // segment_to_nodetype(s) = -3; // // if the minimum rank is equal to the local rank, the segment is master // else if (local_rank == minimum_rank) // segment_to_nodetype(s) = -2; // // if the minimum rank is less than the local rank, the segment is slave // else if (local_rank > minimum_rank) // segment_to_nodetype(s) = minimum_rank; // else // AKANTU_DEBUG_ERROR("The local rank cannot be smaller than the " // "minimum rank if both ghost and not ghost " // "elements are found"); // } // } // } // } /* -------------------------------------------------------------------------- */ UInt MeshUtils::updateLocalMasterGlobalConnectivity(Mesh & mesh, UInt local_nb_new_nodes) { StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); Int rank = comm.whoAmI(); Int nb_proc = comm.getNbProc(); if (nb_proc == 1) return local_nb_new_nodes; /// resize global ids array Array & nodes_global_ids = mesh.getGlobalNodesIds(); UInt old_nb_nodes = mesh.getNbNodes() - local_nb_new_nodes; nodes_global_ids.resize(mesh.getNbNodes()); /// compute the number of global nodes based on the number of old nodes Vector old_local_master_nodes(nb_proc); for (UInt n = 0; n < old_nb_nodes; ++n) if (mesh.isLocalOrMasterNode(n)) ++old_local_master_nodes(rank); comm.allGather(old_local_master_nodes); UInt old_global_nodes = std::accumulate(old_local_master_nodes.storage(), old_local_master_nodes.storage() + nb_proc, 0); /// compute amount of local or master doubled nodes Vector local_master_nodes(nb_proc); for (UInt n = old_nb_nodes; n < mesh.getNbNodes(); ++n) if (mesh.isLocalOrMasterNode(n)) ++local_master_nodes(rank); comm.allGather(local_master_nodes); /// 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, old_global_nodes); for (UInt n = old_nb_nodes; n < mesh.getNbNodes(); ++n) { if (mesh.isLocalOrMasterNode(n)) { nodes_global_ids(n) = starting_index; ++starting_index; } } MeshAccessor mesh_accessor(mesh); mesh_accessor.setNbGlobalNodes(old_global_nodes + total_nb_new_nodes); return total_nb_new_nodes; } /* -------------------------------------------------------------------------- */ // Deactivating -Wunused-parameter #if defined(__INTEL_COMPILER) //#pragma warning ( disable : 383 ) #elif defined(__clang__) // test clang to be sure that when we test for gnu it // is only gnu #elif (defined(__GNUC__) || defined(__GNUG__)) #define GCC_VERSION \ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #if GCC_VERSION > 40600 #pragma GCC diagnostic push #endif #pragma GCC diagnostic ignored "-Wunused-parameter" #endif /* -------------------------------------------------------------------------- */ void MeshUtils::updateElementalConnectivity( Mesh & mesh, UInt old_node, UInt new_node, const std::vector & element_list, __attribute__((unused)) const std::vector * facet_list) { AKANTU_DEBUG_IN(); ElementType el_type = _not_defined; GhostType gt_type = _casper; Array * conn_elem = NULL; #if defined(AKANTU_COHESIVE_ELEMENT) const Array * cohesive_facets = NULL; #endif UInt nb_nodes_per_element = 0; UInt * n_update = NULL; for (UInt el = 0; el < element_list.size(); ++el) { const Element & elem = element_list[el]; if (elem.type == _not_defined) continue; if (elem.type != el_type || elem.ghost_type != gt_type) { el_type = elem.type; gt_type = elem.ghost_type; conn_elem = &mesh.getConnectivity(el_type, gt_type); nb_nodes_per_element = conn_elem->getNbComponent(); #if defined(AKANTU_COHESIVE_ELEMENT) if (elem.kind == _ek_cohesive) cohesive_facets = &mesh.getMeshFacets().getSubelementToElement(el_type, gt_type); #endif } #if defined(AKANTU_COHESIVE_ELEMENT) if (elem.kind == _ek_cohesive) { AKANTU_DEBUG_ASSERT( facet_list != NULL, "Provide a facet list in order to update cohesive elements"); /// loop over cohesive element's facets for (UInt f = 0, n = 0; f < 2; ++f, n += nb_nodes_per_element / 2) { const Element & facet = (*cohesive_facets)(elem.element, f); /// skip facets if not present in the list if (std::find(facet_list->begin(), facet_list->end(), facet) == facet_list->end()) continue; n_update = std::find( conn_elem->storage() + elem.element * nb_nodes_per_element + n, conn_elem->storage() + elem.element * nb_nodes_per_element + n + nb_nodes_per_element / 2, old_node); AKANTU_DEBUG_ASSERT(n_update != conn_elem->storage() + elem.element * nb_nodes_per_element + n + nb_nodes_per_element / 2, "Node not found in current element"); /// update connectivity *n_update = new_node; } } else { #endif n_update = std::find(conn_elem->storage() + elem.element * nb_nodes_per_element, conn_elem->storage() + elem.element * nb_nodes_per_element + nb_nodes_per_element, old_node); AKANTU_DEBUG_ASSERT(n_update != conn_elem->storage() + elem.element * nb_nodes_per_element + nb_nodes_per_element, "Node not found in current element"); /// update connectivity *n_update = new_node; #if defined(AKANTU_COHESIVE_ELEMENT) } #endif } AKANTU_DEBUG_OUT(); } // Reactivating -Wunused-parameter #if defined(__INTEL_COMPILER) //#pragma warning ( disable : 383 ) #elif defined(__clang__) // test clang to be sure that when we test for gnu it // is only gnu #elif defined(__GNUG__) #if GCC_VERSION > 40600 #pragma GCC diagnostic pop #else #pragma GCC diagnostic warning "-Wunused-parameter" #endif #endif /* -------------------------------------------------------------------------- */ } // namespace akantu // LocalWords: ElementType diff --git a/src/mesh_utils/mesh_utils_distribution.cc b/src/mesh_utils/mesh_utils_distribution.cc index f87bc8cc9..3fde5d53c 100644 --- a/src/mesh_utils/mesh_utils_distribution.cc +++ b/src/mesh_utils/mesh_utils_distribution.cc @@ -1,178 +1,172 @@ /** * @file mesh_utils_distribution.cc * * @author Nicolas Richart * * @date Sun Oct 2 19:23:15 2016 * * @brief Implementation of the methods of mesh utils distribute * * @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_utils_distribution.hh" #include "element_info_per_processor.hh" #include "element_synchronizer.hh" #include "mesh.hh" #include "mesh_accessor.hh" #include "mesh_partition.hh" #include "mesh_utils.hh" #include "node_info_per_processor.hh" #include "node_synchronizer.hh" /* -------------------------------------------------------------------------- */ namespace akantu { namespace MeshUtilsDistribution { /* ------------------------------------------------------------------------ */ void distributeMeshCentralized(Mesh & mesh, UInt, const MeshPartition & partition) { MeshAccessor mesh_accessor(mesh); ElementSynchronizer & element_synchronizer = mesh_accessor.getElementSynchronizer(); NodeSynchronizer & node_synchronizer = mesh_accessor.getNodeSynchronizer(); const StaticCommunicator & comm = element_synchronizer.getCommunicator(); UInt nb_proc = comm.getNbProc(); UInt my_rank = comm.whoAmI(); mesh_accessor.setNbGlobalNodes(mesh.getNbNodes()); auto & gids = mesh_accessor.getNodesGlobalIds(); if (nb_proc == 1) return; gids.resize(0); mesh.synchronizeGroupNames(); 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; - + for (auto && type : + mesh.elementTypes(_all_dimensions, _not_ghost, _ek_not_defined)) { /// \todo change this ugly way to avoid a problem if an element /// type is present in the mesh but not in the partitions try { partition.getPartition(type, _not_ghost); } catch (...) { continue; } MasterElementInfoPerProc proc_infos(element_synchronizer, count, my_rank, type, partition); proc_infos.synchronizeConnectivities(); proc_infos.synchronizePartitions(); proc_infos.synchronizeTags(); proc_infos.synchronizeGroups(); ++count; } { /// Ending the synchronization of elements by sending a stop message MasterElementInfoPerProc proc_infos(element_synchronizer, count, my_rank, _not_defined, partition); ++count; } /** * Nodes synchronization */ MasterNodeInfoPerProc node_proc_infos(node_synchronizer, count, my_rank); node_proc_infos.synchronizeNodes(); node_proc_infos.synchronizeTypes(); node_proc_infos.synchronizeGroups(); MeshUtils::fillElementToSubElementsData(mesh); mesh_accessor.setDistributed(); AKANTU_DEBUG_OUT(); } /* ------------------------------------------------------------------------ */ void distributeMeshCentralized(Mesh & mesh, UInt root) { MeshAccessor mesh_accessor(mesh); ElementSynchronizer & element_synchronizer = mesh_accessor.getElementSynchronizer(); NodeSynchronizer & node_synchronizer = mesh_accessor.getNodeSynchronizer(); const StaticCommunicator & comm = element_synchronizer.getCommunicator(); UInt nb_proc = comm.getNbProc(); mesh_accessor.getNodesGlobalIds().resize(0); if (nb_proc == 1) return; mesh.synchronizeGroupNames(); /** * connectivity and communications scheme construction on distant * processors */ UInt count = 0; bool need_synchronize = true; do { /* --------<<<<-SIZE--------------------------------------------------- */ SlaveElementInfoPerProc proc_infos(element_synchronizer, count, root); need_synchronize = proc_infos.needSynchronize(); if (need_synchronize) { proc_infos.synchronizeConnectivities(); proc_infos.synchronizePartitions(); proc_infos.synchronizeTags(); proc_infos.synchronizeGroups(); } ++count; } while (need_synchronize); /** * Nodes synchronization */ SlaveNodeInfoPerProc node_proc_infos(node_synchronizer, count, root); node_proc_infos.synchronizeNodes(); node_proc_infos.synchronizeTypes(); node_proc_infos.synchronizeGroups(); MeshUtils::fillElementToSubElementsData(mesh); mesh_accessor.setDistributed(); } -} // MeshUtilsDistribution +} // namespace MeshUtilsDistribution -} // akantu +} // namespace akantu diff --git a/src/model/common/neighborhood_base.hh b/src/model/common/neighborhood_base.hh index 4b892fff2..73e5fcb22 100644 --- a/src/model/common/neighborhood_base.hh +++ b/src/model/common/neighborhood_base.hh @@ -1,148 +1,151 @@ /** * @file neighborhood_base.hh * * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Sat Sep 26 2015 * @date last modification: Wed Nov 25 2015 * * @brief Generic neighborhood of quadrature points * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NEIGHBORHOOD_BASE_HH__ #define __AKANTU_NEIGHBORHOOD_BASE_HH__ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" #include "aka_memory.hh" #include "data_accessor.hh" #include "integration_point.hh" #include "synchronizer_registry.hh" /* -------------------------------------------------------------------------- */ namespace akantu { class Model; template class SpatialGrid; class GridSynchronizer; class RemovedElementsEvent; } // namespace akantu namespace akantu { class NeighborhoodBase : protected Memory, public DataAccessor, public SynchronizerRegistry { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NeighborhoodBase(Model & model, const ElementTypeMapArray & quad_coordinates, const ID & id = "neighborhood", const MemoryID & memory_id = 0); virtual ~NeighborhoodBase(); typedef std::vector> PairList; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// intialize the neighborhood virtual void initNeighborhood(); // /// create a synchronizer registry // void createSynchronizerRegistry(DataAccessor * data_accessor); /// initialize the material computed parameter inline void insertIntegrationPoint(const IntegrationPoint & quad, const Vector & coords); /// create the pairs of quadrature points void updatePairList(); /// save the pairs of quadrature points in a file void savePairs(const std::string & filename) const; /// save the coordinates of all neighbors of a quad void saveNeighborCoords(const std::string & filename) const; /// create grid synchronizer and exchange ghost cells virtual void createGridSynchronizer() = 0; + virtual void synchronize(DataAccessor & data_accessor, + const SynchronizationTag & tag) = 0; /// inherited function from MeshEventHandler - virtual void onElementsRemoved(const Array & element_list, - const ElementTypeMapArray & new_numbering, - const RemovedElementsEvent & event) ; + virtual void + onElementsRemoved(const Array & element_list, + const ElementTypeMapArray & new_numbering, + const RemovedElementsEvent & event); protected: /// create the grid void createGrid(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); AKANTU_GET_MACRO(Model, model, const Model &); /// return the object handling synchronizers AKANTU_GET_MACRO(PairLists, pair_list, const PairList *); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// the model to which the neighborhood belongs Model & model; /// Radius of impact: to determine if two quadrature points influence each /// other Real neighborhood_radius; /** * the pairs of quadrature points * 0: not ghost to not ghost * 1: not ghost to ghost */ PairList pair_list[2]; /// the regular grid to construct/update the pair lists std::unique_ptr> spatial_grid; bool is_creating_grid; /// the grid synchronizer for parallel computations std::unique_ptr grid_synchronizer; /// the quadrature point positions const ElementTypeMapArray & quad_coordinates; /// the spatial dimension of the problem const UInt spatial_dimension; }; } // namespace akantu #include "neighborhood_base_inline_impl.cc" #endif /* __AKANTU_NEIGHBORHOOD_BASE_HH__ */ diff --git a/src/model/common/non_local_toolbox/non_local_manager.cc b/src/model/common/non_local_toolbox/non_local_manager.cc index 207012548..7c2487e5d 100644 --- a/src/model/common/non_local_toolbox/non_local_manager.cc +++ b/src/model/common/non_local_toolbox/non_local_manager.cc @@ -1,632 +1,639 @@ /** * @file non_local_manager.cc * * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Fri Apr 13 2012 * @date last modification: Wed Dec 16 2015 * * @brief Implementation of non-local manager * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "non_local_manager.hh" #include "grid_synchronizer.hh" #include "model.hh" #include "non_local_neighborhood.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ NonLocalManager::NonLocalManager(Model & model, NonLocalManagerCallback & callback, const ID & id, const MemoryID & memory_id) : Memory(id, memory_id), Parsable(_st_neighborhoods, id), spatial_dimension(model.getMesh().getSpatialDimension()), model(model), integration_points_positions("integration_points_positions", id, memory_id), volumes("volumes", id, memory_id), compute_stress_calls(0), dummy_registry(nullptr), dummy_grid(nullptr) { - Mesh & mesh = this->model.getMesh(); - mesh.registerEventHandler(*this, _ehp_non_local_manager); - /// parse the neighborhood information from the input file const Parser & parser = getStaticParser(); /// iterate over all the non-local sections and store them in a map std::pair weight_sect = parser.getSubSections(_st_non_local); Parser::const_section_iterator it = weight_sect.first; for (; it != weight_sect.second; ++it) { const ParserSection & section = *it; ID name = section.getName(); this->weight_function_types[name] = section; } this->callback = &callback; } /* -------------------------------------------------------------------------- */ NonLocalManager::~NonLocalManager() = default; /* -------------------------------------------------------------------------- */ void NonLocalManager::initialize() { volumes.initialize(this->model.getFEEngine(), _spatial_dimension = spatial_dimension); AKANTU_DEBUG_ASSERT(this->callback, "A callback should be registered prior to this call"); this->callback->insertIntegrationPointsInNeighborhoods(_not_ghost); + auto & mesh = this->model.getMesh(); + mesh.registerEventHandler(*this, _ehp_non_local_manager); + /// store the number of current ghost elements for each type in the mesh - ElementTypeMap nb_ghost_protected; - Mesh & mesh = this->model.getMesh(); - for (auto type : mesh.elementTypes(spatial_dimension, _ghost)) - nb_ghost_protected(mesh.getNbElement(type, _ghost), type, _ghost); + //ElementTypeMap nb_ghost_protected; + // for (auto type : mesh.elementTypes(spatial_dimension, _ghost)) + // nb_ghost_protected(mesh.getNbElement(type, _ghost), type, _ghost); /// exchange the missing ghosts for the non-local neighborhoods this->createNeighborhoodSynchronizers(); /// insert the ghost quadrature points of the non-local materials into the /// non-local neighborhoods this->callback->insertIntegrationPointsInNeighborhoods(_ghost); FEEngine & fee = this->model.getFEEngine(); this->updatePairLists(); /// cleanup the unneccessary ghost elements - this->cleanupExtraGhostElements(nb_ghost_protected); + this->cleanupExtraGhostElements(); //nb_ghost_protected); + + this->callback->initializeNonLocal(); + this->setJacobians(fee, _ek_regular); this->initNonLocalVariables(); this->computeWeights(); } /* -------------------------------------------------------------------------- */ void NonLocalManager::setJacobians(const FEEngine & fe_engine, const ElementKind & kind) { Mesh & mesh = this->model.getMesh(); for (auto ghost_type : ghost_types) { for (auto type : mesh.elementTypes(spatial_dimension, ghost_type, kind)) { jacobians(type, ghost_type) = &fe_engine.getIntegratorInterface().getJacobians(type, ghost_type); } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::createNeighborhood(const ID & weight_func, const ID & neighborhood_id) { AKANTU_DEBUG_IN(); auto weight_func_it = this->weight_function_types.find(weight_func); AKANTU_DEBUG_ASSERT(weight_func_it != weight_function_types.end(), "No info found in the input file for the weight_function " << weight_func << " in the neighborhood " << neighborhood_id); const ParserSection & section = weight_func_it->second; const ID weight_func_type = section.getOption(); /// create new neighborhood for given ID std::stringstream sstr; sstr << id << ":neighborhood:" << neighborhood_id; if (weight_func_type == "base_wf") neighborhoods[neighborhood_id] = std::make_unique>( *this, this->integration_points_positions, sstr.str()); #if defined(AKANTU_DAMAGE_NON_LOCAL) else if (weight_func_type == "remove_wf") neighborhoods[neighborhood_id] = std::make_unique>( *this, this->integration_points_positions, sstr.str()); else if (weight_func_type == "stress_wf") neighborhoods[neighborhood_id] = std::make_unique>( *this, this->integration_points_positions, sstr.str()); else if (weight_func_type == "damage_wf") neighborhoods[neighborhood_id] = std::make_unique>( *this, this->integration_points_positions, sstr.str()); #endif else AKANTU_EXCEPTION("error in weight function type provided in material file"); neighborhoods[neighborhood_id]->parseSection(section); neighborhoods[neighborhood_id]->initNeighborhood(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NonLocalManager::createNeighborhoodSynchronizers() { /// exchange all the neighborhood IDs, so that every proc knows how many /// neighborhoods exist globally /// First: Compute locally the maximum ID size UInt max_id_size = 0; UInt current_size = 0; NeighborhoodMap::const_iterator it; for (it = neighborhoods.begin(); it != neighborhoods.end(); ++it) { current_size = it->first.size(); if (current_size > max_id_size) max_id_size = current_size; } /// get the global maximum ID size on each proc StaticCommunicator & static_communicator = akantu::StaticCommunicator::getStaticCommunicator(); static_communicator.allReduce(max_id_size, _so_max); /// get the rank for this proc and the total nb proc UInt prank = static_communicator.whoAmI(); UInt psize = static_communicator.getNbProc(); /// exchange the number of neighborhoods on each proc Array nb_neighborhoods_per_proc(psize); nb_neighborhoods_per_proc(prank) = neighborhoods.size(); static_communicator.allGather(nb_neighborhoods_per_proc); /// compute the total number of neighborhoods UInt nb_neighborhoods_global = std::accumulate( nb_neighborhoods_per_proc.begin(), nb_neighborhoods_per_proc.end(), 0); /// allocate an array of chars to store the names of all neighborhoods Array buffer(nb_neighborhoods_global, max_id_size); /// starting index on this proc UInt starting_index = std::accumulate(nb_neighborhoods_per_proc.begin(), nb_neighborhoods_per_proc.begin() + prank, 0); it = neighborhoods.begin(); /// store the names of local neighborhoods in the buffer for (UInt i = 0; i < neighborhoods.size(); ++i, ++it) { UInt c = 0; for (; c < it->first.size(); ++c) buffer(i + starting_index, c) = it->first[c]; for (; c < max_id_size; ++c) buffer(i + starting_index, c) = char(0); } /// store the nb of data to send in the all gather Array buffer_size(nb_neighborhoods_per_proc); buffer_size *= max_id_size; /// exchange the names of all the neighborhoods with all procs static_communicator.allGatherV(buffer, buffer_size); for (UInt i = 0; i < nb_neighborhoods_global; ++i) { std::stringstream neighborhood_id; for (UInt c = 0; c < max_id_size; ++c) { if (buffer(i, c) == char(0)) break; neighborhood_id << buffer(i, c); } global_neighborhoods.insert(neighborhood_id.str()); } /// this proc does not know all the neighborhoods -> create dummy /// grid so that this proc can participate in the all gather for /// detecting the overlap of neighborhoods this proc doesn't know Vector grid_center(this->spatial_dimension, std::numeric_limits::max()); Vector spacing(this->spatial_dimension, 0.); dummy_grid = std::make_unique>( this->spatial_dimension, spacing, grid_center); - std::set tags; - tags.insert(_gst_mnl_for_average); - tags.insert(_gst_mnl_weight); for (auto & neighborhood_id : global_neighborhoods) { it = neighborhoods.find(neighborhood_id); if (it != neighborhoods.end()) { it->second->createGridSynchronizer(); } else { - std::stringstream sstr; - sstr << this->id << ":" << neighborhood_id << ":grid_synchronizer"; dummy_synchronizers[neighborhood_id] = std::make_unique( - this->model.getMesh(), *dummy_grid, sstr.str(), this->memory_id, - false); + this->model.getMesh(), *dummy_grid, + std::string(this->id + ":" + neighborhood_id + ":grid_synchronizer"), + this->memory_id, false); + } + } +} + +/* -------------------------------------------------------------------------- */ +void NonLocalManager::synchronize(DataAccessor & data_accessor, const SynchronizationTag & tag) { + for (auto & neighborhood_id : global_neighborhoods) { + auto it = neighborhoods.find(neighborhood_id); + if (it != neighborhoods.end()) { + it->second->synchronize(data_accessor, tag); + } else { + auto synchronizer_it = dummy_synchronizers.find(neighborhood_id); + if (synchronizer_it == dummy_synchronizers.end()) continue; + + synchronizer_it->second->synchronizeOnce(data_accessor, tag); } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::averageInternals(const GhostType & ghost_type) { /// update the weights of the weight function if (ghost_type == _not_ghost) this->computeWeights(); /// loop over all neighborhoods and compute the non-local variables for (auto & neighborhood : neighborhoods) { /// loop over all the non-local variables of the given neighborhood for (auto & non_local_variable : non_local_variables) { NonLocalVariable & non_local_var = *non_local_variable.second; neighborhood.second->weightedAverageOnNeighbours( non_local_var.local, non_local_var.non_local, non_local_var.nb_component, ghost_type); } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::computeWeights() { AKANTU_DEBUG_IN(); this->updateWeightFunctionInternals(); this->volumes.clear(); for (auto global_neighborhood : global_neighborhoods) { auto it = neighborhoods.find(global_neighborhood); if (it != neighborhoods.end()) it->second->updateWeights(); else { dummy_synchronizers[global_neighborhood]->synchronize(dummy_accessor, _gst_mnl_weight); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NonLocalManager::updatePairLists() { AKANTU_DEBUG_IN(); integration_points_positions.initialize( this->model.getFEEngine(), _nb_component = spatial_dimension, _spatial_dimension = spatial_dimension); /// compute the position of the quadrature points this->model.getFEEngine().computeIntegrationPointsCoordinates( integration_points_positions); for (auto & pair : neighborhoods) pair.second->updatePairList(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NonLocalManager::registerNonLocalVariable(const ID & variable_name, const ID & nl_variable_name, UInt nb_component) { AKANTU_DEBUG_IN(); auto non_local_variable_it = non_local_variables.find(variable_name); if (non_local_variable_it == non_local_variables.end()) non_local_variables[nl_variable_name] = std::make_unique( variable_name, nl_variable_name, this->id, nb_component); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ ElementTypeMapReal & NonLocalManager::registerWeightFunctionInternal(const ID & field_name) { AKANTU_DEBUG_IN(); auto it = this->weight_function_internals.find(field_name); if (it == weight_function_internals.end()) { weight_function_internals[field_name] = std::make_unique(field_name, this->id, this->memory_id); } return *(weight_function_internals[field_name]); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void NonLocalManager::updateWeightFunctionInternals() { for (auto & pair : this->weight_function_internals) { auto & internals = *pair.second; internals.clear(); for (auto ghost_type : ghost_types) this->callback->updateLocalInternal(internals, ghost_type, _ek_regular); } } /* -------------------------------------------------------------------------- */ void NonLocalManager::initNonLocalVariables() { /// loop over all the non-local variables for (auto & pair : non_local_variables) { auto & variable = *pair.second; variable.non_local.initialize(this->model.getFEEngine(), _nb_component = variable.nb_component, _spatial_dimension = spatial_dimension); } } /* -------------------------------------------------------------------------- */ void NonLocalManager::computeAllNonLocalStresses() { /// update the flattened version of the internals for (auto & pair : non_local_variables) { auto & variable = *pair.second; variable.local.clear(); variable.non_local.clear(); for (auto ghost_type : ghost_types) { this->callback->updateLocalInternal(variable.local, ghost_type, _ek_regular); } } this->volumes.clear(); for (auto & pair : neighborhoods) { auto & neighborhood = *pair.second; neighborhood.asynchronousSynchronize(_gst_mnl_for_average); } this->averageInternals(_not_ghost); AKANTU_DEBUG_INFO("Wait distant non local stresses"); for (auto & pair : neighborhoods) { auto & neighborhood = *pair.second; neighborhood.waitEndSynchronize(_gst_mnl_for_average); } this->averageInternals(_ghost); /// copy the results in the materials for (auto & pair : non_local_variables) { auto & variable = *pair.second; for (auto ghost_type : ghost_types) { this->callback->updateNonLocalInternal(variable.non_local, ghost_type, _ek_regular); } } this->callback->computeNonLocalStresses(_not_ghost); ++this->compute_stress_calls; } /* -------------------------------------------------------------------------- */ -void NonLocalManager::cleanupExtraGhostElements( - ElementTypeMap & nb_ghost_protected) { +void NonLocalManager::cleanupExtraGhostElements() { + //ElementTypeMap & nb_ghost_protected) { using ElementSet = std::set; ElementSet relevant_ghost_elements; /// loop over all the neighborhoods and get their protected ghosts for (auto & pair : neighborhoods) { auto & neighborhood = *pair.second; ElementSet to_keep_per_neighborhood; neighborhood.cleanupExtraGhostElements(to_keep_per_neighborhood); for (auto & element : to_keep_per_neighborhood) relevant_ghost_elements.insert(element); } - /// remove all unneccessary ghosts from the mesh - /// Create list of element to remove and new numbering for element to keep - Mesh & mesh = this->model.getMesh(); - ElementSet ghost_to_erase; - - RemovedElementsEvent remove_elem(mesh); - auto & new_numberings = remove_elem.getNewNumbering(); - Element element; - element.ghost_type = _ghost; - - for (auto & type : mesh.elementTypes(spatial_dimension, _ghost)) { - element.type = type; - UInt nb_ghost_elem = mesh.getNbElement(type, _ghost); - UInt nb_ghost_elem_protected = 0; - try { - nb_ghost_elem_protected = nb_ghost_protected(type, _ghost); - } catch (...) { - } - - if (!new_numberings.exists(type, _ghost)) - new_numberings.alloc(nb_ghost_elem, 1, type, _ghost); - else - new_numberings(type, _ghost).resize(nb_ghost_elem); - - Array & new_numbering = new_numberings(type, _ghost); - for (UInt g = 0; g < nb_ghost_elem; ++g) { - element.element = g; - if (element.element >= nb_ghost_elem_protected && - relevant_ghost_elements.find(element) == - relevant_ghost_elements.end()) { - remove_elem.getList().push_back(element); - new_numbering(element.element) = UInt(-1); - } - } - /// renumber remaining ghosts - UInt ng = 0; - for (UInt g = 0; g < nb_ghost_elem; ++g) { - if (new_numbering(g) != UInt(-1)) { - new_numbering(g) = ng; - ++ng; - } - } - } - - for (auto & type : mesh.elementTypes(spatial_dimension, _not_ghost)) { - UInt nb_elem = mesh.getNbElement(type, _not_ghost); - if (!new_numberings.exists(type, _not_ghost)) - new_numberings.alloc(nb_elem, 1, type, _not_ghost); - Array & new_numbering = new_numberings(type, _not_ghost); - for (UInt e = 0; e < nb_elem; ++e) { - new_numbering(e) = e; - } - } - mesh.sendEvent(remove_elem); + // /// remove all unneccessary ghosts from the mesh + // /// Create list of element to remove and new numbering for element to keep + // Mesh & mesh = this->model.getMesh(); + // ElementSet ghost_to_erase; + + // RemovedElementsEvent remove_elem(mesh); + // auto & new_numberings = remove_elem.getNewNumbering(); + // Element element; + // element.ghost_type = _ghost; + + // for (auto & type : mesh.elementTypes(spatial_dimension, _ghost)) { + // element.type = type; + // UInt nb_ghost_elem = mesh.getNbElement(type, _ghost); + // // UInt nb_ghost_elem_protected = 0; + // // try { + // // nb_ghost_elem_protected = nb_ghost_protected(type, _ghost); + // // } catch (...) { + // // } + + // if (!new_numberings.exists(type, _ghost)) + // new_numberings.alloc(nb_ghost_elem, 1, type, _ghost); + // else + // new_numberings(type, _ghost).resize(nb_ghost_elem); + + // Array & new_numbering = new_numberings(type, _ghost); + // for (UInt g = 0; g < nb_ghost_elem; ++g) { + // element.element = g; + // if (element.element >= nb_ghost_elem_protected && + // relevant_ghost_elements.find(element) == + // relevant_ghost_elements.end()) { + // remove_elem.getList().push_back(element); + // new_numbering(element.element) = UInt(-1); + // } + // } + // /// renumber remaining ghosts + // UInt ng = 0; + // for (UInt g = 0; g < nb_ghost_elem; ++g) { + // if (new_numbering(g) != UInt(-1)) { + // new_numbering(g) = ng; + // ++ng; + // } + // } + // } + + // for (auto & type : mesh.elementTypes(spatial_dimension, _not_ghost)) { + // UInt nb_elem = mesh.getNbElement(type, _not_ghost); + // if (!new_numberings.exists(type, _not_ghost)) + // new_numberings.alloc(nb_elem, 1, type, _not_ghost); + // Array & new_numbering = new_numberings(type, _not_ghost); + // for (UInt e = 0; e < nb_elem; ++e) { + // new_numbering(e) = e; + // } + // } + // mesh.sendEvent(remove_elem); } /* -------------------------------------------------------------------------- */ void NonLocalManager::onElementsRemoved( const Array & element_list, const ElementTypeMapArray & new_numbering, __attribute__((unused)) const RemovedElementsEvent & event) { FEEngine & fee = this->model.getFEEngine(); this->removeIntegrationPointsFromMap( event.getNewNumbering(), spatial_dimension, integration_points_positions, fee, _ek_regular); this->removeIntegrationPointsFromMap(event.getNewNumbering(), 1, volumes, fee, _ek_regular); /// loop over all the neighborhoods and call onElementsRemoved std::set::const_iterator global_neighborhood_it = global_neighborhoods.begin(); NeighborhoodMap::iterator it; for (; global_neighborhood_it != global_neighborhoods.end(); ++global_neighborhood_it) { it = neighborhoods.find(*global_neighborhood_it); if (it != neighborhoods.end()) it->second->onElementsRemoved(element_list, new_numbering, event); else dummy_synchronizers[*global_neighborhood_it]->onElementsRemoved( element_list, new_numbering, event); } } /* -------------------------------------------------------------------------- */ -void NonLocalManager::onElementsAdded(__attribute__((unused)) - const Array & element_list, - __attribute__((unused)) - const NewElementsEvent & event) { +void NonLocalManager::onElementsAdded(const Array &, + const NewElementsEvent &) { this->resizeElementTypeMap(1, volumes, model.getFEEngine()); this->resizeElementTypeMap(spatial_dimension, integration_points_positions, model.getFEEngine()); } /* -------------------------------------------------------------------------- */ void NonLocalManager::resizeElementTypeMap(UInt nb_component, ElementTypeMapReal & element_map, const FEEngine & fee, const ElementKind el_kind) { Mesh & mesh = this->model.getMesh(); for (auto gt : ghost_types) { for (auto type : mesh.elementTypes(spatial_dimension, gt, el_kind)) { UInt nb_element = mesh.getNbElement(type, gt); UInt nb_quads = fee.getNbIntegrationPoints(type, gt); if (!element_map.exists(type, gt)) element_map.alloc(nb_element * nb_quads, nb_component, type, gt); else element_map(type, gt).resize(nb_element * nb_quads); } } } /* -------------------------------------------------------------------------- */ void NonLocalManager::removeIntegrationPointsFromMap( const ElementTypeMapArray & new_numbering, UInt nb_component, ElementTypeMapReal & element_map, const FEEngine & fee, const ElementKind el_kind) { for (auto gt : ghost_types) { for (auto type : new_numbering.elementTypes(_all_dimensions, gt, el_kind)) { if (element_map.exists(type, gt)) { const Array & renumbering = new_numbering(type, gt); Array & vect = element_map(type, gt); UInt nb_quad_per_elem = fee.getNbIntegrationPoints(type, gt); Array tmp(renumbering.size() * nb_quad_per_elem, nb_component); - AKANTU_DEBUG_ASSERT( - tmp.size() == vect.size(), - "Something strange append some mater was created from nowhere!!"); - AKANTU_DEBUG_ASSERT( tmp.size() == vect.size(), "Something strange append some mater was created or disappeared in " << vect.getID() << "(" << vect.size() << "!=" << tmp.size() << ") " "!!"); UInt new_size = 0; for (UInt i = 0; i < renumbering.size(); ++i) { UInt new_i = renumbering(i); if (new_i != UInt(-1)) { memcpy(tmp.storage() + new_i * nb_component * nb_quad_per_elem, vect.storage() + i * nb_component * nb_quad_per_elem, nb_component * nb_quad_per_elem * sizeof(Real)); ++new_size; } } tmp.resize(new_size * nb_quad_per_elem); vect.copy(tmp); } } } } /* -------------------------------------------------------------------------- */ UInt NonLocalManager::getNbData(const Array & elements, const ID & id) const { UInt size = 0; UInt nb_quadrature_points = this->model.getNbIntegrationPoints(elements); auto it = non_local_variables.find(id); AKANTU_DEBUG_ASSERT(it != non_local_variables.end(), "The non-local variable " << id << " is not registered"); size += it->second->nb_component * sizeof(Real) * nb_quadrature_points; return size; } /* -------------------------------------------------------------------------- */ void NonLocalManager::packData(CommunicationBuffer & buffer, const Array & elements, const ID & id) const { auto it = non_local_variables.find(id); AKANTU_DEBUG_ASSERT(it != non_local_variables.end(), "The non-local variable " << id << " is not registered"); DataAccessor::packElementalDataHelper( it->second->local, buffer, elements, true, this->model.getFEEngine()); } /* -------------------------------------------------------------------------- */ void NonLocalManager::unpackData(CommunicationBuffer & buffer, const Array & elements, const ID & id) const { auto it = non_local_variables.find(id); AKANTU_DEBUG_ASSERT(it != non_local_variables.end(), "The non-local variable " << id << " is not registered"); DataAccessor::unpackElementalDataHelper( it->second->local, buffer, elements, true, this->model.getFEEngine()); } } // namespace akantu diff --git a/src/model/common/non_local_toolbox/non_local_manager.hh b/src/model/common/non_local_toolbox/non_local_manager.hh index d726babd5..458182e59 100644 --- a/src/model/common/non_local_toolbox/non_local_manager.hh +++ b/src/model/common/non_local_toolbox/non_local_manager.hh @@ -1,287 +1,288 @@ /** * @file non_local_manager.hh * * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Fri Jun 18 2010 * @date last modification: Tue Dec 08 2015 * * @brief Classes that manages all the non-local neighborhoods * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "communication_buffer.hh" #include "data_accessor.hh" #include "mesh_events.hh" #include "non_local_manager_callback.hh" #include "parsable.hh" /* -------------------------------------------------------------------------- */ #include #include /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_MANAGER_HH__ #define __AKANTU_NON_LOCAL_MANAGER_HH__ namespace akantu { class Model; class NonLocalNeighborhoodBase; class GridSynchronizer; class SynchronizerRegistry; class IntegrationPoint; template class SpatialGrid; class FEEngine; } // namespace akantu namespace akantu { class NonLocalManager : protected Memory, public MeshEventHandler, public Parsable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NonLocalManager(Model & model, NonLocalManagerCallback & callback, const ID & id = "non_local_manager", const MemoryID & memory_id = 0); virtual ~NonLocalManager(); using NeighborhoodMap = std::map>; /* ------------------------------------------------------------------------ */ /* Methods */ /* ----------------------------------------------------------------------- */ public: /// register a new internal needed for the weight computations ElementTypeMapReal & registerWeightFunctionInternal(const ID & field_name); /// register a non-local variable void registerNonLocalVariable(const ID & variable_name, const ID & nl_variable_name, UInt nb_component); /// register non-local neighborhood inline void registerNeighborhood(const ID & neighborhood, const ID & weight_func_id); // void registerNonLocalManagerCallback(NonLocalManagerCallback & callback); /// average the internals and compute the non-local stresses virtual void computeAllNonLocalStresses(); /// initialize the non-local manager: compute pair lists and weights for all /// neighborhoods virtual void initialize(); + /// synchronize once on a given tag using the neighborhoods synchronizer + void synchronize(DataAccessor & data_accessor, const SynchronizationTag &); protected: /// create the grid synchronizers for each neighborhood void createNeighborhoodSynchronizers(); /// compute the weights in each neighborhood for non-local averaging void computeWeights(); /// compute the weights in each neighborhood for non-local averaging void updatePairLists(); /// average the non-local variables void averageInternals(const GhostType & ghost_type = _not_ghost); /// update the flattened version of the weight function internals void updateWeightFunctionInternals(); - protected: /// create a new neighborhood for a given domain ID void createNeighborhood(const ID & weight_func, const ID & neighborhood); /// set the values of the jacobians void setJacobians(const FEEngine & fe_engine, const ElementKind & kind); /// allocation of eelment type maps // void initElementTypeMap(UInt nb_component, // ElementTypeMapReal & element_map, // const FEEngine & fe_engine, // const ElementKind el_kind = _ek_regular); /// resizing of element type maps void resizeElementTypeMap(UInt nb_component, ElementTypeMapReal & element_map, const FEEngine & fee, const ElementKind el_kind = _ek_regular); /// remove integration points from element type maps void removeIntegrationPointsFromMap( const ElementTypeMapArray & new_numbering, UInt nb_component, ElementTypeMapReal & element_map, const FEEngine & fee, const ElementKind el_kind = _ek_regular); /// allocate the non-local variables void initNonLocalVariables(); /// cleanup unneccessary ghosts - void cleanupExtraGhostElements(ElementTypeMap & nb_ghost_protected); + void cleanupExtraGhostElements();//ElementTypeMap & nb_ghost_protected); /* ------------------------------------------------------------------------ */ /* DataAccessor kind of interface */ /* ------------------------------------------------------------------------ */ public: /// get Nb data for synchronization in parallel UInt getNbData(const Array & elements, const ID & id) const; /// pack data for synchronization in parallel void packData(CommunicationBuffer & buffer, const Array & elements, const ID & id) const; /// unpack data for synchronization in parallel void unpackData(CommunicationBuffer & buffer, const Array & elements, const ID & id) const; /* ------------------------------------------------------------------------ */ /* MeshEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: void onElementsRemoved(const Array & element_list, const ElementTypeMapArray & new_numbering, const RemovedElementsEvent & event) override; void onElementsAdded(const Array & element_list, const NewElementsEvent & event) override; void onElementsChanged(const Array &, const Array &, const ElementTypeMapArray &, const ChangedElementsEvent &) override {} void onNodesAdded(const Array &, const NewNodesEvent &) override {} void onNodesRemoved(const Array &, const Array &, const RemovedNodesEvent &) override{}; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); AKANTU_GET_MACRO(Model, model, const Model &); AKANTU_GET_MACRO_NOT_CONST(Model, model, Model &); AKANTU_GET_MACRO_NOT_CONST(Volumes, volumes, ElementTypeMapReal &) AKANTU_GET_MACRO(NbStressCalls, compute_stress_calls, UInt); /// return the fem object associated with a provided name inline NonLocalNeighborhoodBase & getNeighborhood(const ID & name) const; inline const Array & getJacobians(const ElementType & type, const GhostType & ghost_type) { return *jacobians(type, ghost_type); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// the spatial dimension const UInt spatial_dimension; protected: /// the non-local neighborhoods present NeighborhoodMap neighborhoods; /// list of all the non-local materials in the model // std::vector non_local_materials; struct NonLocalVariable { NonLocalVariable(const ID & variable_name, const ID & nl_variable_name, const ID & id, UInt nb_component) : local(variable_name, id, 0), non_local(nl_variable_name, id, 0), nb_component(nb_component) {} ElementTypeMapReal local; ElementTypeMapReal non_local; UInt nb_component; }; /// the non-local variables associated to a certain neighborhood std::map> non_local_variables; /// reference to the model Model & model; /// jacobians for all the elements in the mesh ElementTypeMap *> jacobians; /// store the position of the quadrature points ElementTypeMapReal integration_points_positions; /// store the volume of each quadrature point for the non-local weight /// normalization ElementTypeMapReal volumes; /// counter for computeStress calls UInt compute_stress_calls; /// map to store weight function types from input file std::map weight_function_types; /// map to store the internals needed by the weight functions std::map> weight_function_internals; /* -------------------------------------------------------------------------- */ /// the following are members needed to make this processor participate in the /// grid creation of neighborhoods he doesn't own as a member. For details see /// createGridSynchronizers function /// synchronizer registry for dummy grid synchronizers std::unique_ptr dummy_registry; /// map of dummy synchronizers std::map> dummy_synchronizers; /// dummy spatial grid std::unique_ptr> dummy_grid; /// create a set of all neighborhoods present in the simulation std::set global_neighborhoods; class DummyDataAccessor : public DataAccessor { public: inline UInt getNbData(const Array &, const SynchronizationTag &) const override { return 0; }; inline void packData(CommunicationBuffer &, const Array &, const SynchronizationTag &) const override{}; inline void unpackData(CommunicationBuffer &, const Array &, const SynchronizationTag &) override{}; }; DummyDataAccessor dummy_accessor; /* ------------------------------------------------------------------------ */ NonLocalManagerCallback * callback; }; } // namespace akantu /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "non_local_manager_inline_impl.cc" #endif /* __AKANTU_NON_LOCAL_MANAGER_HH__ */ diff --git a/src/model/common/non_local_toolbox/non_local_manager_callback.hh b/src/model/common/non_local_toolbox/non_local_manager_callback.hh index 8addddb39..f29671b4d 100644 --- a/src/model/common/non_local_toolbox/non_local_manager_callback.hh +++ b/src/model/common/non_local_toolbox/non_local_manager_callback.hh @@ -1,64 +1,66 @@ /** * @file non_local_manager_callback.hh * * @author Nicolas Richart * * @date creation Sun Jul 09 2017 * * @brief Callback functions for the non local manager * * @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 "element_type_map.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_MANAGER_CALLBACK_HH__ #define __AKANTU_NON_LOCAL_MANAGER_CALLBACK_HH__ namespace akantu { class NonLocalManager; } // namespace akantu namespace akantu { class NonLocalManagerCallback { public: + virtual void initializeNonLocal() {} + /* ------------------------------------------------------------------------ */ virtual void insertIntegrationPointsInNeighborhoods(const GhostType & ghost_type) = 0; virtual void computeNonLocalStresses(const GhostType & ghost_type) = 0; /// update the values of the non local internal virtual void updateLocalInternal(ElementTypeMapReal & internal_flat, const GhostType & ghost_type, const ElementKind & kind) = 0; /// copy the results of the averaging in the materials virtual void updateNonLocalInternal(ElementTypeMapReal & internal_flat, const GhostType & ghost_type, const ElementKind & kind) = 0; }; } // namespace akantu #endif /* __AKANTU_NON_LOCAL_MANAGER_CALLBACK_HH__ */ diff --git a/src/model/common/non_local_toolbox/non_local_neighborhood_base.cc b/src/model/common/non_local_toolbox/non_local_neighborhood_base.cc index 5d1351ee1..15eab0d93 100644 --- a/src/model/common/non_local_toolbox/non_local_neighborhood_base.cc +++ b/src/model/common/non_local_toolbox/non_local_neighborhood_base.cc @@ -1,119 +1,117 @@ /** * @file non_local_neighborhood_base.cc * * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Sat Sep 26 2015 * @date last modification: Wed Nov 25 2015 * * @brief Implementation of non-local neighborhood base * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ -#include "model.hh" -#include "grid_synchronizer.hh" #include "non_local_neighborhood_base.hh" +#include "grid_synchronizer.hh" +#include "model.hh" /* -------------------------------------------------------------------------- */ +#include namespace akantu { /* -------------------------------------------------------------------------- */ NonLocalNeighborhoodBase::NonLocalNeighborhoodBase( - Model & model, const ElementTypeMapReal & quad_coordinates, - const ID & id, const MemoryID & memory_id) + Model & model, const ElementTypeMapReal & quad_coordinates, const ID & id, + const MemoryID & memory_id) : NeighborhoodBase(model, quad_coordinates, id, memory_id), Parsable(_st_non_local, id) { AKANTU_DEBUG_IN(); this->registerParam("radius", neighborhood_radius, 100., _pat_parsable | _pat_readable, "Non local radius"); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -NonLocalNeighborhoodBase::~NonLocalNeighborhoodBase() { - AKANTU_DEBUG_IN(); - - AKANTU_DEBUG_OUT(); -} +NonLocalNeighborhoodBase::~NonLocalNeighborhoodBase() = default; /* -------------------------------------------------------------------------- */ void NonLocalNeighborhoodBase::createGridSynchronizer() { this->is_creating_grid = true; - std::set tags; - tags.insert(_gst_mnl_for_average); - tags.insert(_gst_mnl_weight); - std::stringstream sstr; - sstr << getID() << ":grid_synchronizer"; this->grid_synchronizer = std::make_unique( - this->model.getMesh(), *spatial_grid, *this, tags, sstr.str(), this->memory_id, - false); + this->model.getMesh(), *spatial_grid, *this, + std::set{_gst_mnl_weight, _gst_mnl_for_average}, + std::string(getID() + ":grid_synchronizer"), this->memory_id, false); this->is_creating_grid = false; } +/* -------------------------------------------------------------------------- */ +void NonLocalNeighborhoodBase::synchronize( + DataAccessor & data_accessor, const SynchronizationTag & tag) { + if (not grid_synchronizer) + return; + + grid_synchronizer->synchronizeOnce(data_accessor, tag); +} + /* -------------------------------------------------------------------------- */ void NonLocalNeighborhoodBase::cleanupExtraGhostElements( std::set & relevant_ghost_elements) { - PairList::const_iterator first_pair = pair_list[_ghost].begin(); - PairList::const_iterator last_pair = pair_list[_ghost].end(); - for (; first_pair != last_pair; ++first_pair) { - const IntegrationPoint & q2 = first_pair->second; + for (auto && pair : pair_list[_ghost]) { + const auto & q2 = pair.second; relevant_ghost_elements.insert(q2); } Array ghosts_to_erase(0); - Mesh & mesh = this->model.getMesh(); - Mesh::type_iterator it = mesh.firstType(spatial_dimension, _ghost); - Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _ghost); + auto & mesh = this->model.getMesh(); Element element; element.ghost_type = _ghost; - auto end = relevant_ghost_elements.end(); - for (; it != last_type; ++it) { - element.type = *it; - UInt nb_ghost_elem = mesh.getNbElement(*it, _ghost); + auto end = relevant_ghost_elements.end(); + for (auto & type : mesh.elementTypes(spatial_dimension, _ghost)) { + element.type = type; + UInt nb_ghost_elem = mesh.getNbElement(type, _ghost); for (UInt g = 0; g < nb_ghost_elem; ++g) { element.element = g; if (relevant_ghost_elements.find(element) == end) { ghosts_to_erase.push_back(element); } } } /// remove the unneccessary ghosts from the synchronizer - this->grid_synchronizer->removeElements(ghosts_to_erase); + //this->grid_synchronizer->removeElements(ghosts_to_erase); + mesh.eraseElements(ghosts_to_erase); } /* -------------------------------------------------------------------------- */ void NonLocalNeighborhoodBase::registerNonLocalVariable(const ID & id) { this->non_local_variables.insert(id); } - } // namespace akantu diff --git a/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh b/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh index 7c02c8483..185a3ae6a 100644 --- a/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh +++ b/src/model/common/non_local_toolbox/non_local_neighborhood_base.hh @@ -1,125 +1,130 @@ /** * @file non_local_neighborhood_base.hh * * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Sat Sep 26 2015 * @date last modification: Wed Nov 25 2015 * * @brief Non-local neighborhood base class * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "neighborhood_base.hh" #include "parsable.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_NEIGHBORHOOD_BASE_HH__ #define __AKANTU_NON_LOCAL_NEIGHBORHOOD_BASE_HH__ namespace akantu { class Model; } /* -------------------------------------------------------------------------- */ namespace akantu { class NonLocalNeighborhoodBase : public NeighborhoodBase, public Parsable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: NonLocalNeighborhoodBase(Model & model, const ElementTypeMapReal & quad_coordinates, const ID & id = "non_local_neighborhood", const MemoryID & memory_id = 0); virtual ~NonLocalNeighborhoodBase(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// create grid synchronizer and exchange ghost cells void createGridSynchronizer() override; + void synchronize(DataAccessor & data_accessor, + const SynchronizationTag & tag) override; + /// compute weights, for instance needed for non-local damage computation virtual void computeWeights(){}; // compute the non-local counter part for a given element type map virtual void weightedAverageOnNeighbours(const ElementTypeMapReal & to_accumulate, ElementTypeMapReal & accumulated, UInt nb_degree_of_freedom, const GhostType & ghost_type2) const = 0; /// update the weights for the non-local averaging virtual void updateWeights() = 0; /// update the weights for the non-local averaging - virtual void saveWeights(const std::string & ) const { AKANTU_DEBUG_TO_IMPLEMENT(); } + virtual void saveWeights(const std::string &) const { + AKANTU_DEBUG_TO_IMPLEMENT(); + } /// register a new non-local variable in the neighborhood virtual void registerNonLocalVariable(const ID & id); /// clean up the unneccessary ghosts void cleanupExtraGhostElements(std::set & relevant_ghost_elements); protected: /// create the grid void createGrid(); /* -------------------------------------------------------------------------- */ /* DataAccessor inherited members */ /* -------------------------------------------------------------------------- */ public: inline UInt getNbData(const Array &, const SynchronizationTag &) const override { return 0; } inline void packData(CommunicationBuffer &, const Array &, const SynchronizationTag &) const override {} inline void unpackData(CommunicationBuffer &, const Array &, const SynchronizationTag &) override {} /* -------------------------------------------------------------------------- */ /* Accessors */ /* -------------------------------------------------------------------------- */ public: AKANTU_GET_MACRO(NonLocalVariables, non_local_variables, const std::set &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// list of non-local variables associated to the neighborhood std::set non_local_variables; }; } // namespace akantu #endif /* __AKANTU_NON_LOCAL_NEIGHBORHOOD_BASE_HH__ */ diff --git a/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh b/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh index b805e4bd6..e201b6df9 100644 --- a/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh +++ b/src/model/common/non_local_toolbox/non_local_neighborhood_tmpl.hh @@ -1,280 +1,280 @@ /** * @file non_local_neighborhood_tmpl.hh * * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Mon Sep 28 2015 * @date last modification: Wed Nov 25 2015 * * @brief Implementation of class non-local neighborhood * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "non_local_manager.hh" #include "non_local_neighborhood.hh" #include "static_communicator.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_NON_LOCAL_NEIGHBORHOOD_TMPL_HH__ #define __AKANTU_NON_LOCAL_NEIGHBORHOOD_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template template inline void NonLocalNeighborhood::foreach_weight( const GhostType & ghost_type, Func && func) { auto weight_it = pair_weight[ghost_type]->begin(pair_weight[ghost_type]->getNbComponent()); for (auto & pair : pair_list[ghost_type]) { std::forward(func)(pair.first, pair.second, *weight_it); ++weight_it; } } /* -------------------------------------------------------------------------- */ template template inline void NonLocalNeighborhood::foreach_weight( const GhostType & ghost_type, Func && func) const { auto weight_it = pair_weight[ghost_type]->begin(pair_weight[ghost_type]->getNbComponent()); for (auto & pair : pair_list[ghost_type]) { std::forward(func)(pair.first, pair.second, *weight_it); ++weight_it; } } /* -------------------------------------------------------------------------- */ template NonLocalNeighborhood::NonLocalNeighborhood( NonLocalManager & manager, const ElementTypeMapReal & quad_coordinates, const ID & id, const MemoryID & memory_id) : NonLocalNeighborhoodBase(manager.getModel(), quad_coordinates, id, memory_id), non_local_manager(manager) { AKANTU_DEBUG_IN(); this->weight_function = std::make_unique(manager); this->registerSubSection(_st_weight_function, "weight_parameter", *weight_function); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template NonLocalNeighborhood::~NonLocalNeighborhood() = default; /* -------------------------------------------------------------------------- */ template void NonLocalNeighborhood::computeWeights() { AKANTU_DEBUG_IN(); this->weight_function->setRadius(this->neighborhood_radius); Vector q1_coord(this->spatial_dimension); Vector q2_coord(this->spatial_dimension); UInt nb_weights_per_pair = 2; /// w1: q1->q2, w2: q2->q1 /// get the elementtypemap for the neighborhood volume for each quadrature /// point ElementTypeMapReal & quadrature_points_volumes = this->non_local_manager.getVolumes(); /// update the internals of the weight function if applicable (not /// all the weight functions have internals and do noting in that /// case) weight_function->updateInternals(); for (auto ghost_type : ghost_types) { /// allocate the array to store the weight, if it doesn't exist already if (!(pair_weight[ghost_type])) { pair_weight[ghost_type] = std::make_unique>(0, nb_weights_per_pair); } /// resize the array to the correct size pair_weight[ghost_type]->resize(pair_list[ghost_type].size()); /// set entries to zero pair_weight[ghost_type]->clear(); /// loop over all pairs in the current pair list array and their /// corresponding weights PairList::const_iterator first_pair = pair_list[ghost_type].begin(); PairList::const_iterator last_pair = pair_list[ghost_type].end(); Array::vector_iterator weight_it = pair_weight[ghost_type]->begin(nb_weights_per_pair); // Compute the weights for (; first_pair != last_pair; ++first_pair, ++weight_it) { Vector & weight = *weight_it; const IntegrationPoint & q1 = first_pair->first; const IntegrationPoint & q2 = first_pair->second; /// get the coordinates for the given pair of quads Array::const_vector_iterator coords_type_1_it = this->quad_coordinates(q1.type, q1.ghost_type) .begin(this->spatial_dimension); q1_coord = coords_type_1_it[q1.global_num]; Array::const_vector_iterator coords_type_2_it = this->quad_coordinates(q2.type, q2.ghost_type) .begin(this->spatial_dimension); q2_coord = coords_type_2_it[q2.global_num]; Array & quad_volumes_1 = quadrature_points_volumes(q1.type, q1.ghost_type); const Array & jacobians_2 = this->non_local_manager.getJacobians(q2.type, q2.ghost_type); const Real & q2_wJ = jacobians_2(q2.global_num); /// compute distance between the two quadrature points Real r = q1_coord.distance(q2_coord); /// compute the weight for averaging on q1 based on the distance Real w1 = this->weight_function->operator()(r, q1, q2); weight(0) = q2_wJ * w1; quad_volumes_1(q1.global_num) += weight(0); if (q2.ghost_type != _ghost && q1.global_num != q2.global_num) { const Array & jacobians_1 = this->non_local_manager.getJacobians(q1.type, q1.ghost_type); Array & quad_volumes_2 = quadrature_points_volumes(q2.type, q2.ghost_type); /// compute the weight for averaging on q2 const Real & q1_wJ = jacobians_1(q1.global_num); Real w2 = this->weight_function->operator()(r, q2, q1); weight(1) = q1_wJ * w2; quad_volumes_2(q2.global_num) += weight(1); } else weight(1) = 0.; } } /// normalize the weights for (auto ghost_type : ghost_types) { foreach_weight(ghost_type, [this, &quadrature_points_volumes]( const auto & q1, const auto & q2, auto & weight) { auto & quad_volumes_1 = quadrature_points_volumes(q1.type, q1.ghost_type); auto & quad_volumes_2 = quadrature_points_volumes(q2.type, q2.ghost_type); Real q1_volume = quad_volumes_1(q1.global_num); auto ghost_type2 = q2.ghost_type; weight(0) *= 1. / q1_volume; if (ghost_type2 != _ghost) { Real q2_volume = quad_volumes_2(q2.global_num); weight(1) *= 1. / q2_volume; } }); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void NonLocalNeighborhood::saveWeights( const std::string & filename) const { std::ofstream pout; std::stringstream sstr; const StaticCommunicator & comm = model.getMesh().getCommunicator(); Int prank = comm.whoAmI(); sstr << filename << "." << prank; pout.open(sstr.str().c_str()); for (UInt gt = _not_ghost; gt <= _ghost; ++gt) { GhostType ghost_type = (GhostType)gt; AKANTU_DEBUG_ASSERT((pair_weight[ghost_type]), "the weights have not been computed yet"); Array & weights = *(pair_weight[ghost_type]); Array::const_vector_iterator weights_it = weights.begin(2); for (UInt i = 0; i < weights.size(); ++i, ++weights_it) pout << "w1: " << (*weights_it)(0) << " w2: " << (*weights_it)(1) << std::endl; } } /* -------------------------------------------------------------------------- */ template void NonLocalNeighborhood::weightedAverageOnNeighbours( const ElementTypeMapReal & to_accumulate, ElementTypeMapReal & accumulated, UInt nb_degree_of_freedom, const GhostType & ghost_type2) const { auto it = non_local_variables.find(accumulated.getName()); // do averaging only for variables registered in the neighborhood if (it == non_local_variables.end()) return; foreach_weight( ghost_type2, [ghost_type2, nb_degree_of_freedom, &to_accumulate, &accumulated](const auto & q1, const auto & q2, auto & weight) { const Vector to_acc_1 = to_accumulate(q1.type, q1.ghost_type) .begin(nb_degree_of_freedom)[q1.global_num]; const Vector to_acc_2 = to_accumulate(q2.type, q2.ghost_type) .begin(nb_degree_of_freedom)[q2.global_num]; Vector acc_1 = accumulated(q1.type, q1.ghost_type) .begin(nb_degree_of_freedom)[q1.global_num]; Vector acc_2 = accumulated(q2.type, q2.ghost_type) .begin(nb_degree_of_freedom)[q2.global_num]; acc_1 += weight(0) * to_acc_2; if (ghost_type2 != _ghost) { acc_2 += weight(1) * to_acc_1; } }); } /* -------------------------------------------------------------------------- */ template void NonLocalNeighborhood::updateWeights() { // Update the weights for the non local variable averaging if (this->weight_function->getUpdateRate() && (this->non_local_manager.getNbStressCalls() % this->weight_function->getUpdateRate() == 0)) { - this->synchronize(_gst_mnl_weight); + SynchronizerRegistry::synchronize(_gst_mnl_weight); this->computeWeights(); } } } // namespace akantu #endif /* __AKANTU_NON_LOCAL_NEIGHBORHOOD_TMPL__ */ diff --git a/src/model/solid_mechanics/material.cc b/src/model/solid_mechanics/material.cc index 60d4c0fc5..88db6df47 100644 --- a/src/model/solid_mechanics/material.cc +++ b/src/model/solid_mechanics/material.cc @@ -1,1613 +1,1609 @@ /** * @file material.cc * * @author Aurelia Isabel Cuba Ramos * @author Daniel Pino Muñoz * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Tue Jul 27 2010 * @date last modification: Tue Nov 24 2015 * * @brief Implementation of the common part of the material class * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "material.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Material::Material(SolidMechanicsModel & model, const ID & id) : Memory(id, model.getMemoryID()), Parsable(_st_material, id), is_init(false), fem(model.getFEEngine()), finite_deformation(false), name(""), model(model), spatial_dimension(this->model.getSpatialDimension()), element_filter("element_filter", id, this->memory_id), stress("stress", *this), eigengradu("eigen_grad_u", *this), gradu("grad_u", *this), green_strain("green_strain", *this), piola_kirchhoff_2("piola_kirchhoff_2", *this), potential_energy("potential_energy", *this), is_non_local(false), use_previous_stress(false), use_previous_gradu(false), interpolation_inverse_coordinates("interpolation inverse coordinates", *this), interpolation_points_matrices("interpolation points matrices", *this) { AKANTU_DEBUG_IN(); /// for each connectivity types allocate the element filer array of the /// material element_filter.initialize(model.getMesh(), _spatial_dimension = spatial_dimension); // model.getMesh().initElementTypeMapArray(element_filter, 1, // spatial_dimension, // false, _ek_regular); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Material::Material(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id) : Memory(id, model.getMemoryID()), Parsable(_st_material, id), is_init(false), fem(model.getFEEngine()), finite_deformation(false), name(""), model(model), spatial_dimension(dim), element_filter("element_filter", id, this->memory_id), stress("stress", *this, dim, fe_engine, this->element_filter), eigengradu("eigen_grad_u", *this, dim, fe_engine, this->element_filter), gradu("gradu", *this, dim, fe_engine, this->element_filter), green_strain("green_strain", *this, dim, fe_engine, this->element_filter), piola_kirchhoff_2("poila_kirchhoff_2", *this, dim, fe_engine, this->element_filter), potential_energy("potential_energy", *this, dim, fe_engine, this->element_filter), is_non_local(false), use_previous_stress(false), use_previous_gradu(false), interpolation_inverse_coordinates("interpolation inverse_coordinates", *this, dim, fe_engine, this->element_filter), interpolation_points_matrices("interpolation points matrices", *this, dim, fe_engine, this->element_filter) { AKANTU_DEBUG_IN(); element_filter.initialize(mesh, _spatial_dimension = spatial_dimension); // mesh.initElementTypeMapArray(element_filter, 1, spatial_dimension, false, // _ek_regular); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -Material::~Material() { - AKANTU_DEBUG_IN(); - - AKANTU_DEBUG_OUT(); -} +Material::~Material() = default; /* -------------------------------------------------------------------------- */ void Material::initialize() { registerParam("rho", rho, Real(0.), _pat_parsable | _pat_modifiable, "Density"); registerParam("name", name, std::string(), _pat_parsable | _pat_readable); registerParam("finite_deformation", finite_deformation, false, _pat_parsable | _pat_readable, "Is finite deformation"); registerParam("inelastic_deformation", inelastic_deformation, false, _pat_internal, "Is inelastic deformation"); /// allocate gradu stress for local elements eigengradu.initialize(spatial_dimension * spatial_dimension); gradu.initialize(spatial_dimension * spatial_dimension); stress.initialize(spatial_dimension * spatial_dimension); potential_energy.initialize(1); this->model.registerEventHandler(*this); } /* -------------------------------------------------------------------------- */ void Material::initMaterial() { AKANTU_DEBUG_IN(); if (finite_deformation) { this->piola_kirchhoff_2.initialize(spatial_dimension * spatial_dimension); if (use_previous_stress) this->piola_kirchhoff_2.initializeHistory(); this->green_strain.initialize(spatial_dimension * spatial_dimension); } if (use_previous_stress) this->stress.initializeHistory(); if (use_previous_gradu) this->gradu.initializeHistory(); for (std::map *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->resize(); for (std::map *>::iterator it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->resize(); for (std::map *>::iterator it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) it->second->resize(); is_init = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::savePreviousState() { AKANTU_DEBUG_IN(); for (std::map *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) { if (it->second->hasHistory()) it->second->saveCurrentValues(); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the residual by assembling @f$\int_{e} \sigma_e \frac{\partial * \varphi}{\partial X} dX @f$ * * @param[in] displacements nodes displacements * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ // void Material::updateResidual(GhostType ghost_type) { // AKANTU_DEBUG_IN(); // computeAllStresses(ghost_type); // assembleResidual(ghost_type); // AKANTU_DEBUG_OUT(); // } /* -------------------------------------------------------------------------- */ void Material::assembleInternalForces(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); if (!finite_deformation) { Array & internal_force = const_cast &>(model.getInternalForce()); Mesh & mesh = fem.getMesh(); Mesh::type_iterator it = element_filter.firstType(spatial_dimension, ghost_type); Mesh::type_iterator last_type = element_filter.lastType(spatial_dimension, ghost_type); for (; it != last_type; ++it) { Array & elem_filter = element_filter(*it, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element) { const Array & shapes_derivatives = fem.getShapesDerivatives(*it, ghost_type); UInt size_of_shapes_derivatives = shapes_derivatives.getNbComponent(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(*it); UInt nb_quadrature_points = fem.getNbIntegrationPoints(*it, ghost_type); /// compute @f$\sigma \frac{\partial \varphi}{\partial X}@f$ by /// @f$\mathbf{B}^t \mathbf{\sigma}_q@f$ Array * sigma_dphi_dx = new Array(nb_element * nb_quadrature_points, size_of_shapes_derivatives, "sigma_x_dphi_/_dX"); Array * shapesd_filtered = new Array(0, size_of_shapes_derivatives, "filtered shapesd"); FEEngine::filterElementalData(mesh, shapes_derivatives, *shapesd_filtered, *it, ghost_type, elem_filter); Array & stress_vect = this->stress(*it, ghost_type); Array::matrix_iterator sigma = stress_vect.begin(spatial_dimension, spatial_dimension); Array::matrix_iterator B = shapesd_filtered->begin(spatial_dimension, nb_nodes_per_element); Array::matrix_iterator Bt_sigma_it = sigma_dphi_dx->begin(spatial_dimension, nb_nodes_per_element); for (UInt q = 0; q < nb_element * nb_quadrature_points; ++q, ++sigma, ++B, ++Bt_sigma_it) Bt_sigma_it->mul(*sigma, *B); delete shapesd_filtered; /** * compute @f$\int \sigma * \frac{\partial \varphi}{\partial X}dX@f$ by * @f$ \sum_q \mathbf{B}^t * \mathbf{\sigma}_q \overline w_q J_q@f$ */ Array * int_sigma_dphi_dx = new Array( nb_element, nb_nodes_per_element * spatial_dimension, "int_sigma_x_dphi_/_dX"); fem.integrate(*sigma_dphi_dx, *int_sigma_dphi_dx, size_of_shapes_derivatives, *it, ghost_type, elem_filter); delete sigma_dphi_dx; /// assemble model.getDOFManager().assembleElementalArrayLocalArray( *int_sigma_dphi_dx, internal_force, *it, ghost_type, -1, elem_filter); delete int_sigma_dphi_dx; } } } else { switch (spatial_dimension) { case 1: this->assembleInternalForces<1>(ghost_type); break; case 2: this->assembleInternalForces<2>(ghost_type); break; case 3: this->assembleInternalForces<3>(ghost_type); break; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the stress from the gradu * * @param[in] current_position nodes postition + displacements * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ void Material::computeAllStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); for (const auto & type : element_filter.elementTypes(spatial_dimension, ghost_type)) { Array & elem_filter = element_filter(type, ghost_type); if (elem_filter.size() == 0) continue; Array & gradu_vect = gradu(type, ghost_type); /// compute @f$\nabla u@f$ fem.gradientOnIntegrationPoints(model.getDisplacement(), gradu_vect, spatial_dimension, type, ghost_type, elem_filter); gradu_vect -= eigengradu(type, ghost_type); /// compute @f$\mathbf{\sigma}_q@f$ from @f$\nabla u@f$ computeStress(type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computeAllCauchyStresses(GhostType ghost_type) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_ASSERT(finite_deformation, "The Cauchy stress can only be " "computed if you are working in " "finite deformation."); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { switch (spatial_dimension) { case 1: this->computeCauchyStress<1>(type, ghost_type); break; case 2: this->computeCauchyStress<2>(type, ghost_type); break; case 3: this->computeCauchyStress<3>(type, ghost_type); break; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Material::computeCauchyStress(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array::matrix_iterator gradu_it = this->gradu(el_type, ghost_type).begin(dim, dim); Array::matrix_iterator gradu_end = this->gradu(el_type, ghost_type).end(dim, dim); Array::matrix_iterator piola_it = this->piola_kirchhoff_2(el_type, ghost_type).begin(dim, dim); Array::matrix_iterator stress_it = this->stress(el_type, ghost_type).begin(dim, dim); Matrix F_tensor(dim, dim); for (; gradu_it != gradu_end; ++gradu_it, ++piola_it, ++stress_it) { Matrix & grad_u = *gradu_it; Matrix & piola = *piola_it; Matrix & sigma = *stress_it; gradUToF(grad_u, F_tensor); this->computeCauchyStressOnQuad(F_tensor, piola, sigma); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::setToSteadyState(GhostType ghost_type) { AKANTU_DEBUG_IN(); const Array & displacement = model.getDisplacement(); // resizeInternalArray(gradu); UInt spatial_dimension = model.getSpatialDimension(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { Array & elem_filter = element_filter(type, ghost_type); Array & gradu_vect = gradu(type, ghost_type); /// compute @f$\nabla u@f$ fem.gradientOnIntegrationPoints(displacement, gradu_vect, spatial_dimension, type, ghost_type, elem_filter); setToSteadyState(type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ /** * Compute the stiffness matrix by assembling @f$\int_{\omega} B^t \times D * \times B d\omega @f$ * * @param[in] current_position nodes postition + displacements * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ void Material::assembleStiffnessMatrix(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { if (finite_deformation) { switch (spatial_dimension) { case 1: { assembleStiffnessMatrixNL<1>(type, ghost_type); assembleStiffnessMatrixL2<1>(type, ghost_type); break; } case 2: { assembleStiffnessMatrixNL<2>(type, ghost_type); assembleStiffnessMatrixL2<2>(type, ghost_type); break; } case 3: { assembleStiffnessMatrixNL<3>(type, ghost_type); assembleStiffnessMatrixL2<3>(type, ghost_type); break; } } } else { switch (spatial_dimension) { case 1: { assembleStiffnessMatrix<1>(type, ghost_type); break; } case 2: { assembleStiffnessMatrix<2>(type, ghost_type); break; } case 3: { assembleStiffnessMatrix<3>(type, ghost_type); break; } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Material::assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array & elem_filter = element_filter(type, ghost_type); if (elem_filter.size()) { const Array & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); Array & gradu_vect = gradu(type, ghost_type); UInt nb_element = elem_filter.size(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); gradu_vect.resize(nb_quadrature_points * nb_element); fem.gradientOnIntegrationPoints(model.getDisplacement(), gradu_vect, dim, type, ghost_type, elem_filter); UInt tangent_size = getTangentStiffnessVoigtSize(dim); Array * tangent_stiffness_matrix = new Array( nb_element * nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); tangent_stiffness_matrix->clear(); computeTangentModuli(type, *tangent_stiffness_matrix, ghost_type); Array * shapesd_filtered = new Array( nb_element, dim * nb_nodes_per_element, "filtered shapesd"); FEEngine::filterElementalData(fem.getMesh(), shapes_derivatives, *shapesd_filtered, type, ghost_type, elem_filter); /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_d_b_size = dim * nb_nodes_per_element; Array * bt_d_b = new Array(nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B"); Matrix B(tangent_size, dim * nb_nodes_per_element); Matrix Bt_D(dim * nb_nodes_per_element, tangent_size); Array::matrix_iterator shapes_derivatives_filtered_it = shapesd_filtered->begin(dim, nb_nodes_per_element); Array::matrix_iterator Bt_D_B_it = bt_d_b->begin(dim * nb_nodes_per_element, dim * nb_nodes_per_element); Array::matrix_iterator D_it = tangent_stiffness_matrix->begin(tangent_size, tangent_size); Array::matrix_iterator D_end = tangent_stiffness_matrix->end(tangent_size, tangent_size); for (; D_it != D_end; ++D_it, ++Bt_D_B_it, ++shapes_derivatives_filtered_it) { Matrix & D = *D_it; Matrix & Bt_D_B = *Bt_D_B_it; VoigtHelper::transferBMatrixToSymVoigtBMatrix( *shapes_derivatives_filtered_it, B, nb_nodes_per_element); Bt_D.mul(B, D); Bt_D_B.mul(Bt_D, B); } delete tangent_stiffness_matrix; delete shapesd_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Array * K_e = new Array(nb_element, bt_d_b_size * bt_d_b_size, "K_e"); fem.integrate(*bt_d_b, *K_e, bt_d_b_size * bt_d_b_size, type, ghost_type, elem_filter); delete bt_d_b; model.getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *K_e, type, ghost_type, _symmetric, elem_filter); delete K_e; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Material::assembleStiffnessMatrixNL(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); const Array & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); Array & elem_filter = element_filter(type, ghost_type); // Array & gradu_vect = delta_gradu(type, ghost_type); UInt nb_element = elem_filter.size(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); // gradu_vect.resize(nb_quadrature_points * nb_element); // fem.gradientOnIntegrationPoints(model.getIncrement(), gradu_vect, // dim, type, ghost_type, &elem_filter); Array * shapes_derivatives_filtered = new Array( nb_element * nb_quadrature_points, dim * nb_nodes_per_element, "shapes derivatives filtered"); Array::const_matrix_iterator shapes_derivatives_it = shapes_derivatives.begin(spatial_dimension, nb_nodes_per_element); Array::matrix_iterator shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin(spatial_dimension, nb_nodes_per_element); UInt * elem_filter_val = elem_filter.storage(); for (UInt e = 0; e < nb_element; ++e, ++elem_filter_val) for (UInt q = 0; q < nb_quadrature_points; ++q, ++shapes_derivatives_filtered_it) *shapes_derivatives_filtered_it = shapes_derivatives_it[*elem_filter_val * nb_quadrature_points + q]; /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_s_b_size = dim * nb_nodes_per_element; Array * bt_s_b = new Array(nb_element * nb_quadrature_points, bt_s_b_size * bt_s_b_size, "B^t*D*B"); UInt piola_matrix_size = getCauchyStressMatrixSize(dim); Matrix B(piola_matrix_size, bt_s_b_size); Matrix Bt_S(bt_s_b_size, piola_matrix_size); Matrix S(piola_matrix_size, piola_matrix_size); shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin( spatial_dimension, nb_nodes_per_element); Array::matrix_iterator Bt_S_B_it = bt_s_b->begin(bt_s_b_size, bt_s_b_size); Array::matrix_iterator Bt_S_B_end = bt_s_b->end(bt_s_b_size, bt_s_b_size); Array::matrix_iterator piola_it = piola_kirchhoff_2(type, ghost_type).begin(dim, dim); for (; Bt_S_B_it != Bt_S_B_end; ++Bt_S_B_it, ++shapes_derivatives_filtered_it, ++piola_it) { Matrix & Bt_S_B = *Bt_S_B_it; Matrix & Piola_kirchhoff_matrix = *piola_it; setCauchyStressMatrix(Piola_kirchhoff_matrix, S); VoigtHelper::transferBMatrixToBNL(*shapes_derivatives_filtered_it, B, nb_nodes_per_element); Bt_S.mul(B, S); Bt_S_B.mul(Bt_S, B); } delete shapes_derivatives_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Array * K_e = new Array(nb_element, bt_s_b_size * bt_s_b_size, "K_e"); fem.integrate(*bt_s_b, *K_e, bt_s_b_size * bt_s_b_size, type, ghost_type, elem_filter); delete bt_s_b; model.getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *K_e, type, ghost_type, _symmetric, elem_filter); delete K_e; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Material::assembleStiffnessMatrixL2(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); const Array & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); Array & elem_filter = element_filter(type, ghost_type); Array & gradu_vect = gradu(type, ghost_type); UInt nb_element = elem_filter.size(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); gradu_vect.resize(nb_quadrature_points * nb_element); fem.gradientOnIntegrationPoints(model.getDisplacement(), gradu_vect, dim, type, ghost_type, elem_filter); UInt tangent_size = getTangentStiffnessVoigtSize(dim); Array * tangent_stiffness_matrix = new Array(nb_element * nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); tangent_stiffness_matrix->clear(); computeTangentModuli(type, *tangent_stiffness_matrix, ghost_type); Array * shapes_derivatives_filtered = new Array( nb_element * nb_quadrature_points, dim * nb_nodes_per_element, "shapes derivatives filtered"); Array::const_matrix_iterator shapes_derivatives_it = shapes_derivatives.begin(spatial_dimension, nb_nodes_per_element); Array::matrix_iterator shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin(spatial_dimension, nb_nodes_per_element); UInt * elem_filter_val = elem_filter.storage(); for (UInt e = 0; e < nb_element; ++e, ++elem_filter_val) for (UInt q = 0; q < nb_quadrature_points; ++q, ++shapes_derivatives_filtered_it) *shapes_derivatives_filtered_it = shapes_derivatives_it[*elem_filter_val * nb_quadrature_points + q]; /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_d_b_size = dim * nb_nodes_per_element; Array * bt_d_b = new Array(nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B"); Matrix B(tangent_size, dim * nb_nodes_per_element); Matrix B2(tangent_size, dim * nb_nodes_per_element); Matrix Bt_D(dim * nb_nodes_per_element, tangent_size); shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin( spatial_dimension, nb_nodes_per_element); Array::matrix_iterator Bt_D_B_it = bt_d_b->begin(dim * nb_nodes_per_element, dim * nb_nodes_per_element); Array::matrix_iterator grad_u_it = gradu_vect.begin(dim, dim); Array::matrix_iterator D_it = tangent_stiffness_matrix->begin(tangent_size, tangent_size); Array::matrix_iterator D_end = tangent_stiffness_matrix->end(tangent_size, tangent_size); for (; D_it != D_end; ++D_it, ++Bt_D_B_it, ++shapes_derivatives_filtered_it, ++grad_u_it) { Matrix & grad_u = *grad_u_it; Matrix & D = *D_it; Matrix & Bt_D_B = *Bt_D_B_it; // transferBMatrixToBL1 (*shapes_derivatives_filtered_it, B, // nb_nodes_per_element); VoigtHelper::transferBMatrixToSymVoigtBMatrix( *shapes_derivatives_filtered_it, B, nb_nodes_per_element); VoigtHelper::transferBMatrixToBL2(*shapes_derivatives_filtered_it, grad_u, B2, nb_nodes_per_element); B += B2; Bt_D.mul(B, D); Bt_D_B.mul(Bt_D, B); } delete tangent_stiffness_matrix; delete shapes_derivatives_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Array * K_e = new Array(nb_element, bt_d_b_size * bt_d_b_size, "K_e"); fem.integrate(*bt_d_b, *K_e, bt_d_b_size * bt_d_b_size, type, ghost_type, elem_filter); delete bt_d_b; model.getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *K_e, type, ghost_type, _symmetric, elem_filter); delete K_e; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Material::assembleInternalForces(GhostType ghost_type) { AKANTU_DEBUG_IN(); Array & internal_force = model.getInternalForce(); Mesh & mesh = fem.getMesh(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { const Array & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); Array & elem_filter = element_filter(type, ghost_type); if (elem_filter.size() == 0) continue; UInt size_of_shapes_derivatives = shapes_derivatives.getNbComponent(); UInt nb_element = elem_filter.size(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); Array * shapesd_filtered = new Array( nb_element, size_of_shapes_derivatives, "filtered shapesd"); FEEngine::filterElementalData(mesh, shapes_derivatives, *shapesd_filtered, type, ghost_type, elem_filter); Array::matrix_iterator shapes_derivatives_filtered_it = shapesd_filtered->begin(dim, nb_nodes_per_element); // Set stress vectors UInt stress_size = getTangentStiffnessVoigtSize(dim); // Set matrices B and BNL* UInt bt_s_size = dim * nb_nodes_per_element; Array * bt_s = new Array(nb_element * nb_quadrature_points, bt_s_size, "B^t*S"); Array::matrix_iterator grad_u_it = this->gradu(type, ghost_type).begin(dim, dim); Array::matrix_iterator grad_u_end = this->gradu(type, ghost_type).end(dim, dim); Array::matrix_iterator stress_it = this->piola_kirchhoff_2(type, ghost_type).begin(dim, dim); shapes_derivatives_filtered_it = shapesd_filtered->begin(dim, nb_nodes_per_element); Array::matrix_iterator bt_s_it = bt_s->begin(bt_s_size, 1); Matrix S_vect(stress_size, 1); Matrix B_tensor(stress_size, bt_s_size); Matrix B2_tensor(stress_size, bt_s_size); for (; grad_u_it != grad_u_end; ++grad_u_it, ++stress_it, ++shapes_derivatives_filtered_it, ++bt_s_it) { Matrix & grad_u = *grad_u_it; Matrix & r_it = *bt_s_it; Matrix & S_it = *stress_it; setCauchyStressArray(S_it, S_vect); VoigtHelper::transferBMatrixToSymVoigtBMatrix( *shapes_derivatives_filtered_it, B_tensor, nb_nodes_per_element); VoigtHelper::transferBMatrixToBL2(*shapes_derivatives_filtered_it, grad_u, B2_tensor, nb_nodes_per_element); B_tensor += B2_tensor; r_it.mul(B_tensor, S_vect); } delete shapesd_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ Array * r_e = new Array(nb_element, bt_s_size, "r_e"); fem.integrate(*bt_s, *r_e, bt_s_size, type, ghost_type, elem_filter); delete bt_s; model.getDOFManager().assembleElementalArrayLocalArray( *r_e, internal_force, type, ghost_type, -1., elem_filter); delete r_e; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computeAllStressesFromTangentModuli(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { switch (spatial_dimension) { case 1: { computeAllStressesFromTangentModuli<1>(type, ghost_type); break; } case 2: { computeAllStressesFromTangentModuli<2>(type, ghost_type); break; } case 3: { computeAllStressesFromTangentModuli<3>(type, ghost_type); break; } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void Material::computeAllStressesFromTangentModuli(const ElementType & type, GhostType ghost_type) { AKANTU_DEBUG_IN(); const Array & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); Array & elem_filter = element_filter(type, ghost_type); Array & gradu_vect = gradu(type, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element) { UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); gradu_vect.resize(nb_quadrature_points * nb_element); Array & disp = model.getDisplacement(); fem.gradientOnIntegrationPoints(disp, gradu_vect, dim, type, ghost_type, elem_filter); UInt tangent_moduli_size = getTangentStiffnessVoigtSize(dim); Array * tangent_moduli_tensors = new Array( nb_element * nb_quadrature_points, tangent_moduli_size * tangent_moduli_size, "tangent_moduli_tensors"); tangent_moduli_tensors->clear(); computeTangentModuli(type, *tangent_moduli_tensors, ghost_type); Array * shapesd_filtered = new Array( nb_element, dim * nb_nodes_per_element, "filtered shapesd"); FEEngine::filterElementalData(fem.getMesh(), shapes_derivatives, *shapesd_filtered, type, ghost_type, elem_filter); Array filtered_u(nb_element, nb_nodes_per_element * spatial_dimension); FEEngine::extractNodalToElementField(fem.getMesh(), disp, filtered_u, type, ghost_type, elem_filter); /// compute @f$\mathbf{D} \mathbf{B} \mathbf{u}@f$ Array::matrix_iterator shapes_derivatives_filtered_it = shapesd_filtered->begin(dim, nb_nodes_per_element); Array::matrix_iterator D_it = tangent_moduli_tensors->begin(tangent_moduli_size, tangent_moduli_size); Array::matrix_iterator sigma_it = stress(type, ghost_type).begin(spatial_dimension, spatial_dimension); Array::vector_iterator u_it = filtered_u.begin(spatial_dimension * nb_nodes_per_element); Matrix B(tangent_moduli_size, spatial_dimension * nb_nodes_per_element); Vector Bu(tangent_moduli_size); Vector DBu(tangent_moduli_size); for (UInt e = 0; e < nb_element; ++e, ++u_it) { for (UInt q = 0; q < nb_quadrature_points; ++q, ++D_it, ++shapes_derivatives_filtered_it, ++sigma_it) { Vector & u = *u_it; Matrix & sigma = *sigma_it; Matrix & D = *D_it; VoigtHelper::transferBMatrixToSymVoigtBMatrix( *shapes_derivatives_filtered_it, B, nb_nodes_per_element); Bu.mul(B, u); DBu.mul(D, Bu); // Voigt notation to full symmetric tensor for (UInt i = 0; i < dim; ++i) sigma(i, i) = DBu(i); if (dim == 2) { sigma(0, 1) = sigma(1, 0) = DBu(2); } else if (dim == 3) { sigma(1, 2) = sigma(2, 1) = DBu(3); sigma(0, 2) = sigma(2, 0) = DBu(4); sigma(0, 1) = sigma(1, 0) = DBu(5); } } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computePotentialEnergyByElements() { AKANTU_DEBUG_IN(); for (auto type : element_filter.elementTypes(spatial_dimension, _not_ghost)) { computePotentialEnergy(type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::computePotentialEnergy(ElementType, GhostType) { AKANTU_DEBUG_IN(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real Material::getPotentialEnergy() { AKANTU_DEBUG_IN(); Real epot = 0.; computePotentialEnergyByElements(); /// integrate the potential energy for each type of elements for (auto type : element_filter.elementTypes(spatial_dimension, _not_ghost)) { epot += fem.integrate(potential_energy(type, _not_ghost), type, _not_ghost, element_filter(type, _not_ghost)); } AKANTU_DEBUG_OUT(); return epot; } /* -------------------------------------------------------------------------- */ Real Material::getPotentialEnergy(ElementType & type, UInt index) { AKANTU_DEBUG_IN(); Real epot = 0.; Vector epot_on_quad_points(fem.getNbIntegrationPoints(type)); computePotentialEnergyByElement(type, index, epot_on_quad_points); epot = fem.integrate(epot_on_quad_points, type, element_filter(type)(index)); AKANTU_DEBUG_OUT(); return epot; } /* -------------------------------------------------------------------------- */ Real Material::getEnergy(std::string type) { AKANTU_DEBUG_IN(); if (type == "potential") return getPotentialEnergy(); AKANTU_DEBUG_OUT(); return 0.; } /* -------------------------------------------------------------------------- */ Real Material::getEnergy(std::string energy_id, ElementType type, UInt index) { AKANTU_DEBUG_IN(); if (energy_id == "potential") return getPotentialEnergy(type, index); AKANTU_DEBUG_OUT(); return 0.; } /* -------------------------------------------------------------------------- */ void Material::initElementalFieldInterpolation( const ElementTypeMapArray & interpolation_points_coordinates) { AKANTU_DEBUG_IN(); this->fem.initElementalFieldInterpolationFromIntegrationPoints( interpolation_points_coordinates, this->interpolation_points_matrices, this->interpolation_inverse_coordinates, &(this->element_filter)); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::interpolateStress(ElementTypeMapArray & result, const GhostType ghost_type) { this->fem.interpolateElementalFieldFromIntegrationPoints( this->stress, this->interpolation_points_matrices, this->interpolation_inverse_coordinates, result, ghost_type, &(this->element_filter)); } /* -------------------------------------------------------------------------- */ void Material::interpolateStressOnFacets( ElementTypeMapArray & result, ElementTypeMapArray & by_elem_result, const GhostType ghost_type) { interpolateStress(by_elem_result, ghost_type); UInt stress_size = this->stress.getNbComponent(); const Mesh & mesh = this->model.getMesh(); const Mesh & mesh_facets = mesh.getMeshFacets(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type)) { Array & elem_fil = element_filter(type, ghost_type); Array & by_elem_res = by_elem_result(type, ghost_type); UInt nb_element = elem_fil.size(); UInt nb_element_full = this->model.getMesh().getNbElement(type, ghost_type); UInt nb_interpolation_points_per_elem = by_elem_res.size() / nb_element_full; const Array & facet_to_element = mesh_facets.getSubelementToElement(type, ghost_type); ElementType type_facet = Mesh::getFacetType(type); UInt nb_facet_per_elem = facet_to_element.getNbComponent(); UInt nb_quad_per_facet = nb_interpolation_points_per_elem / nb_facet_per_elem; Element element_for_comparison(type, 0, ghost_type); const Array> * element_to_facet = NULL; GhostType current_ghost_type = _casper; Array * result_vec = NULL; Array::const_matrix_iterator result_it = by_elem_res.begin_reinterpret( stress_size, nb_interpolation_points_per_elem, nb_element_full); for (UInt el = 0; el < nb_element; ++el) { UInt global_el = elem_fil(el); element_for_comparison.element = global_el; for (UInt f = 0; f < nb_facet_per_elem; ++f) { Element facet_elem = facet_to_element(global_el, f); UInt global_facet = facet_elem.element; if (facet_elem.ghost_type != current_ghost_type) { current_ghost_type = facet_elem.ghost_type; element_to_facet = &mesh_facets.getElementToSubelement( type_facet, current_ghost_type); result_vec = &result(type_facet, current_ghost_type); } bool is_second_element = (*element_to_facet)(global_facet)[0] != element_for_comparison; for (UInt q = 0; q < nb_quad_per_facet; ++q) { Vector result_local(result_vec->storage() + (global_facet * nb_quad_per_facet + q) * result_vec->getNbComponent() + is_second_element * stress_size, stress_size); const Matrix & result_tmp(result_it[global_el]); result_local = result_tmp(f * nb_quad_per_facet + q); } } } } } /* -------------------------------------------------------------------------- */ template const Array & Material::getArray(__attribute__((unused)) const ID & vect_id, __attribute__((unused)) const ElementType & type, __attribute__((unused)) const GhostType & ghost_type) const { AKANTU_DEBUG_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template Array & Material::getArray(__attribute__((unused)) const ID & vect_id, __attribute__((unused)) const ElementType & type, __attribute__((unused)) const GhostType & ghost_type) { AKANTU_DEBUG_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template <> const Array & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) const { std::stringstream sstr; std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; sstr << getID() << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getArray(fvect_id); } catch (debug::Exception & e) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain a vector " << vect_id << "(" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ template <> Array & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) { std::stringstream sstr; std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; sstr << getID() << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getArray(fvect_id); } catch (debug::Exception & e) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain a vector " << vect_id << "(" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ template <> const Array & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) const { std::stringstream sstr; std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; sstr << getID() << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getArray(fvect_id); } catch (debug::Exception & e) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain a vector " << vect_id << "(" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ template <> Array & Material::getArray(const ID & vect_id, const ElementType & type, const GhostType & ghost_type) { std::stringstream sstr; std::string ghost_id = ""; if (ghost_type == _ghost) ghost_id = ":ghost"; sstr << getID() << ":" << vect_id << ":" << type << ghost_id; ID fvect_id = sstr.str(); try { return Memory::getArray(fvect_id); } catch (debug::Exception & e) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain a vector " << vect_id << "(" << fvect_id << ") [" << e << "]"); } } /* -------------------------------------------------------------------------- */ template const InternalField & Material::getInternal(__attribute__((unused)) const ID & int_id) const { AKANTU_DEBUG_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template InternalField & Material::getInternal(__attribute__((unused)) const ID & int_id) { AKANTU_DEBUG_TO_IMPLEMENT(); return NULL; } /* -------------------------------------------------------------------------- */ template <> const InternalField & Material::getInternal(const ID & int_id) const { std::map *>::const_iterator it = internal_vectors_real.find(getID() + ":" + int_id); if (it == internal_vectors_real.end()) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain an internal " << int_id << " (" << (getID() + ":" + int_id) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ template <> InternalField & Material::getInternal(const ID & int_id) { std::map *>::iterator it = internal_vectors_real.find(getID() + ":" + int_id); if (it == internal_vectors_real.end()) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain an internal " << int_id << " (" << (getID() + ":" + int_id) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ template <> const InternalField & Material::getInternal(const ID & int_id) const { std::map *>::const_iterator it = internal_vectors_uint.find(getID() + ":" + int_id); if (it == internal_vectors_uint.end()) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain an internal " << int_id << " (" << (getID() + ":" + int_id) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ template <> InternalField & Material::getInternal(const ID & int_id) { std::map *>::iterator it = internal_vectors_uint.find(getID() + ":" + int_id); if (it == internal_vectors_uint.end()) { AKANTU_SILENT_EXCEPTION("The material " << name << "(" << getID() << ") does not contain an internal " << int_id << " (" << (getID() + ":" + int_id) << ")"); } return *it->second; } /* -------------------------------------------------------------------------- */ void Material::addElements(const Array & elements_to_add) { AKANTU_DEBUG_IN(); UInt mat_id = model.getInternalIndexFromID(getID()); Array::const_iterator el_begin = elements_to_add.begin(); Array::const_iterator el_end = elements_to_add.end(); for (; el_begin != el_end; ++el_begin) { const Element & element = *el_begin; Array & mat_indexes = model.getMaterialByElement(element.type, element.ghost_type); Array & mat_loc_num = model.getMaterialLocalNumbering(element.type, element.ghost_type); UInt index = this->addElement(element.type, element.element, element.ghost_type); mat_indexes(element.element) = mat_id; mat_loc_num(element.element) = index; } this->resizeInternals(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::removeElements(const Array & elements_to_remove) { AKANTU_DEBUG_IN(); Array::const_iterator el_begin = elements_to_remove.begin(); Array::const_iterator el_end = elements_to_remove.end(); if (el_begin == el_end) return; ElementTypeMapArray material_local_new_numbering( "remove mat filter elem", getID(), getMemoryID()); Element element; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { GhostType ghost_type = *gt; element.ghost_type = ghost_type; ElementTypeMapArray::type_iterator it = element_filter.firstType(_all_dimensions, ghost_type, _ek_not_defined); ElementTypeMapArray::type_iterator end = element_filter.lastType(_all_dimensions, ghost_type, _ek_not_defined); for (; it != end; ++it) { ElementType type = *it; element.type = type; Array & elem_filter = this->element_filter(type, ghost_type); Array & mat_loc_num = this->model.getMaterialLocalNumbering(type, ghost_type); if (!material_local_new_numbering.exists(type, ghost_type)) material_local_new_numbering.alloc(elem_filter.size(), 1, type, ghost_type); Array & mat_renumbering = material_local_new_numbering(type, ghost_type); UInt nb_element = elem_filter.size(); element.kind = (*el_begin).kind; Array elem_filter_tmp; UInt new_id = 0; for (UInt el = 0; el < nb_element; ++el) { element.element = elem_filter(el); if (std::find(el_begin, el_end, element) == el_end) { elem_filter_tmp.push_back(element.element); mat_renumbering(el) = new_id; mat_loc_num(element.element) = new_id; ++new_id; } else { mat_renumbering(el) = UInt(-1); } } elem_filter.resize(elem_filter_tmp.size()); elem_filter.copy(elem_filter_tmp); } } for (std::map *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (std::map *>::iterator it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (std::map *>::iterator it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::resizeInternals() { AKANTU_DEBUG_IN(); for (std::map *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->resize(); for (std::map *>::iterator it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->resize(); for (std::map *>::iterator it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) it->second->resize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void Material::onElementsAdded(const Array &, const NewElementsEvent &) { this->resizeInternals(); } /* -------------------------------------------------------------------------- */ void Material::onElementsRemoved( const Array & element_list, const ElementTypeMapArray & new_numbering, __attribute__((unused)) const RemovedElementsEvent & event) { UInt my_num = model.getInternalIndexFromID(getID()); ElementTypeMapArray material_local_new_numbering( "remove mat filter elem", getID(), getMemoryID()); Array::const_iterator el_begin = element_list.begin(); Array::const_iterator el_end = element_list.end(); for (ghost_type_t::iterator g = ghost_type_t::begin(); g != ghost_type_t::end(); ++g) { GhostType gt = *g; ElementTypeMapArray::type_iterator it = new_numbering.firstType(_all_dimensions, gt, _ek_not_defined); ElementTypeMapArray::type_iterator end = new_numbering.lastType(_all_dimensions, gt, _ek_not_defined); for (; it != end; ++it) { ElementType type = *it; if (element_filter.exists(type, gt) && element_filter(type, gt).size()) { Array & elem_filter = element_filter(type, gt); Array & mat_indexes = this->model.getMaterialByElement(*it, gt); Array & mat_loc_num = this->model.getMaterialLocalNumbering(*it, gt); UInt nb_element = this->model.getMesh().getNbElement(type, gt); // all materials will resize of the same size... mat_indexes.resize(nb_element); mat_loc_num.resize(nb_element); if (!material_local_new_numbering.exists(type, gt)) material_local_new_numbering.alloc(elem_filter.size(), 1, type, gt); Array & mat_renumbering = material_local_new_numbering(type, gt); const Array & renumbering = new_numbering(type, gt); Array elem_filter_tmp; UInt ni = 0; Element el; el.type = type; el.ghost_type = gt; el.kind = Mesh::getKind(type); for (UInt i = 0; i < elem_filter.size(); ++i) { el.element = elem_filter(i); if (std::find(el_begin, el_end, el) == el_end) { UInt new_el = renumbering(el.element); AKANTU_DEBUG_ASSERT( new_el != UInt(-1), "A not removed element as been badly renumbered"); elem_filter_tmp.push_back(new_el); mat_renumbering(i) = ni; mat_indexes(new_el) = my_num; mat_loc_num(new_el) = ni; ++ni; } else { mat_renumbering(i) = UInt(-1); } } elem_filter.resize(elem_filter_tmp.size()); elem_filter.copy(elem_filter_tmp); } } } for (std::map *>::iterator it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (std::map *>::iterator it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); for (std::map *>::iterator it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) it->second->removeIntegrationPoints(material_local_new_numbering); } /* -------------------------------------------------------------------------- */ void Material::beforeSolveStep() { this->savePreviousState(); } /* -------------------------------------------------------------------------- */ void Material::afterSolveStep() { for (auto & type : element_filter.elementTypes(_all_dimensions, _not_ghost, _ek_not_defined)) { this->updateEnergies(type, _not_ghost); } } /* -------------------------------------------------------------------------- */ void Material::onDamageIteration() { this->savePreviousState(); } /* -------------------------------------------------------------------------- */ void Material::onDamageUpdate() { ElementTypeMapArray::type_iterator it = this->element_filter.firstType( _all_dimensions, _not_ghost, _ek_not_defined); ElementTypeMapArray::type_iterator end = element_filter.lastType(_all_dimensions, _not_ghost, _ek_not_defined); for (; it != end; ++it) { this->updateEnergiesAfterDamage(*it, _not_ghost); } } /* -------------------------------------------------------------------------- */ void Material::onDump() { if (this->isFiniteDeformation()) this->computeAllCauchyStresses(_not_ghost); } /* -------------------------------------------------------------------------- */ void Material::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; std::string type = getID().substr(getID().find_last_of(":") + 1); stream << space << "Material " << type << " [" << std::endl; Parsable::printself(stream, indent); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ /// extrapolate internal values void Material::extrapolateInternal(const ID & id, const Element & element, __attribute__((unused)) const Matrix & point, Matrix & extrapolated) { if (this->isInternal(id, element.kind)) { UInt nb_element = this->element_filter(element.type, element.ghost_type).size(); const ID name = this->getID() + ":" + id; UInt nb_quads = this->internal_vectors_real[name]->getFEEngine().getNbIntegrationPoints( element.type, element.ghost_type); const Array & internal = this->getArray(id, element.type, element.ghost_type); UInt nb_component = internal.getNbComponent(); Array::const_matrix_iterator internal_it = internal.begin_reinterpret(nb_component, nb_quads, nb_element); Element local_element = this->convertToLocalElement(element); /// instead of really extrapolating, here the value of the first GP /// is copied into the result vector. This works only for linear /// elements /// @todo extrapolate!!!! AKANTU_DEBUG_WARNING("This is a fix, values are not truly extrapolated"); const Matrix & values = internal_it[local_element.element]; UInt index = 0; Vector tmp(nb_component); for (UInt j = 0; j < values.cols(); ++j) { tmp = values(j); if (tmp.norm() > 0) { index = j; break; } } for (UInt i = 0; i < extrapolated.size(); ++i) { extrapolated(i) = values(index); } } else { Matrix default_values(extrapolated.rows(), extrapolated.cols(), 0.); extrapolated = default_values; } } /* -------------------------------------------------------------------------- */ void Material::applyEigenGradU(const Matrix & prescribed_eigen_grad_u, const GhostType ghost_type) { for (auto && type : element_filter.elementTypes(_all_dimensions, _not_ghost, _ek_not_defined)) { if (!element_filter(type, ghost_type).size()) continue; auto eigen_it = this->eigengradu(type, ghost_type) .begin(spatial_dimension, spatial_dimension); auto eigen_end = this->eigengradu(type, ghost_type) .end(spatial_dimension, spatial_dimension); for (; eigen_it != eigen_end; ++eigen_it) { auto & current_eigengradu = *eigen_it; current_eigengradu = prescribed_eigen_grad_u; } } } } // namespace akantu diff --git a/src/model/solid_mechanics/material.hh b/src/model/solid_mechanics/material.hh index 607c34d01..311e68a66 100644 --- a/src/model/solid_mechanics/material.hh +++ b/src/model/solid_mechanics/material.hh @@ -1,682 +1,683 @@ /** * @file material.hh * * @author Daniel Pino Muñoz * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Fri Jun 18 2010 * @date last modification: Wed Nov 25 2015 * * @brief Mother class for all materials * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_factory.hh" #include "aka_voigthelper.hh" #include "data_accessor.hh" #include "integration_point.hh" #include "parsable.hh" #include "parser.hh" /* -------------------------------------------------------------------------- */ #include "internal_field.hh" #include "random_internal_field.hh" /* -------------------------------------------------------------------------- */ #include "mesh_events.hh" #include "solid_mechanics_model_event_handler.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_HH__ #define __AKANTU_MATERIAL_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class Model; class SolidMechanicsModel; } // namespace akantu namespace akantu { /** * Interface of all materials * Prerequisites for a new material * - inherit from this class * - implement the following methods: * \code * virtual Real getStableTimeStep(Real h, const Element & element = * ElementNull); * * virtual void computeStress(ElementType el_type, * GhostType ghost_type = _not_ghost); * * virtual void computeTangentStiffness(const ElementType & el_type, * Array & tangent_matrix, * GhostType ghost_type = _not_ghost); * \endcode * */ class Material : public Memory, public DataAccessor, public Parsable, public MeshEventHandler, protected SolidMechanicsModelEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: #if __cplusplus > 199711L Material(const Material & mat) = delete; Material & operator=(const Material & mat) = delete; #endif /// Initialize material with defaults Material(SolidMechanicsModel & model, const ID & id = ""); /// Initialize material with custom mesh & fe_engine Material(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id = ""); /// Destructor virtual ~Material(); protected: void initialize(); /* ------------------------------------------------------------------------ */ /* Function that materials can/should reimplement */ /* ------------------------------------------------------------------------ */ protected: /// constitutive law virtual void computeStress(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// compute the tangent stiffness matrix virtual void computeTangentModuli(__attribute__((unused)) const ElementType & el_type, __attribute__((unused)) Array & tangent_matrix, __attribute__((unused)) GhostType ghost_type = _not_ghost) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// compute the potential energy virtual void computePotentialEnergy(ElementType el_type, GhostType ghost_type = _not_ghost); /// compute the potential energy for an element virtual void computePotentialEnergyByElement(__attribute__((unused)) ElementType type, __attribute__((unused)) UInt index, __attribute__((unused)) Vector & epot_on_quad_points) { AKANTU_DEBUG_TO_IMPLEMENT(); } virtual void updateEnergies(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost) {} virtual void updateEnergiesAfterDamage(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost) {} /// set the material to steady state (to be implemented for materials that /// need it) virtual void setToSteadyState(__attribute__((unused)) ElementType el_type, __attribute__((unused)) GhostType ghost_type = _not_ghost) {} /// function called to update the internal parameters when the modifiable /// parameters are modified virtual void updateInternalParameters() {} public: /// extrapolate internal values virtual void extrapolateInternal(const ID & id, const Element & element, const Matrix & points, Matrix & extrapolated); /// compute the p-wave speed in the material virtual Real getPushWaveSpeed(__attribute__((unused)) const Element & element) const { AKANTU_DEBUG_TO_IMPLEMENT(); } /// compute the s-wave speed in the material virtual Real getShearWaveSpeed(__attribute__((unused)) const Element & element) const { AKANTU_DEBUG_TO_IMPLEMENT(); } /// get a material celerity to compute the stable time step (default: is the /// push wave speed) virtual Real getCelerity(const Element & element) const { return getPushWaveSpeed(element); } /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: template void registerInternal(__attribute__((unused)) InternalField & vect) { AKANTU_DEBUG_TO_IMPLEMENT(); } template void unregisterInternal(__attribute__((unused)) InternalField & vect) { AKANTU_DEBUG_TO_IMPLEMENT(); } /// initialize the material computed parameter virtual void initMaterial(); /// compute the residual for this material // virtual void updateResidual(GhostType ghost_type = _not_ghost); /// assemble the residual for this material virtual void assembleInternalForces(GhostType ghost_type); /// save the stress in the previous_stress if needed virtual void savePreviousState(); /// compute the stresses for this material virtual void computeAllStresses(GhostType ghost_type = _not_ghost); virtual void computeAllStressesFromTangentModuli(GhostType ghost_type = _not_ghost); virtual void computeAllCauchyStresses(GhostType ghost_type = _not_ghost); /// set material to steady state void setToSteadyState(GhostType ghost_type = _not_ghost); /// compute the stiffness matrix virtual void assembleStiffnessMatrix(GhostType ghost_type); /// add an element to the local mesh filter inline UInt addElement(const ElementType & type, UInt element, const GhostType & ghost_type); + inline UInt addElement(const Element & element); /// add many elements at once void addElements(const Array & elements_to_add); /// remove many element at once void removeElements(const Array & elements_to_remove); /// function to print the contain of the class virtual void printself(std::ostream & stream, int indent = 0) const; /** * interpolate stress on given positions for each element by means * of a geometrical interpolation on quadrature points */ void interpolateStress(ElementTypeMapArray & result, const GhostType ghost_type = _not_ghost); /** * interpolate stress on given positions for each element by means * of a geometrical interpolation on quadrature points and store the * results per facet */ void interpolateStressOnFacets(ElementTypeMapArray & result, ElementTypeMapArray & by_elem_result, const GhostType ghost_type = _not_ghost); /** * function to initialize the elemental field interpolation * function by inverting the quadrature points' coordinates */ void initElementalFieldInterpolation( const ElementTypeMapArray & interpolation_points_coordinates); /* ------------------------------------------------------------------------ */ /* Common part */ /* ------------------------------------------------------------------------ */ protected: /* ------------------------------------------------------------------------ */ inline UInt getTangentStiffnessVoigtSize(UInt spatial_dimension) const; /// compute the potential energy by element void computePotentialEnergyByElements(); /// resize the intenals arrays virtual void resizeInternals(); /* ------------------------------------------------------------------------ */ /* Finite deformation functions */ /* This functions area implementing what is described in the paper of Bathe */ /* et al, in IJNME, Finite Element Formulations For Large Deformation */ /* Dynamic Analysis, Vol 9, 353-386, 1975 */ /* ------------------------------------------------------------------------ */ protected: /// assemble the residual template void assembleInternalForces(GhostType ghost_type); /// Computation of Cauchy stress tensor in the case of finite deformation from /// the 2nd Piola-Kirchhoff for a given element type template void computeCauchyStress(ElementType el_type, GhostType ghost_type = _not_ghost); /// Computation the Cauchy stress the 2nd Piola-Kirchhoff and the deformation /// gradient template inline void computeCauchyStressOnQuad(const Matrix & F, const Matrix & S, Matrix & cauchy, const Real & C33 = 1.0) const; template void computeAllStressesFromTangentModuli(const ElementType & type, GhostType ghost_type); template void assembleStiffnessMatrix(const ElementType & type, GhostType ghost_type); /// assembling in finite deformation template void assembleStiffnessMatrixNL(const ElementType & type, GhostType ghost_type); template void assembleStiffnessMatrixL2(const ElementType & type, GhostType ghost_type); /// Size of the Stress matrix for the case of finite deformation see: Bathe et /// al, IJNME, Vol 9, 353-386, 1975 inline UInt getCauchyStressMatrixSize(UInt spatial_dimension) const; /// Sets the stress matrix according to Bathe et al, IJNME, Vol 9, 353-386, /// 1975 template inline void setCauchyStressMatrix(const Matrix & S_t, Matrix & sigma); /// write the stress tensor in the Voigt notation. template inline void setCauchyStressArray(const Matrix & S_t, Matrix & sigma_voight); /* ------------------------------------------------------------------------ */ /* Conversion functions */ /* ------------------------------------------------------------------------ */ public: template static inline void gradUToF(const Matrix & grad_u, Matrix & F); static inline void rightCauchy(const Matrix & F, Matrix & C); static inline void leftCauchy(const Matrix & F, Matrix & B); template static inline void gradUToEpsilon(const Matrix & grad_u, Matrix & epsilon); template static inline void gradUToGreenStrain(const Matrix & grad_u, Matrix & epsilon); static inline Real stressToVonMises(const Matrix & stress); protected: /// converts global element to local element inline Element convertToLocalElement(const Element & global_element) const; /// converts local element to global element inline Element convertToGlobalElement(const Element & local_element) const; /// converts global quadrature point to local quadrature point inline IntegrationPoint convertToLocalPoint(const IntegrationPoint & global_point) const; /// converts local quadrature point to global quadrature point inline IntegrationPoint convertToGlobalPoint(const IntegrationPoint & local_point) const; /* ------------------------------------------------------------------------ */ /* DataAccessor inherited members */ /* ------------------------------------------------------------------------ */ public: virtual inline UInt getNbData(const Array & elements, const SynchronizationTag & tag) const; virtual inline void packData(CommunicationBuffer & buffer, const Array & elements, const SynchronizationTag & tag) const; virtual inline void unpackData(CommunicationBuffer & buffer, const Array & elements, const SynchronizationTag & tag); template inline void packElementDataHelper(const ElementTypeMapArray & data_to_pack, CommunicationBuffer & buffer, const Array & elements, const ID & fem_id = ID()) const; template inline void unpackElementDataHelper(ElementTypeMapArray & data_to_unpack, CommunicationBuffer & buffer, const Array & elements, const ID & fem_id = ID()); /* ------------------------------------------------------------------------ */ /* MeshEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: /* ------------------------------------------------------------------------ */ virtual void onNodesAdded(const Array &, const NewNodesEvent &){}; virtual void onNodesRemoved(const Array &, const Array &, const RemovedNodesEvent &){}; virtual void onElementsAdded(const Array & element_list, const NewElementsEvent & event); virtual void onElementsRemoved(const Array & element_list, const ElementTypeMapArray & new_numbering, const RemovedElementsEvent & event); virtual void onElementsChanged(const Array &, const Array &, const ElementTypeMapArray &, const ChangedElementsEvent &){}; /* ------------------------------------------------------------------------ */ /* SolidMechanicsModelEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: virtual void beforeSolveStep(); virtual void afterSolveStep(); virtual void onDamageIteration(); virtual void onDamageUpdate(); virtual void onDump(); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(Name, name, const std::string &); AKANTU_GET_MACRO(Model, model, const SolidMechanicsModel &) AKANTU_GET_MACRO(ID, Memory::getID(), const ID &); AKANTU_GET_MACRO(Rho, rho, Real); AKANTU_SET_MACRO(Rho, rho, Real); AKANTU_GET_MACRO(SpatialDimension, spatial_dimension, UInt); /// return the potential energy for the subset of elements contained by the /// material Real getPotentialEnergy(); /// return the potential energy for the provided element Real getPotentialEnergy(ElementType & type, UInt index); /// return the energy (identified by id) for the subset of elements contained /// by the material virtual Real getEnergy(std::string energy_id); /// return the energy (identified by id) for the provided element virtual Real getEnergy(std::string energy_id, ElementType type, UInt index); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(ElementFilter, element_filter, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(GradU, gradu, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Stress, stress, Real); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(PotentialEnergy, potential_energy, Real); AKANTU_GET_MACRO(GradU, gradu, const ElementTypeMapArray &); AKANTU_GET_MACRO(Stress, stress, const ElementTypeMapArray &); AKANTU_GET_MACRO(ElementFilter, element_filter, const ElementTypeMapArray &); AKANTU_GET_MACRO(FEEngine, fem, FEEngine &); bool isNonLocal() const { return is_non_local; } template const Array & getArray(const ID & id, const ElementType & type, const GhostType & ghost_type = _not_ghost) const; template Array & getArray(const ID & id, const ElementType & type, const GhostType & ghost_type = _not_ghost); template const InternalField & getInternal(const ID & id) const; template InternalField & getInternal(const ID & id); template inline bool isInternal(const ID & id, const ElementKind & element_kind) const; template ElementTypeMap getInternalDataPerElem(const ID & id, const ElementKind & element_kind) const; bool isFiniteDeformation() const { return finite_deformation; } bool isInelasticDeformation() const { return inelastic_deformation; } template inline void setParam(const ID & param, T value); inline const Parameter & getParam(const ID & param) const; template void flattenInternal(const std::string & field_id, ElementTypeMapArray & internal_flat, const GhostType ghost_type = _not_ghost, ElementKind element_kind = _ek_not_defined) const; /// apply a constant eigengrad_u everywhere in the material virtual void applyEigenGradU(const Matrix & prescribed_eigen_grad_u, const GhostType = _not_ghost); /// specify if the matrix need to be recomputed for this material virtual bool hasStiffnessMatrixChanged() { return true; } protected: bool isInit() const { return is_init; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// boolean to know if the material has been initialized bool is_init; std::map *> internal_vectors_real; std::map *> internal_vectors_uint; std::map *> internal_vectors_bool; protected: /// Link to the fem object in the model FEEngine & fem; /// Finite deformation bool finite_deformation; /// Finite deformation bool inelastic_deformation; /// material name std::string name; /// The model to witch the material belong SolidMechanicsModel & model; /// density : rho Real rho; /// spatial dimension UInt spatial_dimension; /// list of element handled by the material ElementTypeMapArray element_filter; /// stresses arrays ordered by element types InternalField stress; /// eigengrad_u arrays ordered by element types InternalField eigengradu; /// grad_u arrays ordered by element types InternalField gradu; /// Green Lagrange strain (Finite deformation) InternalField green_strain; /// Second Piola-Kirchhoff stress tensor arrays ordered by element types /// (Finite deformation) InternalField piola_kirchhoff_2; /// potential energy by element InternalField potential_energy; /// tell if using in non local mode or not bool is_non_local; /// tell if the material need the previous stress state bool use_previous_stress; /// tell if the material need the previous strain state bool use_previous_gradu; /// elemental field interpolation coordinates InternalField interpolation_inverse_coordinates; /// elemental field interpolation points InternalField interpolation_points_matrices; /// vector that contains the names of all the internals that need to /// be transferred when material interfaces move std::vector internals_to_transfer; }; /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const Material & _this) { _this.printself(stream); return stream; } } // namespace akantu #include "material_inline_impl.cc" #include "internal_field_tmpl.hh" #include "random_internal_field_tmpl.hh" /* -------------------------------------------------------------------------- */ /* Auto loop */ /* -------------------------------------------------------------------------- */ /// This can be used to automatically write the loop on quadrature points in /// functions such as computeStress. This macro in addition to write the loop /// provides two tensors (matrices) sigma and grad_u #define MATERIAL_STRESS_QUADRATURE_POINT_LOOP_BEGIN(el_type, ghost_type) \ Array::matrix_iterator gradu_it = \ this->gradu(el_type, ghost_type) \ .begin(this->spatial_dimension, this->spatial_dimension); \ Array::matrix_iterator gradu_end = \ this->gradu(el_type, ghost_type) \ .end(this->spatial_dimension, this->spatial_dimension); \ \ this->stress(el_type, ghost_type) \ .resize(this->gradu(el_type, ghost_type).size()); \ \ Array::iterator> stress_it = \ this->stress(el_type, ghost_type) \ .begin(this->spatial_dimension, this->spatial_dimension); \ \ if (this->isFiniteDeformation()) { \ this->piola_kirchhoff_2(el_type, ghost_type) \ .resize(this->gradu(el_type, ghost_type).size()); \ stress_it = this->piola_kirchhoff_2(el_type, ghost_type) \ .begin(this->spatial_dimension, this->spatial_dimension); \ } \ \ for (; gradu_it != gradu_end; ++gradu_it, ++stress_it) { \ Matrix & __attribute__((unused)) grad_u = *gradu_it; \ Matrix & __attribute__((unused)) sigma = *stress_it #define MATERIAL_STRESS_QUADRATURE_POINT_LOOP_END } /// This can be used to automatically write the loop on quadrature points in /// functions such as computeTangentModuli. This macro in addition to write the /// loop provides two tensors (matrices) sigma_tensor, grad_u, and a matrix /// where the elemental tangent moduli should be stored in Voigt Notation #define MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_BEGIN(tangent_mat) \ Array::matrix_iterator gradu_it = \ this->gradu(el_type, ghost_type) \ .begin(this->spatial_dimension, this->spatial_dimension); \ Array::matrix_iterator gradu_end = \ this->gradu(el_type, ghost_type) \ .end(this->spatial_dimension, this->spatial_dimension); \ Array::matrix_iterator sigma_it = \ this->stress(el_type, ghost_type) \ .begin(this->spatial_dimension, this->spatial_dimension); \ \ tangent_mat.resize(this->gradu(el_type, ghost_type).size()); \ \ UInt tangent_size = \ this->getTangentStiffnessVoigtSize(this->spatial_dimension); \ Array::matrix_iterator tangent_it = \ tangent_mat.begin(tangent_size, tangent_size); \ \ for (; gradu_it != gradu_end; ++gradu_it, ++sigma_it, ++tangent_it) { \ Matrix & __attribute__((unused)) grad_u = *gradu_it; \ Matrix & __attribute__((unused)) sigma_tensor = *sigma_it; \ Matrix & tangent = *tangent_it #define MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END } /* -------------------------------------------------------------------------- */ namespace akantu { using MaterialFactory = Factory; } // namespace akantu #define INSTANTIATE_MATERIAL_ONLY(mat_name) \ template class mat_name<1>; \ template class mat_name<2>; \ template class mat_name<3> #define MATERIAL_DEFAULT_PER_DIM_ALLOCATOR(id, mat_name) \ [](UInt dim, const ID &, SolidMechanicsModel & model, \ const ID & id) -> std::unique_ptr { \ switch (dim) { \ case 1: \ return std::make_unique>(model, id); \ case 2: \ return std::make_unique>(model, id); \ case 3: \ return std::make_unique>(model, id); \ default: \ AKANTU_EXCEPTION("The dimension " \ << dim << "is not a valid dimension for the material " \ << #id); \ } \ } #define INSTANTIATE_MATERIAL(id, mat_name) \ INSTANTIATE_MATERIAL_ONLY(mat_name); \ static bool material_is_alocated_##id = \ MaterialFactory::getInstance().registerAllocator( \ #id, MATERIAL_DEFAULT_PER_DIM_ALLOCATOR(id, mat_name)) #endif /* __AKANTU_MATERIAL_HH__ */ diff --git a/src/model/solid_mechanics/material_inline_impl.cc b/src/model/solid_mechanics/material_inline_impl.cc index 9bbda3334..5013aec13 100644 --- a/src/model/solid_mechanics/material_inline_impl.cc +++ b/src/model/solid_mechanics/material_inline_impl.cc @@ -1,461 +1,466 @@ /** * @file material_inline_impl.cc * * @author Daniel Pino Muñoz * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Tue Jul 27 2010 * @date last modification: Wed Nov 25 2015 * * @brief Implementation of the inline functions of the class material * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_MATERIAL_INLINE_IMPL_CC__ #define __AKANTU_MATERIAL_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline UInt Material::addElement(const ElementType & type, UInt element, const GhostType & ghost_type) { Array & el_filter = this->element_filter(type, ghost_type); el_filter.push_back(element); return el_filter.size() - 1; } +/* -------------------------------------------------------------------------- */ +inline UInt Material::addElement(const Element & element) { + return this->addElement(element.type, element.element, element.ghost_type); +} + /* -------------------------------------------------------------------------- */ inline UInt Material::getTangentStiffnessVoigtSize(UInt dim) const { return (dim * (dim - 1) / 2 + dim); } /* -------------------------------------------------------------------------- */ inline UInt Material::getCauchyStressMatrixSize(UInt dim) const { return (dim * dim); } /* -------------------------------------------------------------------------- */ template inline void Material::gradUToF(const Matrix & grad_u, Matrix & F) { AKANTU_DEBUG_ASSERT(F.size() >= grad_u.size() && grad_u.size() == dim * dim, "The dimension of the tensor F should be greater or " "equal to the dimension of the tensor grad_u."); F.eye(); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) F(i, j) += grad_u(i, j); } /* -------------------------------------------------------------------------- */ template inline void Material::computeCauchyStressOnQuad(const Matrix & F, const Matrix & piola, Matrix & sigma, const Real & C33) const { Real J = F.det() * sqrt(C33); Matrix F_S(dim, dim); F_S.mul(F, piola); Real constant = J ? 1. / J : 0; sigma.mul(F_S, F, constant); } /* -------------------------------------------------------------------------- */ inline void Material::rightCauchy(const Matrix & F, Matrix & C) { C.mul(F, F); } /* -------------------------------------------------------------------------- */ inline void Material::leftCauchy(const Matrix & F, Matrix & B) { B.mul(F, F); } /* -------------------------------------------------------------------------- */ template inline void Material::gradUToEpsilon(const Matrix & grad_u, Matrix & epsilon) { for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) epsilon(i, j) = 0.5 * (grad_u(i, j) + grad_u(j, i)); } /* -------------------------------------------------------------------------- */ template inline void Material::gradUToGreenStrain(const Matrix & grad_u, Matrix & epsilon) { epsilon.mul(grad_u, grad_u, .5); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) epsilon(i, j) += 0.5 * (grad_u(i, j) + grad_u(j, i)); } /* -------------------------------------------------------------------------- */ inline Real Material::stressToVonMises(const Matrix & stress) { // compute deviatoric stress UInt dim = stress.cols(); Matrix deviatoric_stress = Matrix::eye(dim, -1. * stress.trace() / 3.); for (UInt i = 0; i < dim; ++i) for (UInt j = 0; j < dim; ++j) deviatoric_stress(i, j) += stress(i, j); // return Von Mises stress return std::sqrt(3. * deviatoric_stress.doubleDot(deviatoric_stress) / 2.); } /* ---------------------------------------------------------------------------*/ template inline void Material::setCauchyStressArray(const Matrix & S_t, Matrix & sigma_voight) { AKANTU_DEBUG_IN(); sigma_voight.clear(); // see Finite ekement formulations for large deformation dynamic analysis, // Bathe et al. IJNME vol 9, 1975, page 364 ^t\tau /* * 1d: [ s11 ]' * 2d: [ s11 s22 s12 ]' * 3d: [ s11 s22 s33 s23 s13 s12 ] */ for (UInt i = 0; i < dim; ++i) // diagonal terms sigma_voight(i, 0) = S_t(i, i); for (UInt i = 1; i < dim; ++i) // term s12 in 2D and terms s23 s13 in 3D sigma_voight(dim + i - 1, 0) = S_t(dim - i - 1, dim - 1); for (UInt i = 2; i < dim; ++i) // term s13 in 3D sigma_voight(dim + i, 0) = S_t(0, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template inline void Material::setCauchyStressMatrix(const Matrix & S_t, Matrix & sigma) { AKANTU_DEBUG_IN(); sigma.clear(); /// see Finite ekement formulations for large deformation dynamic analysis, /// Bathe et al. IJNME vol 9, 1975, page 364 ^t\tau for (UInt i = 0; i < dim; ++i) { for (UInt m = 0; m < dim; ++m) { for (UInt n = 0; n < dim; ++n) { sigma(i * dim + m, i * dim + n) = S_t(m, n); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline Element Material::convertToLocalElement(const Element & global_element) const { UInt ge = global_element.element; #ifndef AKANTU_NDEBUG UInt model_mat_index = this->model.getMaterialByElement( global_element.type, global_element.ghost_type)(ge); UInt mat_index = this->model.getMaterialIndex(this->name); AKANTU_DEBUG_ASSERT(model_mat_index == mat_index, "Conversion of a global element in a local element for " "the wrong material " << this->name << std::endl); #endif UInt le = this->model.getMaterialLocalNumbering( global_element.type, global_element.ghost_type)(ge); Element tmp_quad(global_element.type, le, global_element.ghost_type, global_element.kind); return tmp_quad; } /* -------------------------------------------------------------------------- */ inline Element Material::convertToGlobalElement(const Element & local_element) const { UInt le = local_element.element; UInt ge = this->element_filter(local_element.type, local_element.ghost_type)(le); Element tmp_quad(local_element.type, ge, local_element.ghost_type, local_element.kind); return tmp_quad; } /* -------------------------------------------------------------------------- */ inline IntegrationPoint Material::convertToLocalPoint(const IntegrationPoint & global_point) const { const FEEngine & fem = this->model.getFEEngine(); UInt nb_quad = fem.getNbIntegrationPoints(global_point.type); Element el = this->convertToLocalElement(static_cast(global_point)); IntegrationPoint tmp_quad(el, global_point.num_point, nb_quad); return tmp_quad; } /* -------------------------------------------------------------------------- */ inline IntegrationPoint Material::convertToGlobalPoint(const IntegrationPoint & local_point) const { const FEEngine & fem = this->model.getFEEngine(); UInt nb_quad = fem.getNbIntegrationPoints(local_point.type); Element el = this->convertToGlobalElement(static_cast(local_point)); IntegrationPoint tmp_quad(el, local_point.num_point, nb_quad); return tmp_quad; } /* -------------------------------------------------------------------------- */ inline UInt Material::getNbData(const Array & elements, const SynchronizationTag & tag) const { if (tag == _gst_smm_stress) { return (this->isFiniteDeformation() ? 3 : 1) * spatial_dimension * spatial_dimension * sizeof(Real) * this->getModel().getNbIntegrationPoints(elements); } return 0; } /* -------------------------------------------------------------------------- */ inline void Material::packData(CommunicationBuffer & buffer, const Array & elements, const SynchronizationTag & tag) const { if (tag == _gst_smm_stress) { if (this->isFiniteDeformation()) { packElementDataHelper(piola_kirchhoff_2, buffer, elements); packElementDataHelper(gradu, buffer, elements); } packElementDataHelper(stress, buffer, elements); } } /* -------------------------------------------------------------------------- */ inline void Material::unpackData(CommunicationBuffer & buffer, const Array & elements, const SynchronizationTag & tag) { if (tag == _gst_smm_stress) { if (this->isFiniteDeformation()) { unpackElementDataHelper(piola_kirchhoff_2, buffer, elements); unpackElementDataHelper(gradu, buffer, elements); } unpackElementDataHelper(stress, buffer, elements); } } /* -------------------------------------------------------------------------- */ inline const Parameter & Material::getParam(const ID & param) const { try { return get(param); } catch (...) { AKANTU_EXCEPTION("No parameter " << param << " in the material " << getID()); } } /* -------------------------------------------------------------------------- */ template inline void Material::setParam(const ID & param, T value) { try { set(param, value); } catch (...) { AKANTU_EXCEPTION("No parameter " << param << " in the material " << getID()); } updateInternalParameters(); } /* -------------------------------------------------------------------------- */ template inline void Material::packElementDataHelper( const ElementTypeMapArray & data_to_pack, CommunicationBuffer & buffer, const Array & elements, const ID & fem_id) const { DataAccessor::packElementalDataHelper(data_to_pack, buffer, elements, true, model.getFEEngine(fem_id)); } /* -------------------------------------------------------------------------- */ template inline void Material::unpackElementDataHelper( ElementTypeMapArray & data_to_unpack, CommunicationBuffer & buffer, const Array & elements, const ID & fem_id) { DataAccessor::unpackElementalDataHelper(data_to_unpack, buffer, elements, true, model.getFEEngine(fem_id)); } /* -------------------------------------------------------------------------- */ template <> inline void Material::registerInternal(InternalField & vect) { internal_vectors_real[vect.getID()] = &vect; } template <> inline void Material::registerInternal(InternalField & vect) { internal_vectors_uint[vect.getID()] = &vect; } template <> inline void Material::registerInternal(InternalField & vect) { internal_vectors_bool[vect.getID()] = &vect; } /* -------------------------------------------------------------------------- */ template <> inline void Material::unregisterInternal(InternalField & vect) { internal_vectors_real.erase(vect.getID()); } template <> inline void Material::unregisterInternal(InternalField & vect) { internal_vectors_uint.erase(vect.getID()); } template <> inline void Material::unregisterInternal(InternalField & vect) { internal_vectors_bool.erase(vect.getID()); } /* -------------------------------------------------------------------------- */ template inline bool Material::isInternal(__attribute__((unused)) const ID & id, __attribute__((unused)) const ElementKind & element_kind) const { AKANTU_DEBUG_TO_IMPLEMENT(); } template <> inline bool Material::isInternal(const ID & id, const ElementKind & element_kind) const { std::map *>::const_iterator internal_array = internal_vectors_real.find(this->getID() + ":" + id); if (internal_array == internal_vectors_real.end() || internal_array->second->getElementKind() != element_kind) return false; return true; } /* -------------------------------------------------------------------------- */ template inline ElementTypeMap Material::getInternalDataPerElem(const ID & field_id, const ElementKind & element_kind) const { if (!this->template isInternal(field_id, element_kind)) AKANTU_EXCEPTION("Cannot find internal field " << id << " in material " << this->name); const InternalField & internal_field = this->template getInternal(field_id); const FEEngine & fe_engine = internal_field.getFEEngine(); UInt nb_data_per_quad = internal_field.getNbComponent(); ElementTypeMap res; for (ghost_type_t::iterator gt = ghost_type_t::begin(); gt != ghost_type_t::end(); ++gt) { typedef typename InternalField::type_iterator type_iterator; type_iterator tit = internal_field.firstType(*gt); type_iterator tend = internal_field.lastType(*gt); for (; tit != tend; ++tit) { UInt nb_quadrature_points = fe_engine.getNbIntegrationPoints(*tit, *gt); res(*tit, *gt) = nb_data_per_quad * nb_quadrature_points; } } return res; } /* -------------------------------------------------------------------------- */ template void Material::flattenInternal(const std::string & field_id, ElementTypeMapArray & internal_flat, const GhostType ghost_type, ElementKind element_kind) const { if (!this->template isInternal(field_id, element_kind)) AKANTU_EXCEPTION("Cannot find internal field " << id << " in material " << this->name); const InternalField & internal_field = this->template getInternal(field_id); const FEEngine & fe_engine = internal_field.getFEEngine(); const Mesh & mesh = fe_engine.getMesh(); typedef typename InternalField::filter_type_iterator type_iterator; type_iterator tit = internal_field.filterFirstType(ghost_type); type_iterator tend = internal_field.filterLastType(ghost_type); for (; tit != tend; ++tit) { ElementType type = *tit; const Array & src_vect = internal_field(type, ghost_type); const Array & filter = internal_field.getFilter(type, ghost_type); // total number of elements in the corresponding mesh UInt nb_element_dst = mesh.getNbElement(type, ghost_type); // number of element in the internal field UInt nb_element_src = filter.size(); // number of quadrature points per elem UInt nb_quad_per_elem = fe_engine.getNbIntegrationPoints(type); // number of data per quadrature point UInt nb_data_per_quad = internal_field.getNbComponent(); if (!internal_flat.exists(type, ghost_type)) { internal_flat.alloc(nb_element_dst * nb_quad_per_elem, nb_data_per_quad, type, ghost_type); } if (nb_element_src == 0) continue; // number of data per element UInt nb_data = nb_quad_per_elem * nb_data_per_quad; Array & dst_vect = internal_flat(type, ghost_type); dst_vect.resize(nb_element_dst * nb_quad_per_elem); Array::const_scalar_iterator it = filter.begin(); Array::const_scalar_iterator end = filter.end(); Array::const_vector_iterator it_src = src_vect.begin_reinterpret(nb_data, nb_element_src); Array::vector_iterator it_dst = dst_vect.begin_reinterpret(nb_data, nb_element_dst); for (; it != end; ++it, ++it_src) { it_dst[*it] = *it_src; } } } } // akantu #endif /* __AKANTU_MATERIAL_INLINE_IMPL_CC__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model.cc b/src/model/solid_mechanics/solid_mechanics_model.cc index 80820a83b..a405ad107 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.cc +++ b/src/model/solid_mechanics/solid_mechanics_model.cc @@ -1,965 +1,1266 @@ /** * @file solid_mechanics_model.cc * * @author Ramin Aghababaei * @author Guillaume Anciaux * @author Aurelia Isabel Cuba Ramos * @author David Simon Kammer * @author Daniel Pino Muñoz * @author Nicolas Richart * @author Clement Roux * @author Marco Vocialta * * @date creation: Tue Jul 27 2010 * @date last modification: Tue Jan 19 2016 * * @brief Implementation of the SolidMechanicsModel class * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model.hh" #include "integrator_gauss.hh" #include "shape_lagrange.hh" #include "element_synchronizer.hh" #include "sparse_matrix.hh" #include "static_communicator.hh" #include "synchronizer_registry.hh" #include "dumpable_inline_impl.hh" #ifdef AKANTU_USE_IOHELPER #include "dumper_paraview.hh" #endif #include "material_non_local.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ /** * A solid mechanics model need a mesh and a dimension to be created. the model * by it self can not do a lot, the good init functions should be called in * order to configure the model depending on what we want to do. * * @param mesh mesh representing the model we want to simulate * @param dim spatial dimension of the problem, if dim = 0 (default value) the * dimension of the problem is assumed to be the on of the mesh * @param id an id to identify the model */ SolidMechanicsModel::SolidMechanicsModel(Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) : Model(mesh, dim, id, memory_id), BoundaryCondition(), f_m2a(1.0), displacement(nullptr), previous_displacement(nullptr), displacement_increment(nullptr), mass(nullptr), velocity(nullptr), acceleration(nullptr), external_force(nullptr), internal_force(nullptr), blocked_dofs(nullptr), current_position(nullptr), material_index("material index", id, memory_id), material_local_numbering("material local numbering", id, memory_id), material_selector(new DefaultMaterialSelector(material_index)), is_default_material_selector(true), increment_flag(false), are_materials_instantiated(false) { //, pbc_synch(nullptr) { AKANTU_DEBUG_IN(); this->registerFEEngineObject("SolidMechanicsFEEngine", mesh, Model::spatial_dimension); #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper("paraview_all", id, true); this->mesh.addDumpMesh(mesh, Model::spatial_dimension, _not_ghost, _ek_regular); #endif this->initDOFManager(); this->registerDataAccessor(*this); if (this->mesh.isDistributed()) { auto & synchronizer = this->mesh.getElementSynchronizer(); this->registerSynchronizer(synchronizer, _gst_material_id); this->registerSynchronizer(synchronizer, _gst_smm_mass); this->registerSynchronizer(synchronizer, _gst_smm_stress); this->registerSynchronizer(synchronizer, _gst_smm_boundary); this->registerSynchronizer(synchronizer, _gst_for_dump); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SolidMechanicsModel::~SolidMechanicsModel() { AKANTU_DEBUG_IN(); if (is_default_material_selector) { delete material_selector; material_selector = nullptr; } for (auto & internal : this->registered_internals) { delete internal.second; } // delete pbc_synch; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::setTimeStep(Real time_step, const ID & solver_id) { Model::setTimeStep(time_step, solver_id); #if defined(AKANTU_USE_IOHELPER) this->mesh.getDumper().setTimeStep(time_step); #endif } /* -------------------------------------------------------------------------- */ /* Initialization */ /* -------------------------------------------------------------------------- */ /** * This function groups many of the initialization in on function. For most of * basics case the function should be enough. The functions initialize the * model, the internal vectors, set them to 0, and depending on the parameters * it also initialize the explicit or implicit solver. * * @param material_file the file containing the materials to use * @param method the analysis method wanted. See the akantu::AnalysisMethod for * the different possibilities */ void SolidMechanicsModel::initFull(const ModelOptions & options) { Model::initFull(options); const SolidMechanicsModelOptions & smm_options = dynamic_cast(options); - this->method = smm_options.analysis_method; - - // initialize the vectors - for (auto ghost_type : ghost_types) { - for (auto type : mesh.elementTypes(Model::spatial_dimension, ghost_type, - _ek_not_defined)) { - UInt nb_element = mesh.getNbElement(type, ghost_type); - this->material_index.alloc(nb_element, 1, type, ghost_type); - this->material_local_numbering.alloc(nb_element, 1, type, ghost_type); - } - } + method = smm_options.analysis_method; + + material_index.initialize(mesh, _element_kind = _ek_not_defined, + _default_value = UInt(-1), _with_nb_element = true); + material_local_numbering.initialize(mesh, _element_kind = _ek_not_defined, + _with_nb_element = true); if (!this->hasDefaultSolver()) this->initNewSolver(this->method); // initialize pbc if (this->pbc_pair.size() != 0) this->initPBC(); // initialize the materials if (this->parser->getLastParsedFile() != "") { this->instantiateMaterials(); } this->initMaterials(); this->initBC(*this, *displacement, *displacement_increment, *external_force); } /* -------------------------------------------------------------------------- */ TimeStepSolverType SolidMechanicsModel::getDefaultSolverType() const { return _tsst_dynamic_lumped; } /* -------------------------------------------------------------------------- */ ModelSolverOptions SolidMechanicsModel::getDefaultSolverOptions( const TimeStepSolverType & type) const { ModelSolverOptions options; switch (type) { case _tsst_dynamic_lumped: { options.non_linear_solver_type = _nls_lumped; options.integration_scheme_type["displacement"] = _ist_central_difference; options.solution_type["displacement"] = IntegrationScheme::_acceleration; break; } case _tsst_static: { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["displacement"] = _ist_pseudo_time; options.solution_type["displacement"] = IntegrationScheme::_not_defined; break; } case _tsst_dynamic: { if (this->method == _explicit_consistent_mass) { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["displacement"] = _ist_central_difference; options.solution_type["displacement"] = IntegrationScheme::_acceleration; } else { options.non_linear_solver_type = _nls_newton_raphson; options.integration_scheme_type["displacement"] = _ist_trapezoidal_rule_2; options.solution_type["displacement"] = IntegrationScheme::_displacement; } break; } } return options; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initNewSolver(const AnalysisMethod & method) { ID solver_name; TimeStepSolverType tss_type; this->method = method; switch (this->method) { case _explicit_lumped_mass: { solver_name = "explicit_lumped"; tss_type = _tsst_dynamic_lumped; break; } case _explicit_consistent_mass: { solver_name = "explicit"; tss_type = _tsst_dynamic; break; } case _static: { solver_name = "static"; tss_type = _tsst_static; break; } case _implicit_dynamic: { solver_name = "implicit"; tss_type = _tsst_dynamic; break; } } if (!this->hasSolver(solver_name)) { ModelSolverOptions options = this->getDefaultSolverOptions(tss_type); this->getNewSolver(solver_name, tss_type, options.non_linear_solver_type); this->setIntegrationScheme(solver_name, "displacement", options.integration_scheme_type["displacement"], options.solution_type["displacement"]); this->setDefaultSolver(solver_name); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initSolver(TimeStepSolverType time_step_solver_type, NonLinearSolverType) { DOFManager & dof_manager = this->getDOFManager(); /* ------------------------------------------------------------------------ */ // for alloc type of solvers this->allocNodalField(this->displacement, spatial_dimension, "displacement"); this->allocNodalField(this->previous_displacement, spatial_dimension, "previous_displacement"); this->allocNodalField(this->displacement_increment, spatial_dimension, "displacement_increment"); this->allocNodalField(this->internal_force, spatial_dimension, "internal_force"); this->allocNodalField(this->external_force, spatial_dimension, "external_force"); this->allocNodalField(this->blocked_dofs, spatial_dimension, "blocked_dofs"); this->allocNodalField(this->current_position, spatial_dimension, "current_position"); // initialize the current positions this->current_position->copy(this->mesh.getNodes()); /* ------------------------------------------------------------------------ */ if (!dof_manager.hasDOFs("displacement")) { dof_manager.registerDOFs("displacement", *this->displacement, _dst_nodal); dof_manager.registerBlockedDOFs("displacement", *this->blocked_dofs); dof_manager.registerDOFsIncrement("displacement", *this->displacement_increment); dof_manager.registerDOFsPrevious("displacement", *this->previous_displacement); } /* ------------------------------------------------------------------------ */ // for dynamic if (time_step_solver_type == _tsst_dynamic || time_step_solver_type == _tsst_dynamic_lumped) { this->allocNodalField(this->velocity, spatial_dimension, "velocity"); this->allocNodalField(this->acceleration, spatial_dimension, "acceleration"); if (!dof_manager.hasDOFsDerivatives("displacement", 1)) { dof_manager.registerDOFsDerivative("displacement", 1, *this->velocity); dof_manager.registerDOFsDerivative("displacement", 2, *this->acceleration); } } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initFEEngineBoundary() { FEEngine & fem_boundary = getFEEngineBoundary(); fem_boundary.initShapeFunctions(_not_ghost); fem_boundary.initShapeFunctions(_ghost); fem_boundary.computeNormalsOnIntegrationPoints(_not_ghost); fem_boundary.computeNormalsOnIntegrationPoints(_ghost); } /* -------------------------------------------------------------------------- */ /** * Initialize the model,basically it pre-compute the shapes, shapes derivatives * and jacobian */ void SolidMechanicsModel::initModel() { /// \todo add the current position as a parameter to initShapeFunctions for /// large deformation getFEEngine().initShapeFunctions(_not_ghost); getFEEngine().initShapeFunctions(_ghost); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleResidual() { AKANTU_DEBUG_IN(); /* ------------------------------------------------------------------------ */ // computes the internal forces this->assembleInternalForces(); /* ------------------------------------------------------------------------ */ this->getDOFManager().assembleToResidual("displacement", *this->external_force, 1); this->getDOFManager().assembleToResidual("displacement", *this->internal_force, 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ MatrixType SolidMechanicsModel::getMatrixType(const ID & matrix_id) { // \TODO check the materials to know what is the correct answer if (matrix_id == "C") return _mt_not_defined; return _symmetric; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleMatrix(const ID & matrix_id) { if (matrix_id == "K") { this->assembleStiffnessMatrix(); } else if (matrix_id == "M") { this->assembleMass(); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleLumpedMatrix(const ID & matrix_id) { if (matrix_id == "M") { this->assembleMassLumped(); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::beforeSolveStep() { for (auto & material : materials) material->beforeSolveStep(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::afterSolveStep() { for (auto & material : materials) material->afterSolveStep(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::predictor() { ++displacement_release; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::corrector() { ++displacement_release; } /* -------------------------------------------------------------------------- */ /** * This function computes the internal forces as F_{int} = \int_{\Omega} N * \sigma d\Omega@f$ */ void SolidMechanicsModel::assembleInternalForces() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the internal forces"); this->internal_force->clear(); // compute the stresses of local elements AKANTU_DEBUG_INFO("Compute local stresses"); for (auto & material : materials) { material->computeAllStresses(_not_ghost); } /* ------------------------------------------------------------------------ */ /* Computation of the non local part */ if (this->non_local_manager) this->non_local_manager->computeAllNonLocalStresses(); // communicate the stresses AKANTU_DEBUG_INFO("Send data for residual assembly"); this->asynchronousSynchronize(_gst_smm_stress); // assemble the forces due to local stresses AKANTU_DEBUG_INFO("Assemble residual for local elements"); for (auto & material : materials) { material->assembleInternalForces(_not_ghost); } // finalize communications AKANTU_DEBUG_INFO("Wait distant stresses"); this->waitEndSynchronize(_gst_smm_stress); // assemble the stresses due to ghost elements AKANTU_DEBUG_INFO("Assemble residual for ghost elements"); for (auto & material : materials) { material->assembleInternalForces(_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assembleStiffnessMatrix() { AKANTU_DEBUG_IN(); AKANTU_DEBUG_INFO("Assemble the new stiffness matrix."); // Check if materials need to recompute the matrix bool need_to_reassemble = false; for (auto & material : materials) { need_to_reassemble |= material->hasStiffnessMatrixChanged(); } if (need_to_reassemble) { this->getDOFManager().getMatrix("K").clear(); // call compute stiffness matrix on each local elements for (auto & material : materials) { material->assembleStiffnessMatrix(_not_ghost); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateCurrentPosition() { if (this->current_position_release == this->displacement_release) return; this->current_position->copy(this->mesh.getNodes()); auto cpos_it = this->current_position->begin(Model::spatial_dimension); auto cpos_end = this->current_position->end(Model::spatial_dimension); auto disp_it = this->displacement->begin(Model::spatial_dimension); for (; cpos_it != cpos_end; ++cpos_it, ++disp_it) { *cpos_it += *disp_it; } this->current_position_release = this->displacement_release; } /* -------------------------------------------------------------------------- */ const Array & SolidMechanicsModel::getCurrentPosition() { this->updateCurrentPosition(); return *this->current_position; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateDataForNonLocalCriterion( ElementTypeMapReal & criterion) { const ID field_name = criterion.getName(); for (auto & material : materials) { if (!material->isInternal(field_name, _ek_regular)) continue; for (auto ghost_type : ghost_types) { material->flattenInternal(field_name, criterion, ghost_type, _ek_regular); } } } /* -------------------------------------------------------------------------- */ /* Information */ /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep() { AKANTU_DEBUG_IN(); Real min_dt = getStableTimeStep(_not_ghost); /// reduction min over all processors StaticCommunicator::getStaticCommunicator().allReduce(min_dt, _so_min); AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getStableTimeStep(const GhostType & ghost_type) { AKANTU_DEBUG_IN(); Real min_dt = std::numeric_limits::max(); this->updateCurrentPosition(); Element elem; elem.ghost_type = ghost_type; elem.kind = _ek_regular; for (auto type : mesh.elementTypes(Model::spatial_dimension, ghost_type, _ek_regular)) { elem.type = type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); UInt nb_element = mesh.getNbElement(type); auto mat_indexes = material_index(type, ghost_type).begin(); auto mat_loc_num = material_local_numbering(type, ghost_type).begin(); Array X(0, nb_nodes_per_element * Model::spatial_dimension); FEEngine::extractNodalToElementField(mesh, *current_position, X, type, _not_ghost); auto X_el = X.begin(Model::spatial_dimension, nb_nodes_per_element); for (UInt el = 0; el < nb_element; ++el, ++X_el, ++mat_indexes, ++mat_loc_num) { elem.element = *mat_loc_num; Real el_h = getFEEngine().getElementInradius(*X_el, type); Real el_c = this->materials[*mat_indexes]->getCelerity(elem); Real el_dt = el_h / el_c; min_dt = std::min(min_dt, el_dt); } } AKANTU_DEBUG_OUT(); return min_dt; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getKineticEnergy() { AKANTU_DEBUG_IN(); Real ekin = 0.; UInt nb_nodes = mesh.getNbNodes(); if (this->getDOFManager().hasLumpedMatrix("M")) { auto m_it = this->mass->begin(Model::spatial_dimension); auto m_end = this->mass->end(Model::spatial_dimension); auto v_it = this->velocity->begin(Model::spatial_dimension); for (UInt n = 0; m_it != m_end; ++n, ++m_it, ++v_it) { const Vector & v = *v_it; const Vector & m = *m_it; Real mv2 = 0; bool is_local_node = mesh.isLocalOrMasterNode(n); // bool is_not_pbc_slave_node = !isPBCSlaveNode(n); bool count_node = is_local_node; // && is_not_pbc_slave_node; if (count_node) { for (UInt i = 0; i < Model::spatial_dimension; ++i) { if (m(i) > std::numeric_limits::epsilon()) mv2 += v(i) * v(i) * m(i); } } ekin += mv2; } } else if (this->getDOFManager().hasMatrix("M")) { Array Mv(nb_nodes, Model::spatial_dimension); this->getDOFManager().getMatrix("M").matVecMul(*this->velocity, Mv); auto mv_it = Mv.begin(Model::spatial_dimension); auto mv_end = Mv.end(Model::spatial_dimension); auto v_it = this->velocity->begin(Model::spatial_dimension); for (; mv_it != mv_end; ++mv_it, ++v_it) { ekin += v_it->dot(*mv_it); } } else { AKANTU_DEBUG_ERROR("No function called to assemble the mass matrix."); } StaticCommunicator::getStaticCommunicator().allReduce(ekin, _so_sum); AKANTU_DEBUG_OUT(); return ekin * .5; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getKineticEnergy(const ElementType & type, UInt index) { AKANTU_DEBUG_IN(); UInt nb_quadrature_points = getFEEngine().getNbIntegrationPoints(type); Array vel_on_quad(nb_quadrature_points, Model::spatial_dimension); Array filter_element(1, 1, index); getFEEngine().interpolateOnIntegrationPoints(*velocity, vel_on_quad, Model::spatial_dimension, type, _not_ghost, filter_element); Array::vector_iterator vit = vel_on_quad.begin(Model::spatial_dimension); Array::vector_iterator vend = vel_on_quad.end(Model::spatial_dimension); Vector rho_v2(nb_quadrature_points); Real rho = materials[material_index(type)(index)]->getRho(); for (UInt q = 0; vit != vend; ++vit, ++q) { rho_v2(q) = rho * vit->dot(*vit); } AKANTU_DEBUG_OUT(); return .5 * getFEEngine().integrate(rho_v2, type, index); } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getExternalWork() { AKANTU_DEBUG_IN(); auto incr_or_velo_it = this->velocity->begin(Model::spatial_dimension); if (this->method == _static) { incr_or_velo_it = this->displacement_increment->begin(Model::spatial_dimension); } auto ext_force_it = external_force->begin(Model::spatial_dimension); auto int_force_it = internal_force->begin(Model::spatial_dimension); auto boun_it = blocked_dofs->begin(Model::spatial_dimension); Real work = 0.; UInt nb_nodes = this->mesh.getNbNodes(); for (UInt n = 0; n < nb_nodes; ++n, ++ext_force_it, ++int_force_it, ++boun_it, ++incr_or_velo_it) { const auto & int_force = *int_force_it; const auto & ext_force = *ext_force_it; const auto & boun = *boun_it; const auto & incr_or_velo = *incr_or_velo_it; bool is_local_node = this->mesh.isLocalOrMasterNode(n); // bool is_not_pbc_slave_node = !this->isPBCSlaveNode(n); bool count_node = is_local_node; // && is_not_pbc_slave_node; if (count_node) { for (UInt i = 0; i < Model::spatial_dimension; ++i) { if (boun(i)) work -= int_force(i) * incr_or_velo(i); else work += ext_force(i) * incr_or_velo(i); } } } StaticCommunicator::getStaticCommunicator().allReduce(work, _so_sum); if (this->method != _static) work *= this->getTimeStep(); AKANTU_DEBUG_OUT(); return work; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getEnergy(const std::string & energy_id) { AKANTU_DEBUG_IN(); if (energy_id == "kinetic") { return getKineticEnergy(); } else if (energy_id == "external work") { return getExternalWork(); } Real energy = 0.; for (auto & material : materials) energy += material->getEnergy(energy_id); /// reduction sum over all processors StaticCommunicator::getStaticCommunicator().allReduce(energy, _so_sum); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ Real SolidMechanicsModel::getEnergy(const std::string & energy_id, const ElementType & type, UInt index) { AKANTU_DEBUG_IN(); if (energy_id == "kinetic") { return getKineticEnergy(type, index); } UInt mat_index = this->material_index(type, _not_ghost)(index); UInt mat_loc_num = this->material_local_numbering(type, _not_ghost)(index); Real energy = this->materials[mat_index]->getEnergy(energy_id, type, mat_loc_num); AKANTU_DEBUG_OUT(); return energy; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onElementsAdded(const Array & element_list, const NewElementsEvent & event) { AKANTU_DEBUG_IN(); - for (auto ghost_type : ghost_types) { - for (auto type : mesh.elementTypes(Model::spatial_dimension, ghost_type, - _ek_not_defined)) { + for(auto && ghost_type : ghost_types) { + for (auto type : + mesh.elementTypes(spatial_dimension, ghost_type, _ek_not_defined)) { UInt nb_element = this->mesh.getNbElement(type, ghost_type); if (!material_index.exists(type, ghost_type)) { this->material_index.alloc(nb_element, 1, type, ghost_type); - this->material_local_numbering.alloc(nb_element, 1, type, ghost_type); + this->material_local_numbering.alloc(nb_element, 1, type, ghost_type, + UInt(-1)); } else { this->material_index(type, ghost_type).resize(nb_element); - this->material_local_numbering(type, ghost_type).resize(nb_element); + this->material_local_numbering(type, ghost_type) + .resize(nb_element, UInt(-1)); } } } ElementTypeMapArray filter("new_element_filter", this->getID(), this->getMemoryID()); for (auto & elem : element_list) { if (!filter.exists(elem.type, elem.ghost_type)) filter.alloc(0, 1, elem.type, elem.ghost_type); filter(elem.type, elem.ghost_type).push_back(elem.element); } this->assignMaterialToElements(&filter); for (auto & material : materials) material->onElementsAdded(element_list, event); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onElementsRemoved( - __attribute__((unused)) const Array & element_list, + const Array & element_list, const ElementTypeMapArray & new_numbering, const RemovedElementsEvent & event) { - this->getFEEngine().initShapeFunctions(_not_ghost); - this->getFEEngine().initShapeFunctions(_ghost); + //this->getFEEngine().initShapeFunctions(_not_ghost); + //this->getFEEngine().initShapeFunctions(_ghost); for (auto & material : materials) { material->onElementsRemoved(element_list, new_numbering, event); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onNodesAdded(const Array & nodes_list, - __attribute__((unused)) const NewNodesEvent & event) { AKANTU_DEBUG_IN(); UInt nb_nodes = mesh.getNbNodes(); if (displacement) { displacement->resize(nb_nodes, 0.); ++displacement_release; } if (mass) mass->resize(nb_nodes, 0.); if (velocity) velocity->resize(nb_nodes, 0.); if (acceleration) acceleration->resize(nb_nodes, 0.); if (external_force) external_force->resize(nb_nodes, 0.); if (internal_force) internal_force->resize(nb_nodes, 0.); if (blocked_dofs) blocked_dofs->resize(nb_nodes, 0.); if (current_position) current_position->resize(nb_nodes, 0.); if (previous_displacement) previous_displacement->resize(nb_nodes, 0.); if (displacement_increment) displacement_increment->resize(nb_nodes, 0.); for (auto & material : materials) { material->onNodesAdded(nodes_list, event); } need_to_reassemble_lumped_mass = true; need_to_reassemble_mass = true; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::onNodesRemoved(__attribute__((unused)) const Array & element_list, const Array & new_numbering, __attribute__((unused)) const RemovedNodesEvent & event) { if (displacement) { mesh.removeNodesFromArray(*displacement, new_numbering); ++displacement_release; } if (mass) mesh.removeNodesFromArray(*mass, new_numbering); if (velocity) mesh.removeNodesFromArray(*velocity, new_numbering); if (acceleration) mesh.removeNodesFromArray(*acceleration, new_numbering); if (internal_force) mesh.removeNodesFromArray(*internal_force, new_numbering); if (external_force) mesh.removeNodesFromArray(*external_force, new_numbering); if (blocked_dofs) mesh.removeNodesFromArray(*blocked_dofs, new_numbering); // if (increment_acceleration) // mesh.removeNodesFromArray(*increment_acceleration, new_numbering); if (displacement_increment) mesh.removeNodesFromArray(*displacement_increment, new_numbering); if (previous_displacement) mesh.removeNodesFromArray(*previous_displacement, new_numbering); // if (method != _explicit_lumped_mass) { // this->initSolver(); // } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "Solid Mechanics Model [" << std::endl; stream << space << " + id : " << id << std::endl; stream << space << " + spatial dimension : " << Model::spatial_dimension << std::endl; stream << space << " + fem [" << std::endl; getFEEngine().printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + nodals information [" << std::endl; displacement->printself(stream, indent + 2); mass->printself(stream, indent + 2); velocity->printself(stream, indent + 2); acceleration->printself(stream, indent + 2); external_force->printself(stream, indent + 2); internal_force->printself(stream, indent + 2); blocked_dofs->printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + material information [" << std::endl; material_index.printself(stream, indent + 2); stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << " + materials [" << std::endl; for (auto & material : materials) { material->printself(stream, indent + 1); } stream << space << AKANTU_INDENT << "]" << std::endl; stream << space << "]" << std::endl; } +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModel::initializeNonLocal() { + this->non_local_manager->synchronize(*this, _gst_material_id); +} + /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::insertIntegrationPointsInNeighborhoods( const GhostType & ghost_type) { for (auto & mat : materials) { MaterialNonLocalInterface * mat_non_local; if ((mat_non_local = dynamic_cast(mat.get())) == nullptr) continue; ElementTypeMapArray quadrature_points_coordinates( "quadrature_points_coordinates_tmp_nl", this->id, this->memory_id); quadrature_points_coordinates.initialize(this->getFEEngine(), _nb_component = spatial_dimension, _ghost_type = ghost_type); for (auto & type : quadrature_points_coordinates.elementTypes( Model::spatial_dimension, ghost_type)) { this->getFEEngine().computeIntegrationPointsCoordinates( quadrature_points_coordinates(type, ghost_type), type, ghost_type); } mat_non_local->initMaterialNonLocal(); mat_non_local->insertIntegrationPointsInNeighborhoods( ghost_type, quadrature_points_coordinates); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::computeNonLocalStresses( const GhostType & ghost_type) { for (auto & mat : materials) { try { auto & mat_non_local = dynamic_cast(*mat); mat_non_local.computeNonLocalStresses(ghost_type); } catch (std::bad_cast &) { } } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateLocalInternal( ElementTypeMapReal & internal_flat, const GhostType & ghost_type, const ElementKind & kind) { const ID field_name = internal_flat.getName(); for (auto & material : materials) { if (material->isInternal(field_name, kind)) material->flattenInternal(field_name, internal_flat, ghost_type, kind); } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::updateNonLocalInternal( ElementTypeMapReal & internal_flat, const GhostType & ghost_type, const ElementKind & kind) { const ID field_name = internal_flat.getName(); for (auto & mat : materials) { try { auto & mat_non_local = dynamic_cast(*mat); mat_non_local.updateNonLocalInternals(internal_flat, field_name, ghost_type, kind); } catch (std::bad_cast &) { } } } /* -------------------------------------------------------------------------- */ FEEngine & SolidMechanicsModel::getFEEngineBoundary(const ID & name) { return dynamic_cast( getFEEngineClassBoundary(name)); } +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModel::splitElementByMaterial( + const Array & elements, Array * elements_per_mat) const { + ElementType current_element_type = _not_defined; + GhostType current_ghost_type = _casper; + const Array * mat_indexes = NULL; + const Array * mat_loc_num = 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; + mat_indexes = &(this->material_index(el.type, el.ghost_type)); + mat_loc_num = &(this->material_local_numbering(el.type, el.ghost_type)); + } + + UInt old_id = el.element; + el.element = (*mat_loc_num)(old_id); + elements_per_mat[(*mat_indexes)(old_id)].push_back(el); + } +} + +/* -------------------------------------------------------------------------- */ +UInt SolidMechanicsModel::getNbData(const Array & elements, + const SynchronizationTag & tag) const { + AKANTU_DEBUG_IN(); + + UInt size = 0; + UInt nb_nodes_per_element = 0; + + for (const Element & el : elements) { + nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type); + } + + switch (tag) { + case _gst_material_id: { + size += elements.size() * sizeof(UInt); + break; + } + case _gst_smm_mass: { + size += nb_nodes_per_element * sizeof(Real) * + Model::spatial_dimension; // mass vector + break; + } + case _gst_smm_for_gradu: { + size += nb_nodes_per_element * Model::spatial_dimension * + sizeof(Real); // displacement + break; + } + case _gst_smm_boundary: { + // force, displacement, boundary + size += nb_nodes_per_element * Model::spatial_dimension * + (2 * sizeof(Real) + sizeof(bool)); + break; + } + case _gst_for_dump: { + // displacement, velocity, acceleration, residual, force + size += nb_nodes_per_element * Model::spatial_dimension * sizeof(Real) * 5; + 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]->getNbData(elements_per_mat[i], tag); + } + delete[] elements_per_mat; + } + + AKANTU_DEBUG_OUT(); + return size; +} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModel::packData(CommunicationBuffer & buffer, + const Array & elements, + const SynchronizationTag & tag) const { + AKANTU_DEBUG_IN(); + + switch (tag) { + case _gst_material_id: { + this->packElementalDataHelper(material_index, buffer, elements, false, + getFEEngine()); + break; + } + case _gst_smm_mass: { + packNodalDataHelper(*mass, buffer, elements, mesh); + break; + } + case _gst_smm_for_gradu: { + packNodalDataHelper(*displacement, buffer, elements, mesh); + break; + } + case _gst_for_dump: { + packNodalDataHelper(*displacement, buffer, elements, mesh); + packNodalDataHelper(*velocity, buffer, elements, mesh); + packNodalDataHelper(*acceleration, buffer, elements, mesh); + packNodalDataHelper(*internal_force, buffer, elements, mesh); + packNodalDataHelper(*external_force, buffer, elements, mesh); + break; + } + case _gst_smm_boundary: { + packNodalDataHelper(*external_force, buffer, elements, mesh); + packNodalDataHelper(*velocity, buffer, elements, mesh); + packNodalDataHelper(*blocked_dofs, 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]->packData(buffer, elements_per_mat[i], tag); + } + + delete[] elements_per_mat; + } + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer, + const Array & elements, + const SynchronizationTag & tag) { + AKANTU_DEBUG_IN(); + + switch (tag) { + case _gst_material_id: { + for (auto && element : elements) { + UInt recv_mat_index; + buffer >> recv_mat_index; + UInt & mat_index = material_index(element); + if (mat_index != UInt(-1)) + continue; + + mat_index = recv_mat_index; + UInt index = materials[mat_index]->addElement(element); + material_local_numbering(element) = index; + std::cout << "Registering: " << element << " in material " << mat_index + << std::endl; + } + break; + } + case _gst_smm_mass: { + unpackNodalDataHelper(*mass, buffer, elements, mesh); + break; + } + case _gst_smm_for_gradu: { + unpackNodalDataHelper(*displacement, buffer, elements, mesh); + break; + } + case _gst_for_dump: { + unpackNodalDataHelper(*displacement, buffer, elements, mesh); + unpackNodalDataHelper(*velocity, buffer, elements, mesh); + unpackNodalDataHelper(*acceleration, buffer, elements, mesh); + unpackNodalDataHelper(*internal_force, buffer, elements, mesh); + unpackNodalDataHelper(*external_force, buffer, elements, mesh); + break; + } + case _gst_smm_boundary: { + unpackNodalDataHelper(*external_force, buffer, elements, mesh); + unpackNodalDataHelper(*velocity, buffer, elements, mesh); + unpackNodalDataHelper(*blocked_dofs, 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]->unpackData(buffer, elements_per_mat[i], tag); + } + + delete[] elements_per_mat; + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +UInt SolidMechanicsModel::getNbData(const Array & dofs, + const SynchronizationTag & tag) const { + AKANTU_DEBUG_IN(); + + UInt size = 0; + // UInt nb_nodes = mesh.getNbNodes(); + + switch (tag) { + case _gst_smm_uv: { + size += sizeof(Real) * Model::spatial_dimension * 2; + break; + } + case _gst_smm_res: { + size += sizeof(Real) * Model::spatial_dimension; + break; + } + case _gst_smm_mass: { + size += sizeof(Real) * Model::spatial_dimension; + break; + } + case _gst_for_dump: { + size += sizeof(Real) * Model::spatial_dimension * 5; + break; + } + default: { + AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); + } + } + + AKANTU_DEBUG_OUT(); + return size * dofs.size(); +} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModel::packData(CommunicationBuffer & buffer, + const Array & dofs, + const SynchronizationTag & tag) const { + AKANTU_DEBUG_IN(); + + switch (tag) { + case _gst_smm_uv: { + packDOFDataHelper(*displacement, buffer, dofs); + packDOFDataHelper(*velocity, buffer, dofs); + break; + } + case _gst_smm_res: { + packDOFDataHelper(*internal_force, buffer, dofs); + break; + } + case _gst_smm_mass: { + packDOFDataHelper(*mass, buffer, dofs); + break; + } + case _gst_for_dump: { + packDOFDataHelper(*displacement, buffer, dofs); + packDOFDataHelper(*velocity, buffer, dofs); + packDOFDataHelper(*acceleration, buffer, dofs); + packDOFDataHelper(*internal_force, buffer, dofs); + packDOFDataHelper(*external_force, buffer, dofs); + break; + } + default: { + AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); + } + } + + AKANTU_DEBUG_OUT(); +} + +/* -------------------------------------------------------------------------- */ +void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer, + const Array & dofs, + const SynchronizationTag & tag) { + AKANTU_DEBUG_IN(); + + switch (tag) { + case _gst_smm_uv: { + unpackDOFDataHelper(*displacement, buffer, dofs); + unpackDOFDataHelper(*velocity, buffer, dofs); + break; + } + case _gst_smm_res: { + unpackDOFDataHelper(*internal_force, buffer, dofs); + break; + } + case _gst_smm_mass: { + unpackDOFDataHelper(*mass, buffer, dofs); + break; + } + case _gst_for_dump: { + unpackDOFDataHelper(*displacement, buffer, dofs); + unpackDOFDataHelper(*velocity, buffer, dofs); + unpackDOFDataHelper(*acceleration, buffer, dofs); + unpackDOFDataHelper(*internal_force, buffer, dofs); + unpackDOFDataHelper(*external_force, buffer, dofs); + break; + } + default: { + AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); + } + } + + AKANTU_DEBUG_OUT(); +} + } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model.hh b/src/model/solid_mechanics/solid_mechanics_model.hh index b6f61e377..3bea24f26 100644 --- a/src/model/solid_mechanics/solid_mechanics_model.hh +++ b/src/model/solid_mechanics/solid_mechanics_model.hh @@ -1,595 +1,595 @@ /** * @file solid_mechanics_model.hh * * @author Guillaume Anciaux * @author Daniel Pino Muñoz * @author Nicolas Richart * * @date creation: Tue Jul 27 2010 * @date last modification: Tue Jan 19 2016 * * @brief Model of Solid Mechanics * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "boundary_condition.hh" #include "data_accessor.hh" +#include "fe_engine.hh" #include "model.hh" #include "non_local_manager.hh" #include "solid_mechanics_model_event_handler.hh" -#include "fe_engine.hh" /* -------------------------------------------------------------------------- */ //#include "integrator_gauss.hh" //#include "shape_lagrange.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLID_MECHANICS_MODEL_HH__ #define __AKANTU_SOLID_MECHANICS_MODEL_HH__ namespace akantu { class Material; class MaterialSelector; class DumperIOHelper; class NonLocalManager; template class IntegratorGauss; template class ShapeLagrange; } // namespace akantu /* -------------------------------------------------------------------------- */ namespace akantu { namespace { -DECLARE_NAMED_ARGUMENT(analysis_method); + DECLARE_NAMED_ARGUMENT(analysis_method); } struct SolidMechanicsModelOptions : public ModelOptions { explicit SolidMechanicsModelOptions( AnalysisMethod analysis_method = _explicit_lumped_mass); template SolidMechanicsModelOptions(use_named_args_t, pack &&... _pack); AnalysisMethod analysis_method; }; /* -------------------------------------------------------------------------- */ class SolidMechanicsModel : public Model, public DataAccessor, public DataAccessor, public BoundaryCondition, public NonLocalManagerCallback, public EventHandlerManager { /* ------------------------------------------------------------------------ */ /* 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; }; using MyFEEngineType = FEEngineTemplate; protected: using EventManager = EventHandlerManager; public: SolidMechanicsModel(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "solid_mechanics_model", const MemoryID & memory_id = 0); virtual ~SolidMechanicsModel(); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: template void initFull(named_argument::param_t && first, pack &&... _pack) { this->initFull(SolidMechanicsModelOptions{use_named_args, first, _pack...}); } /// initialize completely the model void initFull( const ModelOptions & options = SolidMechanicsModelOptions()) override; /// initialize the fem object needed for boundary conditions void initFEEngineBoundary(); /// initialize all internal arrays for materials virtual void initMaterials(); /// initialize the model void initModel() override; /// initialize a new solver and sets it as the default one to use void initNewSolver(const AnalysisMethod & method); /// function to print the containt of the class void printself(std::ostream & stream, int indent = 0) const override; /* ------------------------------------------------------------------------ */ /* Solver interface */ /* ------------------------------------------------------------------------ */ public: /// assembles the stiffness matrix, virtual void assembleStiffnessMatrix(); /// assembles the internal forces in the array internal_forces virtual void assembleInternalForces(); protected: /// callback for the solver, this adds f_{ext} - f_{int} to the residual void assembleResidual() override; /// get the type of matrix needed MatrixType getMatrixType(const ID & matrix_id) override; /// callback for the solver, this assembles different matrices void assembleMatrix(const ID & matrix_id) override; /// callback for the solver, this assembles the stiffness matrix void assembleLumpedMatrix(const ID & matrix_id) override; /// callback for the solver, this is called at beginning of solve void predictor() override; /// callback for the solver, this is called at end of solve void corrector() override; /// callback for the solver, this is called at beginning of solve void beforeSolveStep() override; /// callback for the solver, this is called at end of solve void afterSolveStep() override; /// Callback for the model to instantiate the matricees when needed void initSolver(TimeStepSolverType time_step_solver_type, NonLinearSolverType non_linear_solver_type) override; protected: /* ------------------------------------------------------------------------ */ TimeStepSolverType getDefaultSolverType() const override; /* ------------------------------------------------------------------------ */ ModelSolverOptions getDefaultSolverOptions(const TimeStepSolverType & type) const override; public: bool isDefaultSolverExplicit() { return method == _explicit_lumped_mass || method == _explicit_consistent_mass; } protected: /// update the current position vector void updateCurrentPosition(); /* ------------------------------------------------------------------------ */ /* Materials (solid_mechanics_model_material.cc) */ /* ------------------------------------------------------------------------ */ public: /// register an empty material of a given type Material & registerNewMaterial(const ID & mat_name, const ID & mat_type, const ID & opt_param); /// reassigns materials depending on the material selector virtual void reassignMaterial(); /// apply a constant eigen_grad_u on all quadrature points of a given material virtual void applyEigenGradU(const Matrix & prescribed_eigen_grad_u, const ID & material_name, const GhostType ghost_type = _not_ghost); protected: /// register a material in the dynamic database Material & registerNewMaterial(const ParserSection & mat_section); /// read the material files to instantiate all the materials void instantiateMaterials(); /// set the element_id_by_material and add the elements to the good materials void assignMaterialToElements(const ElementTypeMapArray * filter = NULL); /* ------------------------------------------------------------------------ */ /* 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); /// 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(); /* ------------------------------------------------------------------------ */ /* NonLocalManager inherited members */ /* ------------------------------------------------------------------------ */ protected: + void initializeNonLocal() override; + void updateDataForNonLocalCriterion(ElementTypeMapReal & criterion) override; void computeNonLocalStresses(const GhostType & ghost_type) override; void insertIntegrationPointsInNeighborhoods(const GhostType & ghost_type) override; /// update the values of the non local internal void updateLocalInternal(ElementTypeMapReal & internal_flat, const GhostType & ghost_type, const ElementKind & kind) override; /// copy the results of the averaging in the materials void updateNonLocalInternal(ElementTypeMapReal & internal_flat, const GhostType & ghost_type, const ElementKind & kind) override; /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ public: - inline UInt getNbData(const Array & elements, - const SynchronizationTag & tag) const override; + UInt getNbData(const Array & elements, + const SynchronizationTag & tag) const override; - inline void packData(CommunicationBuffer & buffer, - const Array & elements, - const SynchronizationTag & tag) const override; + void packData(CommunicationBuffer & buffer, const Array & elements, + const SynchronizationTag & tag) const override; - inline void unpackData(CommunicationBuffer & buffer, - const Array & elements, - const SynchronizationTag & tag) override; + void unpackData(CommunicationBuffer & buffer, const Array & elements, + const SynchronizationTag & tag) override; - inline UInt getNbData(const Array & dofs, - const SynchronizationTag & tag) const override; + UInt getNbData(const Array & dofs, + const SynchronizationTag & tag) const override; - inline void packData(CommunicationBuffer & buffer, const Array & dofs, - const SynchronizationTag & tag) const override; + void packData(CommunicationBuffer & buffer, const Array & dofs, + const SynchronizationTag & tag) const override; - inline void unpackData(CommunicationBuffer & buffer, const Array & dofs, - const SynchronizationTag & tag) override; + void unpackData(CommunicationBuffer & buffer, const Array & dofs, + const SynchronizationTag & tag) override; protected: inline void splitElementByMaterial(const Array & elements, Array * elements_per_mat) const; /* ------------------------------------------------------------------------ */ /* Mesh Event Handler inherited members */ /* ------------------------------------------------------------------------ */ protected: void onNodesAdded(const Array & nodes_list, const NewNodesEvent & event) override; void onNodesRemoved(const Array & element_list, const Array & new_numbering, const RemovedNodesEvent & event) override; void onElementsAdded(const Array & nodes_list, const NewElementsEvent & event) override; void onElementsRemoved(const Array & element_list, const ElementTypeMapArray & new_numbering, const RemovedElementsEvent & event) override; void onElementsChanged(const Array &, const Array &, const ElementTypeMapArray &, const ChangedElementsEvent &) override{}; /* ------------------------------------------------------------------------ */ /* Dumpable interface (kept for convenience) and dumper relative functions */ /* ------------------------------------------------------------------------ */ public: virtual void onDump(); //! decide wether a field is a material internal or not bool isInternal(const std::string & field_name, const ElementKind & element_kind); #ifndef SWIG //! give the amount of data per element virtual ElementTypeMap getInternalDataPerElem(const std::string & field_name, const ElementKind & kind); //! flatten a given material internal field ElementTypeMapArray & flattenInternal(const std::string & field_name, const ElementKind & kind, const GhostType ghost_type = _not_ghost); //! flatten all the registered material internals void flattenAllRegisteredInternals(const ElementKind & kind); #endif dumper::Field * createNodalFieldReal(const std::string & field_name, const std::string & group_name, bool padding_flag) override; dumper::Field * createNodalFieldBool(const std::string & field_name, const std::string & group_name, bool padding_flag) override; dumper::Field * createElementalField(const std::string & field_name, const std::string & group_name, bool padding_flag, const UInt & spatial_dimension, const ElementKind & kind) override; virtual void dump(const std::string & dumper_name); virtual void dump(const std::string & dumper_name, UInt step); virtual void dump(const std::string & dumper_name, Real time, UInt step); void dump() override; virtual void dump(UInt step); virtual void dump(Real time, UInt step); /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// return the dimension of the system space AKANTU_GET_MACRO(SpatialDimension, Model::spatial_dimension, UInt); /// set the value of the time step void setTimeStep(Real time_step, const ID & solver_id = "") override; /// 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 const Array & getCurrentPosition(); /// get the SolidMechanicsModel::increment vector \warn only consistent if /// SolidMechanicsModel::setIncrementFlagOn has been called before AKANTU_GET_MACRO(Increment, *displacement_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 (external forces) AKANTU_GET_MACRO(Force, *external_force, Array &); /// get the SolidMechanicsModel::internal_force vector (internal forces) AKANTU_GET_MACRO(InternalForce, *internal_force, Array &); /// get the SolidMechanicsModel::blocked_dofs vector AKANTU_GET_MACRO(BlockedDOFs, *blocked_dofs, 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(); /// 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); /// get the FEEngine object to integrate or interpolate on the boundary FEEngine & getFEEngineBoundary(const ID & name = "") override; AKANTU_GET_MACRO(MaterialByElement, material_index, const ElementTypeMapArray &); /// vectors containing local material element index for each global element /// index AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(MaterialByElement, material_index, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(MaterialByElement, material_index, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(MaterialLocalNumbering, material_local_numbering, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(MaterialLocalNumbering, material_local_numbering, UInt); /// Get the type of analysis method used AKANTU_GET_MACRO(AnalysisMethod, method, AnalysisMethod); /// Access the non_local_manager interface AKANTU_GET_MACRO(NonLocalManager, *non_local_manager, NonLocalManager &); protected: friend class Material; protected: /// compute the stable time step Real getStableTimeStep(const GhostType & ghost_type); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// conversion coefficient form force/mass to acceleration Real f_m2a; /// displacements array Array * displacement; UInt displacement_release{0}; /// displacements array at the previous time step (used in finite deformation) Array * previous_displacement; /// increment of displacement Array * displacement_increment; /// lumped mass array Array * mass; /// Check if materials need to recompute the mass array bool need_to_reassemble_lumped_mass{true}; /// Check if materials need to recompute the mass matrix bool need_to_reassemble_mass{true}; /// velocities array Array * velocity; /// accelerations array Array * acceleration; /// accelerations array // Array * increment_acceleration; /// external forces array Array * external_force; /// internal forces array Array * internal_force; /// array specifing if a degree of freedom is blocked or not Array * blocked_dofs; /// array of current position used during update residual Array * current_position; UInt current_position_release{0}; /// Arrays containing the material index for each element ElementTypeMapArray material_index; /// Arrays containing the position in the element filter of the material /// (material's local numbering) ElementTypeMapArray material_local_numbering; #ifdef SWIGPYTHON public: #endif /// list of used materials std::vector> materials; /// mapping between material name and material internal id std::map materials_names_to_id; #ifdef SWIGPYTHON protected: #endif /// class defining of to choose a material MaterialSelector * material_selector; /// define if it is the default selector or not bool is_default_material_selector; /// flag defining if the increment must be computed or not bool increment_flag; /// analysis method check the list in akantu::AnalysisMethod AnalysisMethod method; /// tells if the material are instantiated bool are_materials_instantiated; typedef std::map, ElementTypeMapArray *> flatten_internal_map; /// map a registered internals to be flattened for dump purposes flatten_internal_map registered_internals; /// non local manager std::unique_ptr non_local_manager; }; /* -------------------------------------------------------------------------- */ namespace BC { namespace Neumann { typedef FromHigherDim FromStress; typedef FromSameDim FromTraction; } // namespace Neumann } // namespace BC /// standard output stream operator inline std::ostream & operator<<(std::ostream & stream, const SolidMechanicsModel & _this) { _this.printself(stream); return stream; } } // namespace akantu /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "material.hh" #include "parser.hh" #include "solid_mechanics_model_inline_impl.cc" #include "solid_mechanics_model_tmpl.hh" #include "material_selector_tmpl.hh" #endif /* __AKANTU_SOLID_MECHANICS_MODEL_HH__ */ 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 9ab911c71..1e9873c88 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_inline_impl.cc @@ -1,421 +1,124 @@ /** * @file solid_mechanics_model_inline_impl.cc * * @author Guillaume Anciaux * @author Daniel Pino Muñoz * @author Nicolas Richart * * @date creation: Wed Aug 04 2010 * @date last modification: Wed Nov 18 2015 * * @brief Implementation of the inline functions of the SolidMechanicsModel * class * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_named_argument.hh" #include "material_selector.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLID_MECHANICS_MODEL_INLINE_IMPL_CC__ #define __AKANTU_SOLID_MECHANICS_MODEL_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline SolidMechanicsModelOptions::SolidMechanicsModelOptions( AnalysisMethod analysis_method) : analysis_method(analysis_method) {} /* -------------------------------------------------------------------------- */ template SolidMechanicsModelOptions::SolidMechanicsModelOptions(use_named_args_t, pack &&... _pack) : SolidMechanicsModelOptions( OPTIONAL_NAMED_ARG(analysis_method, _explicit_lumped_mass)) {} /* -------------------------------------------------------------------------- */ 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 void SolidMechanicsModel::splitElementByMaterial( - const Array & elements, Array * elements_per_mat) const { - ElementType current_element_type = _not_defined; - GhostType current_ghost_type = _casper; - const Array * mat_indexes = NULL; - const Array * mat_loc_num = 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; - mat_indexes = &(this->material_index(el.type, el.ghost_type)); - mat_loc_num = &(this->material_local_numbering(el.type, el.ghost_type)); - } - - UInt old_id = el.element; - el.element = (*mat_loc_num)(old_id); - elements_per_mat[(*mat_indexes)(old_id)].push_back(el); - } -} - -/* -------------------------------------------------------------------------- */ -inline UInt -SolidMechanicsModel::getNbData(const Array & elements, - const SynchronizationTag & tag) const { - AKANTU_DEBUG_IN(); - - UInt size = 0; - 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.size() * sizeof(UInt); - break; - } - case _gst_smm_mass: { - size += nb_nodes_per_element * sizeof(Real) * - Model::spatial_dimension; // mass vector - break; - } - case _gst_smm_for_gradu: { - size += nb_nodes_per_element * Model::spatial_dimension * - sizeof(Real); // displacement - break; - } - case _gst_smm_boundary: { - // force, displacement, boundary - size += nb_nodes_per_element * Model::spatial_dimension * - (2 * sizeof(Real) + sizeof(bool)); - break; - } - case _gst_for_dump: { - // displacement, velocity, acceleration, residual, force - size += nb_nodes_per_element * Model::spatial_dimension * sizeof(Real) * 5; - 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]->getNbData(elements_per_mat[i], tag); - } - delete[] elements_per_mat; - } - - AKANTU_DEBUG_OUT(); - return size; -} - -/* -------------------------------------------------------------------------- */ -inline void -SolidMechanicsModel::packData(CommunicationBuffer & buffer, - const Array & elements, - const SynchronizationTag & tag) const { - AKANTU_DEBUG_IN(); - - switch (tag) { - case _gst_material_id: { - this->packElementalDataHelper(material_index, buffer, elements, false, - getFEEngine()); - break; - } - case _gst_smm_mass: { - packNodalDataHelper(*mass, buffer, elements, mesh); - break; - } - case _gst_smm_for_gradu: { - packNodalDataHelper(*displacement, buffer, elements, mesh); - break; - } - case _gst_for_dump: { - packNodalDataHelper(*displacement, buffer, elements, mesh); - packNodalDataHelper(*velocity, buffer, elements, mesh); - packNodalDataHelper(*acceleration, buffer, elements, mesh); - packNodalDataHelper(*internal_force, buffer, elements, mesh); - packNodalDataHelper(*external_force, buffer, elements, mesh); - break; - } - case _gst_smm_boundary: { - packNodalDataHelper(*external_force, buffer, elements, mesh); - packNodalDataHelper(*velocity, buffer, elements, mesh); - packNodalDataHelper(*blocked_dofs, 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]->packData(buffer, elements_per_mat[i], tag); - } - - delete[] elements_per_mat; - } - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ -inline void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer, - const Array & elements, - const SynchronizationTag & tag) { - AKANTU_DEBUG_IN(); - - switch (tag) { - case _gst_material_id: { - unpackElementalDataHelper(material_index, buffer, elements, false, - getFEEngine()); - break; - } - case _gst_smm_mass: { - unpackNodalDataHelper(*mass, buffer, elements, mesh); - break; - } - case _gst_smm_for_gradu: { - unpackNodalDataHelper(*displacement, buffer, elements, mesh); - break; - } - case _gst_for_dump: { - unpackNodalDataHelper(*displacement, buffer, elements, mesh); - unpackNodalDataHelper(*velocity, buffer, elements, mesh); - unpackNodalDataHelper(*acceleration, buffer, elements, mesh); - unpackNodalDataHelper(*internal_force, buffer, elements, mesh); - unpackNodalDataHelper(*external_force, buffer, elements, mesh); - break; - } - case _gst_smm_boundary: { - unpackNodalDataHelper(*external_force, buffer, elements, mesh); - unpackNodalDataHelper(*velocity, buffer, elements, mesh); - unpackNodalDataHelper(*blocked_dofs, 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]->unpackData(buffer, elements_per_mat[i], tag); - } - - delete[] elements_per_mat; - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ -inline UInt -SolidMechanicsModel::getNbData(const Array & dofs, - const SynchronizationTag & tag) const { - AKANTU_DEBUG_IN(); - - UInt size = 0; - // UInt nb_nodes = mesh.getNbNodes(); - - switch (tag) { - case _gst_smm_uv: { - size += sizeof(Real) * Model::spatial_dimension * 2; - break; - } - case _gst_smm_res: { - size += sizeof(Real) * Model::spatial_dimension; - break; - } - case _gst_smm_mass: { - size += sizeof(Real) * Model::spatial_dimension; - break; - } - case _gst_for_dump: { - size += sizeof(Real) * Model::spatial_dimension * 5; - break; - } - default: { - AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); - } - } - - AKANTU_DEBUG_OUT(); - return size * dofs.size(); -} - -/* -------------------------------------------------------------------------- */ -inline void -SolidMechanicsModel::packData(CommunicationBuffer & buffer, - const Array & dofs, - const SynchronizationTag & tag) const { - AKANTU_DEBUG_IN(); - - switch (tag) { - case _gst_smm_uv: { - packDOFDataHelper(*displacement, buffer, dofs); - packDOFDataHelper(*velocity, buffer, dofs); - break; - } - case _gst_smm_res: { - packDOFDataHelper(*internal_force, buffer, dofs); - break; - } - case _gst_smm_mass: { - packDOFDataHelper(*mass, buffer, dofs); - break; - } - case _gst_for_dump: { - packDOFDataHelper(*displacement, buffer, dofs); - packDOFDataHelper(*velocity, buffer, dofs); - packDOFDataHelper(*acceleration, buffer, dofs); - packDOFDataHelper(*internal_force, buffer, dofs); - packDOFDataHelper(*external_force, buffer, dofs); - break; - } - default: { - AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); - } - } - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ -inline void SolidMechanicsModel::unpackData(CommunicationBuffer & buffer, - const Array & dofs, - const SynchronizationTag & tag) { - AKANTU_DEBUG_IN(); - - switch (tag) { - case _gst_smm_uv: { - unpackDOFDataHelper(*displacement, buffer, dofs); - unpackDOFDataHelper(*velocity, buffer, dofs); - break; - } - case _gst_smm_res: { - unpackDOFDataHelper(*internal_force, buffer, dofs); - break; - } - case _gst_smm_mass: { - unpackDOFDataHelper(*mass, buffer, dofs); - break; - } - case _gst_for_dump: { - unpackDOFDataHelper(*displacement, buffer, dofs); - unpackDOFDataHelper(*velocity, buffer, dofs); - unpackDOFDataHelper(*acceleration, buffer, dofs); - unpackDOFDataHelper(*internal_force, buffer, dofs); - unpackDOFDataHelper(*external_force, buffer, dofs); - break; - } - default: { - AKANTU_DEBUG_ERROR("Unknown ghost synchronization tag : " << tag); - } - } - - AKANTU_DEBUG_OUT(); -} - /* -------------------------------------------------------------------------- */ } // namespace akantu #endif /* __AKANTU_SOLID_MECHANICS_MODEL_INLINE_IMPL_CC__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_material.cc b/src/model/solid_mechanics/solid_mechanics_model_material.cc index 43d1007b3..8ed83cee0 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_material.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_material.cc @@ -1,316 +1,316 @@ /** * @file solid_mechanics_model_material.cc * * @author Guillaume Anciaux * @author Nicolas Richart * * @date creation: Fri Nov 26 2010 * @date last modification: Mon Nov 16 2015 * * @brief instatiation of materials * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_factory.hh" #include "aka_math.hh" #include "material_non_local.hh" #include "solid_mechanics_model.hh" #ifdef AKANTU_DAMAGE_NON_LOCAL #include "non_local_manager.hh" #endif /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Material & SolidMechanicsModel::registerNewMaterial(const ParserSection & section) { std::string mat_name; std::string mat_type = section.getName(); std::string opt_param = section.getOption(); try { std::string tmp = section.getParameter("name"); mat_name = tmp; /** this can seam weird, but there is an ambiguous operator * overload that i couldn't solve. @todo remove the * weirdness of this code */ } catch (debug::Exception &) { AKANTU_DEBUG_ERROR( "A material of type \'" << mat_type << "\' in the input file has been defined without a name!"); } Material & mat = this->registerNewMaterial(mat_name, mat_type, opt_param); mat.parseSection(section); return mat; } /* -------------------------------------------------------------------------- */ Material & SolidMechanicsModel::registerNewMaterial(const ID & mat_name, const ID & mat_type, const ID & opt_param) { AKANTU_DEBUG_ASSERT(materials_names_to_id.find(mat_name) == materials_names_to_id.end(), "A material with this name '" << mat_name << "' has already been registered. " << "Please use unique names for materials"); UInt mat_count = materials.size(); materials_names_to_id[mat_name] = mat_count; std::stringstream sstr_mat; sstr_mat << this->id << ":" << mat_count << ":" << mat_type; ID mat_id = sstr_mat.str(); std::unique_ptr material = MaterialFactory::getInstance().allocate( - mat_type, Model::spatial_dimension, opt_param, *this, mat_id); + mat_type, spatial_dimension, opt_param, *this, mat_id); materials.push_back(std::move(material)); return *(materials.back()); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::instantiateMaterials() { std::pair sub_sect = this->parser->getSubSections(_st_material); Parser::const_section_iterator it = sub_sect.first; for (; it != sub_sect.second; ++it) { const ParserSection & section = *it; registerNewMaterial(section); } #ifdef AKANTU_DAMAGE_NON_LOCAL for (auto & material : materials) { if (dynamic_cast(material.get()) == nullptr) continue; this->non_local_manager = std::make_unique( *this, *this, id + ":non_local_manager", memory_id); break; } #endif are_materials_instantiated = true; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::assignMaterialToElements( const ElementTypeMapArray * filter) { Element element; element.ghost_type = _not_ghost; auto element_types = - mesh.elementTypes(Model::spatial_dimension, _not_ghost, _ek_not_defined); - if (filter != NULL) { - element_types = filter->elementTypes(Model::spatial_dimension, _not_ghost, - _ek_not_defined); + mesh.elementTypes(spatial_dimension, _not_ghost, _ek_not_defined); + if (filter != nullptr) { + element_types = + filter->elementTypes(spatial_dimension, _not_ghost, _ek_not_defined); } // Fill the element material array from the material selector for (auto type : element_types) { UInt nb_element = mesh.getNbElement(type, _not_ghost); - const Array * filter_array = NULL; - if (filter != NULL) { + const Array * filter_array = nullptr; + if (filter != nullptr) { filter_array = &((*filter)(type, _not_ghost)); nb_element = filter_array->size(); } element.type = type; element.kind = mesh.getKind(element.type); Array & mat_indexes = material_index(type, _not_ghost); for (UInt el = 0; el < nb_element; ++el) { - if (filter != NULL) + if (filter != nullptr) element.element = (*filter_array)(el); else element.element = el; UInt mat_index = (*material_selector)(element); AKANTU_DEBUG_ASSERT( mat_index < materials.size(), "The material selector returned an index that does not exists"); mat_indexes(element.element) = mat_index; } } - // synchronize the element material arrays - this->synchronize(_gst_material_id); + if (non_local_manager) + non_local_manager->synchronize(*this, _gst_material_id); /// fill the element filters of the materials using the element_material /// arrays - for (auto ghost_type : ghost_types) { - element_types = mesh.elementTypes(Model::spatial_dimension, ghost_type, - _ek_not_defined); - - if (filter != NULL) { - element_types = filter->elementTypes(Model::spatial_dimension, ghost_type, - _ek_not_defined); - } + auto ghost_type = _not_ghost; + if (filter != nullptr) { + element_types = + filter->elementTypes(spatial_dimension, ghost_type, _ek_not_defined); + } else { + element_types = + mesh.elementTypes(spatial_dimension, ghost_type, _ek_not_defined); + } - for (auto type : element_types) { - UInt nb_element = mesh.getNbElement(type, ghost_type); + for (auto type : element_types) { + UInt nb_element = mesh.getNbElement(type, ghost_type); - const Array * filter_array = NULL; - if (filter != NULL) { - filter_array = &((*filter)(type, ghost_type)); - nb_element = filter_array->size(); - } + const Array * filter_array = nullptr; + if (filter != nullptr) { + filter_array = &((*filter)(type, ghost_type)); + nb_element = filter_array->size(); + } - Array & mat_indexes = material_index(type, ghost_type); - Array & mat_local_num = material_local_numbering(type, ghost_type); - for (UInt el = 0; el < nb_element; ++el) { - UInt element; + Array & mat_indexes = material_index(type, ghost_type); + Array & mat_local_num = material_local_numbering(type, ghost_type); + for (UInt el = 0; el < nb_element; ++el) { + UInt element; - if (filter != NULL) - element = (*filter_array)(el); - else - element = el; + if (filter != nullptr) + element = (*filter_array)(el); + else + element = el; - UInt mat_index = mat_indexes(element); - UInt index = - materials[mat_index]->addElement(type, element, ghost_type); - mat_local_num(element) = index; - } + UInt mat_index = mat_indexes(element); + UInt index = materials[mat_index]->addElement(type, element, ghost_type); + mat_local_num(element) = index; } } } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::initMaterials() { AKANTU_DEBUG_ASSERT(materials.size() != 0, "No material to initialize !"); if (!are_materials_instantiated) instantiateMaterials(); this->assignMaterialToElements(); + // synchronize the element material arrays + this->synchronize(_gst_material_id); for (auto & material : materials) { /// init internals properties material->initMaterial(); } this->synchronize(_gst_smm_init_mat); // initialize mass switch (method) { case _explicit_lumped_mass: assembleMassLumped(); break; case _explicit_consistent_mass: case _implicit_dynamic: assembleMass(); break; case _static: break; default: AKANTU_EXCEPTION("analysis method not recognised by SolidMechanicsModel"); break; } - - if(this->non_local_manager) + if (this->non_local_manager) { this->non_local_manager->initialize(); + } } /* -------------------------------------------------------------------------- */ Int SolidMechanicsModel::getInternalIndexFromID(const ID & id) const { AKANTU_DEBUG_IN(); auto it = materials.begin(); auto end = materials.end(); for (; it != end; ++it) if ((*it)->getID() == id) { AKANTU_DEBUG_OUT(); return (it - materials.begin()); } AKANTU_DEBUG_OUT(); return -1; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::reassignMaterial() { AKANTU_DEBUG_IN(); std::vector> element_to_add(materials.size()); std::vector> element_to_remove(materials.size()); Element element; for (auto ghost_type : ghost_types) { element.ghost_type = ghost_type; - for (auto type : mesh.elementTypes(Model::spatial_dimension, ghost_type, - _ek_not_defined)) { + for (auto type : + mesh.elementTypes(spatial_dimension, ghost_type, _ek_not_defined)) { element.type = type; element.kind = Mesh::getKind(type); UInt nb_element = mesh.getNbElement(type, ghost_type); Array & mat_indexes = material_index(type, ghost_type); for (UInt el = 0; el < nb_element; ++el) { element.element = el; UInt old_material = mat_indexes(el); UInt new_material = (*material_selector)(element); if (old_material != new_material) { element_to_add[new_material].push_back(element); element_to_remove[old_material].push_back(element); } } } } UInt mat_index = 0; for (auto mat_it = materials.begin(); mat_it != materials.end(); ++mat_it, ++mat_index) { (*mat_it)->removeElements(element_to_remove[mat_index]); (*mat_it)->addElements(element_to_add[mat_index]); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModel::applyEigenGradU( const Matrix & prescribed_eigen_grad_u, const ID & material_name, const GhostType ghost_type) { AKANTU_DEBUG_ASSERT(prescribed_eigen_grad_u.size() == - Model::spatial_dimension * Model::spatial_dimension, + spatial_dimension * spatial_dimension, "The prescribed grad_u is not of the good size"); for (auto & material : materials) { if (material->getName() == material_name) material->applyEigenGradU(prescribed_eigen_grad_u, ghost_type); } } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/synchronizer/communication_descriptor.hh b/src/synchronizer/communication_descriptor.hh index 1888491fa..e22d60d03 100644 --- a/src/synchronizer/communication_descriptor.hh +++ b/src/synchronizer/communication_descriptor.hh @@ -1,147 +1,152 @@ /** * @file synchronizer_tmpl.hh * * @author Nicolas Richart * * @date Wed Aug 3 13:49:36 2016 * * @brief Implementation of the helper classes for the 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 "aka_array.hh" #include "communication_tag.hh" #include "data_accessor.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMUNICATION_DESCRIPTOR_HH__ #define __AKANTU_COMMUNICATION_DESCRIPTOR_HH__ namespace akantu { /* ------------------------------------------------------------------------ */ enum CommunicationSendRecv { _send, _recv, _csr_not_defined }; /* -------------------------------------------------------------------------- */ struct CommunicationSRType { typedef CommunicationSendRecv type; static const type _begin_ = _send; static const type _end_ = _csr_not_defined; }; typedef safe_enum send_recv_t; +namespace { + send_recv_t iterate_send_recv{}; +} + /* ------------------------------------------------------------------------ */ class Communication { public: - Communication(const CommunicationSendRecv & type = _csr_not_defined) + explicit Communication(const CommunicationSendRecv & type = _csr_not_defined) : _size(0), _type(type) {} Communication(const Communication &) = delete; Communication & operator=(const Communication &) = delete; void resize(UInt size) { this->_size = size; this->_buffer.resize(size); } inline const CommunicationSendRecv & type() const { return this->_type; } inline const UInt & size() const { return this->_size; } inline const CommunicationRequest & request() const { return this->_request; } inline CommunicationRequest & request() { return this->_request; } inline const CommunicationBuffer & buffer() const { return this->_buffer; } inline CommunicationBuffer & buffer() { return this->_buffer; } + private: UInt _size; CommunicationBuffer _buffer; CommunicationRequest _request; CommunicationSendRecv _type; }; template class Communications; /* ------------------------------------------------------------------------ */ template class CommunicationDescriptor { public: CommunicationDescriptor(Communication & communication, Array & scheme, Communications & communications, const SynchronizationTag & tag, UInt proc); CommunicationDescriptor(const CommunicationDescriptor &) = default; CommunicationDescriptor & operator=(const CommunicationDescriptor &) = default; /// get the quantity of data in the buffer UInt getNbData() { return communication.size(); } /// set the quantity of data in the buffer void setNbData(UInt size) { communication.resize(size); } /// get the corresponding tag const SynchronizationTag & getTag() const { return tag; } /// get the data buffer CommunicationBuffer & getBuffer(); /// get the corresponding request CommunicationRequest & getRequest(); /// get the communication scheme Array & getScheme(); /// reset the buffer before pack or after unpack void resetBuffer(); /// pack data for entities in the buffer void packData(const DataAccessor & accessor); /// unpack data for entities from the buffer void unpackData(DataAccessor & accessor); /// posts asynchronous send requests void postSend(int hash_id); /// posts asynchronous receive requests void postRecv(int hash_id); /// free the request void freeRequest(); UInt getProc() { return proc; } protected: Communication & communication; Array & scheme; Communications & communications; const SynchronizationTag & tag; UInt proc; UInt rank; UInt counter; }; /* -------------------------------------------------------------------------- */ -} // akantu +} // namespace akantu #include "communication_descriptor_tmpl.hh" #endif /* __AKANTU_COMMUNICATION_DESCRIPTOR_HH__ */ diff --git a/src/synchronizer/communications.hh b/src/synchronizer/communications.hh index 6b2b07eba..a25243627 100644 --- a/src/synchronizer/communications.hh +++ b/src/synchronizer/communications.hh @@ -1,192 +1,273 @@ /** * @file communications.hh * * @author Nicolas Richart * * @date Wed Aug 24 13:56:14 2016 * * @brief * * @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 "communication_descriptor.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COMMUNICATIONS_HH__ #define __AKANTU_COMMUNICATIONS_HH__ namespace akantu { namespace debug { class CommunicationException : public Exception { public: CommunicationException() : Exception("An exception happen during a communication process.") {} }; } // namespace debug /* -------------------------------------------------------------------------- */ template class Communications { public: using Scheme = Array; protected: using CommunicationPerProcs = std::map; using CommunicationsPerTags = std::map; using CommunicationSchemes = std::map; using Request = std::map>; friend class CommunicationDescriptor; public: using scheme_iterator = typename CommunicationSchemes::iterator; using const_scheme_iterator = typename CommunicationSchemes::const_iterator; /* ------------------------------------------------------------------------ */ class iterator; class tag_iterator; /* ------------------------------------------------------------------------ */ public: CommunicationPerProcs & getCommunications(const SynchronizationTag & tag, const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ bool hasPending(const SynchronizationTag & tag, const CommunicationSendRecv & sr) const; UInt getPending(const SynchronizationTag & tag, const CommunicationSendRecv & sr) const; /* ------------------------------------------------------------------------ */ iterator begin(const SynchronizationTag & tag, const CommunicationSendRecv & sr); iterator end(const SynchronizationTag & tag, const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ iterator waitAny(const SynchronizationTag & tag, const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ void waitAll(const SynchronizationTag & tag, const CommunicationSendRecv & sr); void incrementPending(const SynchronizationTag & tag, const CommunicationSendRecv & sr); void decrementPending(const SynchronizationTag & tag, const CommunicationSendRecv & sr); void freeRequests(const SynchronizationTag & tag, const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ Scheme & createScheme(UInt proc, const CommunicationSendRecv & sr); void resetSchemes(const CommunicationSendRecv & sr); /* ------------------------------------------------------------------------ */ void setCommunicationSize(const SynchronizationTag & tag, UInt proc, UInt size, const CommunicationSendRecv & sr); public: explicit Communications(const StaticCommunicator & communicator); + + /* ------------------------------------------------------------------------ */ + class IterableCommunicationDesc { + public: + IterableCommunicationDesc(Communications & communications, + SynchronizationTag tag, + CommunicationSendRecv sr) + : communications(communications), tag(std::move(tag)), sr(std::move(sr)) {} + decltype(auto) begin() { return communications.begin(tag, sr); } + decltype(auto) end() { return communications.end(tag, sr); } + + private: + Communications & communications; + SynchronizationTag tag; + CommunicationSendRecv sr; + }; + + decltype(auto) iterateRecv(const SynchronizationTag & tag) { + return IterableCommunicationDesc(*this, tag, _recv); + } + decltype(auto) iterateSend(const SynchronizationTag & tag) { + return IterableCommunicationDesc(*this, tag, _send); + } + /* ------------------------------------------------------------------------ */ iterator begin_send(const SynchronizationTag & tag); iterator end_send(const SynchronizationTag & tag); /* ------------------------------------------------------------------------ */ iterator begin_recv(const SynchronizationTag & tag); iterator end_recv(const SynchronizationTag & tag); /* ------------------------------------------------------------------------ */ + class IterableTags { + public: + explicit IterableTags(Communications & communications) + : communications(communications) {} + decltype(auto) begin() { return communications.begin_tag(); } + decltype(auto) end() { return communications.end_tag(); } + + private: + Communications & communications; + }; + + decltype(auto) iterateTags() { return IterableTags(*this); } + tag_iterator begin_tag(); tag_iterator end_tag(); /* ------------------------------------------------------------------------ */ bool hasCommunication(const SynchronizationTag & tag) const; void incrementCounter(const SynchronizationTag & tag); UInt getCounter(const SynchronizationTag & tag) const; bool hasPendingRecv(const SynchronizationTag & tag) const; bool hasPendingSend(const SynchronizationTag & tag) const; const StaticCommunicator & getCommunicator() const; /* ------------------------------------------------------------------------ */ iterator waitAnyRecv(const SynchronizationTag & tag); iterator waitAnySend(const SynchronizationTag & tag); void waitAllRecv(const SynchronizationTag & tag); void waitAllSend(const SynchronizationTag & tag); void freeSendRequests(const SynchronizationTag & tag); void freeRecvRequests(const SynchronizationTag & tag); /* ------------------------------------------------------------------------ */ + /* ------------------------------------------------------------------------ */ + class IterableSchemes { + public: + IterableSchemes(Communications & communications, + CommunicationSendRecv sr) + : communications(communications), sr(std::move(sr)) {} + decltype(auto) begin() { return communications.begin_scheme(sr); } + decltype(auto) end() { return communications.end_scheme(sr); } + + private: + Communications & communications; + CommunicationSendRecv sr; + }; + + class ConstIterableSchemes { + public: + ConstIterableSchemes(const Communications & communications, + CommunicationSendRecv sr) + : communications(communications), sr(std::move(sr)) {} + decltype(auto) begin() const { return communications.begin_scheme(sr); } + decltype(auto) end() const { return communications.end_scheme(sr); } + + private: + const Communications & communications; + CommunicationSendRecv sr; + }; + + decltype(auto) iterateSchemes(const CommunicationSendRecv & sr) { + return IterableSchemes(*this, sr); + } + decltype(auto) iterateSchemes(const CommunicationSendRecv & sr) const { + return ConstIterableSchemes(*this, sr); + } + + decltype(auto) iterateSendSchemes() { return IterableSchemes(*this, _send); } + decltype(auto) iterateSendSchemes() const { + return ConstIterableSchemes(*this, _send); + } + + decltype(auto) iterateRecvSchemes() { return IterableSchemes(*this, _recv); } + decltype(auto) iterateRecvSchemes() const { + return ConstIterableSchemes(*this, _recv); + } + scheme_iterator begin_scheme(const CommunicationSendRecv & sr); scheme_iterator end_scheme(const CommunicationSendRecv & sr); const_scheme_iterator begin_scheme(const CommunicationSendRecv & sr) const; const_scheme_iterator end_scheme(const CommunicationSendRecv & sr) const; /* ------------------------------------------------------------------------ */ scheme_iterator begin_send_scheme(); scheme_iterator end_send_scheme(); const_scheme_iterator begin_send_scheme() const; const_scheme_iterator end_send_scheme() const; /* ------------------------------------------------------------------------ */ scheme_iterator begin_recv_scheme(); scheme_iterator end_recv_scheme(); const_scheme_iterator begin_recv_scheme() const; const_scheme_iterator end_recv_scheme() const; /* ------------------------------------------------------------------------ */ Scheme & createSendScheme(UInt proc); Scheme & createRecvScheme(UInt proc); /* ------------------------------------------------------------------------ */ Scheme & getScheme(UInt proc, const CommunicationSendRecv & sr); const Scheme & getScheme(UInt proc, const CommunicationSendRecv & sr) const; /* ------------------------------------------------------------------------ */ void resetSchemes(); /* ------------------------------------------------------------------------ */ void setSendCommunicationSize(const SynchronizationTag & tag, UInt proc, UInt size); void setRecvCommunicationSize(const SynchronizationTag & tag, UInt proc, UInt size); void initializeCommunications(const SynchronizationTag & tag); protected: CommunicationSchemes schemes[2]; CommunicationsPerTags communications[2]; std::map comm_counter; std::map pending_communications[2]; const StaticCommunicator & communicator; }; } // namespace akantu #include "communications_tmpl.hh" #endif /* __AKANTU_COMMUNICATIONS_HH__ */ diff --git a/src/synchronizer/element_info_per_processor.cc b/src/synchronizer/element_info_per_processor.cc index efd12cd1b..f4901669a 100644 --- a/src/synchronizer/element_info_per_processor.cc +++ b/src/synchronizer/element_info_per_processor.cc @@ -1,111 +1,110 @@ /** * @file element_info_per_processor.cc * * @author Nicolas Richart * * @date Fri Mar 11 14:56:42 2016 * * @brief * * @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 "element_info_per_processor.hh" #include "element_synchronizer.hh" #include "static_communicator.hh" /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ ElementInfoPerProc::ElementInfoPerProc(ElementSynchronizer & synchronizer, UInt message_cnt, UInt root, ElementType type) : MeshAccessor(synchronizer.getMesh()), synchronizer(synchronizer), rank(synchronizer.getCommunicator().whoAmI()), nb_proc(synchronizer.getCommunicator().getNbProc()), root(root), type(type), message_count(message_cnt), mesh(synchronizer.getMesh()), - comm(synchronizer.getCommunicator()) { } + comm(synchronizer.getCommunicator()) {} /* -------------------------------------------------------------------------- */ void ElementInfoPerProc::fillCommunicationScheme( const Array & partition) { AKANTU_DEBUG_IN(); Element element; element.type = this->type; element.kind = Mesh::getKind(this->type); - Communications & communications = - this->synchronizer.getCommunications(); + auto & communications = this->synchronizer.getCommunications(); + auto part = partition.begin(); - Array::const_scalar_iterator part = partition.begin(); - - std::map > send_array_per_proc; + std::map> send_array_per_proc; 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, ++part) { UInt proc = *part; - AKANTU_DEBUG(dblAccessory, "Must send : " << element << " to proc " - << proc); + AKANTU_DEBUG(dblAccessory, + "Must send : " << element << " to proc " << proc); send_array_per_proc[proc].push_back(element); } } for (auto & send_schemes : send_array_per_proc) { - if (send_schemes.second.size() == 0) continue; + if (send_schemes.second.size() == 0) + continue; auto & scheme = communications.createSendScheme(send_schemes.first); scheme.append(send_schemes.second); } - std::map > recv_array_per_proc; + std::map> recv_array_per_proc; for (UInt gel = 0; gel < nb_ghost_element; ++gel, ++part) { UInt proc = *part; element.element = gel; element.ghost_type = _ghost; - AKANTU_DEBUG(dblAccessory, "Must recv : " << element << " from proc " - << proc); + AKANTU_DEBUG(dblAccessory, + "Must recv : " << element << " from proc " << proc); recv_array_per_proc[proc].push_back(element); } for (auto & recv_schemes : recv_array_per_proc) { - if (recv_schemes.second.size() == 0) continue; + if (recv_schemes.second.size() == 0) + continue; auto & scheme = communications.createRecvScheme(recv_schemes.first); scheme.append(recv_schemes.second); } - AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ -} // akantu +} // namespace akantu diff --git a/src/synchronizer/element_info_per_processor.hh b/src/synchronizer/element_info_per_processor.hh index 88ce97160..ac07a9376 100644 --- a/src/synchronizer/element_info_per_processor.hh +++ b/src/synchronizer/element_info_per_processor.hh @@ -1,144 +1,144 @@ /** * @file element_info_per_processor.hh * * @author Nicolas Richart * * @date Fri Mar 11 14:45:15 2016 * * @brief Helper classes to create the distributed synchronizer and distribute * a mesh * * @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 "communication_buffer.hh" #include "mesh.hh" #include "mesh_accessor.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_INFO_PER_PROCESSOR_HH__ #define __AKANTU_ELEMENT_INFO_PER_PROCESSOR_HH__ namespace akantu { class ElementSynchronizer; class StaticCommunicator; class MeshPartition; } /* -------------------------------------------------------------------------- */ namespace akantu { class ElementInfoPerProc : protected MeshAccessor { public: ElementInfoPerProc(ElementSynchronizer & synchronizer, UInt message_cnt, UInt root, ElementType type); virtual void synchronizeConnectivities() = 0; virtual void synchronizePartitions() = 0; virtual void synchronizeTags() = 0; virtual void synchronizeGroups() = 0; protected: void fillCommunicationScheme(const Array & partition); template void fillElementGroupsFromBuffer(CommunicationBuffer & buffer); template void fillMeshDataTemplated(BufferType & buffer, const std::string & tag_name, UInt nb_component); template void fillMeshData(BufferType & buffer, const std::string & tag_name, const MeshDataTypeCode & type_code, UInt nb_component); protected: ElementSynchronizer & synchronizer; - UInt rank; - UInt nb_proc; + UInt rank{0}; + UInt nb_proc{1}; - UInt root; + UInt root{0}; - ElementType type; + ElementType type{_not_defined}; - UInt nb_tags; - UInt nb_nodes_per_element; - UInt nb_element; + UInt nb_tags{0}; + UInt nb_nodes_per_element{0}; + UInt nb_element{0}; - UInt nb_local_element; - UInt nb_ghost_element; + UInt nb_local_element{0}; + UInt nb_ghost_element{0}; - UInt message_count; + UInt message_count{0}; Mesh & mesh; const StaticCommunicator & comm; }; /* -------------------------------------------------------------------------- */ class MasterElementInfoPerProc : protected ElementInfoPerProc { public: MasterElementInfoPerProc(ElementSynchronizer & synchronizer, UInt message_cnt, UInt root, ElementType type, const MeshPartition & partition); - void synchronizeConnectivities(); - void synchronizePartitions(); - void synchronizeTags(); - void synchronizeGroups(); + void synchronizeConnectivities() override; + void synchronizePartitions() override; + void synchronizeTags() override; + void synchronizeGroups() override; protected: template - void fillTagBufferTemplated(DynamicCommunicationBuffer * buffers, + void fillTagBufferTemplated(std::vector & buffers, const std::string & tag_name); - void fillTagBuffer(DynamicCommunicationBuffer * buffers, + void fillTagBuffer(std::vector & buffers, const std::string & tag_name); private: const MeshPartition & partition; Vector all_nb_local_element; Vector all_nb_ghost_element; Vector all_nb_element_to_send; }; /* -------------------------------------------------------------------------- */ class SlaveElementInfoPerProc : protected ElementInfoPerProc { public: SlaveElementInfoPerProc(ElementSynchronizer & synchronizer, UInt message_cnt, UInt root); - void synchronizeConnectivities(); - void synchronizePartitions(); - void synchronizeTags(); - void synchronizeGroups(); + void synchronizeConnectivities() override; + void synchronizePartitions() override; + void synchronizeTags() override; + void synchronizeGroups() override; bool needSynchronize(); private: - UInt nb_element_to_receive; + UInt nb_element_to_receive{0}; }; } // akantu #include "element_info_per_processor_tmpl.hh" #endif /* __AKANTU_ELEMENT_INFO_PER_PROCESSOR_HH__ */ diff --git a/src/synchronizer/element_info_per_processor_tmpl.hh b/src/synchronizer/element_info_per_processor_tmpl.hh index 20390c680..dc4fb5228 100644 --- a/src/synchronizer/element_info_per_processor_tmpl.hh +++ b/src/synchronizer/element_info_per_processor_tmpl.hh @@ -1,149 +1,146 @@ /** * @file element_info_per_processor_tmpl.hh * * @author Nicolas Richart * * @date Fri Mar 11 15:03:12 2016 * * @brief * * @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 "element_group.hh" #include "element_info_per_processor.hh" #include "mesh.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_ELEMENT_INFO_PER_PROCESSOR_TMPL_HH__ #define __AKANTU_ELEMENT_INFO_PER_PROCESSOR_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template void ElementInfoPerProc::fillMeshDataTemplated(BufferType & buffer, const std::string & tag_name, UInt nb_component) { AKANTU_DEBUG_ASSERT(this->mesh.getNbElement(this->type) == nb_local_element, "Did not got enought informations for the tag " << tag_name << " and the element type " << this->type << ":" << "_not_ghost." << " Got " << nb_local_element << " values, expected " << mesh.getNbElement(this->type)); MeshData & mesh_data = this->getMeshData(); mesh_data.registerElementalData(tag_name); Array & data = mesh_data.getElementalDataArrayAlloc( tag_name, this->type, _not_ghost, nb_component); data.resize(nb_local_element); /// unpacking the data, element by element for (UInt i(0); i < nb_local_element; ++i) { for (UInt j(0); j < nb_component; ++j) { buffer >> data(i, j); } } AKANTU_DEBUG_ASSERT(mesh.getNbElement(this->type, _ghost) == nb_ghost_element, "Did not got enought informations for the tag " << tag_name << " and the element type " << this->type << ":" << "_ghost." << " Got " << nb_ghost_element << " values, expected " << mesh.getNbElement(this->type, _ghost)); Array & data_ghost = mesh_data.getElementalDataArrayAlloc( tag_name, this->type, _ghost, nb_component); data_ghost.resize(nb_ghost_element); /// unpacking the ghost data, element by element for (UInt j(0); j < nb_ghost_element; ++j) { for (UInt k(0); k < nb_component; ++k) { buffer >> data_ghost(j, k); } } } /* -------------------------------------------------------------------------- */ template void ElementInfoPerProc::fillMeshData(BufferType & buffer, const std::string & tag_name, const MeshDataTypeCode & type_code, UInt nb_component) { #define AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA(r, extra_param, elem) \ case BOOST_PP_TUPLE_ELEM(2, 0, elem): { \ fillMeshDataTemplated(buffer, tag_name, \ nb_component); \ break; \ } switch (type_code) { BOOST_PP_SEQ_FOR_EACH(AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA, , AKANTU_MESH_DATA_TYPES) default: AKANTU_DEBUG_ERROR("Could not determine the type of tag" << tag_name << "!"); break; } #undef AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA } /* -------------------------------------------------------------------------- */ template void ElementInfoPerProc::fillElementGroupsFromBuffer( CommunicationBuffer & buffer) { AKANTU_DEBUG_IN(); Element el; el.type = type; - for (ghost_type_t::iterator gt = ghost_type_t::begin(); - gt != ghost_type_t::end(); ++gt) { - UInt nb_element = mesh.getNbElement(type, *gt); - el.ghost_type = *gt; + for(auto && ghost_type : ghost_types) { + UInt nb_element = mesh.getNbElement(type, ghost_type); + el.ghost_type = ghost_type; for (UInt e = 0; e < nb_element; ++e) { el.element = e; std::vector element_to_group; buffer >> element_to_group; - AKANTU_DEBUG_ASSERT(e < mesh.getNbElement(type, *gt), + AKANTU_DEBUG_ASSERT(e < mesh.getNbElement(type, ghost_type), "The mesh does not have the element " << e); - std::vector::iterator it = element_to_group.begin(); - std::vector::iterator end = element_to_group.end(); - for (; it != end; ++it) { - mesh.getElementGroup(*it).add(el, false, false); + for (auto && element : element_to_group) { + mesh.getElementGroup(element).add(el, false, false); } } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ } // akantu #endif /* __AKANTU_ELEMENT_INFO_PER_PROCESSOR_TMPL_HH__ */ diff --git a/src/synchronizer/element_synchronizer.cc b/src/synchronizer/element_synchronizer.cc index 5bba47f79..6c4be2299 100644 --- a/src/synchronizer/element_synchronizer.cc +++ b/src/synchronizer/element_synchronizer.cc @@ -1,407 +1,342 @@ /** * @file element_synchronizer.cc * * @author Guillaume Anciaux * @author Dana Christen * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Wed Sep 01 2010 * @date last modification: Fri Jan 22 2016 * * @brief implementation of a communicator using a static_communicator for * real * send/receive * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "element_synchronizer.hh" #include "aka_common.hh" #include "mesh.hh" #include "mesh_utils.hh" /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ -#if defined(AKANTU_DEBUG_TOOLS) -#include "aka_debug_tools.hh" -#endif - -/* -------------------------------------------------------------------------- */ - namespace akantu { /* -------------------------------------------------------------------------- */ -ElementSynchronizer::ElementSynchronizer(Mesh & mesh, - const ID & id, MemoryID memory_id, +ElementSynchronizer::ElementSynchronizer(Mesh & mesh, const ID & id, + MemoryID memory_id, bool register_to_event_manager, EventHandlerPriority event_priority) - : SynchronizerImpl(id, memory_id, mesh.getCommunicator()), mesh(mesh), - prank_to_element("prank_to_element", id, memory_id) { + : SynchronizerImpl(id, memory_id, mesh.getCommunicator()), + mesh(mesh), prank_to_element("prank_to_element", id, memory_id) { AKANTU_DEBUG_IN(); if (register_to_event_manager) this->mesh.registerEventHandler(*this, event_priority); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ ElementSynchronizer::~ElementSynchronizer() = default; /* -------------------------------------------------------------------------- */ void ElementSynchronizer::substituteElements( const std::map & old_to_new_elements) { - // substitute old elements with new ones + auto found_element_end = + old_to_new_elements.end(); - auto subsitute = - [&old_to_new_elements](Communications::scheme_iterator it, - Communications::scheme_iterator end) { - std::map::const_iterator found_element_it; - std::map::const_iterator found_element_end = - old_to_new_elements.end(); - - for (; it != end; ++it) { - Array & list = it->second; - for (UInt el = 0; el < list.size(); ++el) { - found_element_it = old_to_new_elements.find(list(el)); - if (found_element_it != found_element_end) - list(el) = found_element_it->second; - } - } - }; - - subsitute(communications.begin_recv_scheme(), - communications.end_recv_scheme()); - subsitute(communications.begin_send_scheme(), - communications.end_send_scheme()); + // substitute old elements with new ones + for (auto && sr : iterate_send_recv) { + for (auto && scheme_pair : communications.iterateSchemes(sr)) { + auto & list = scheme_pair.second; + for (auto & el : list) { + auto found_element_it = old_to_new_elements.find(el); + if (found_element_it != found_element_end) + el = found_element_it->second; + } + } + } } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::onElementsChanged( const Array & old_elements_list, - const Array & new_elements_list, - __attribute__((unused)) const ElementTypeMapArray & new_numbering, - __attribute__((unused)) const ChangedElementsEvent & event) { + const Array & new_elements_list, const ElementTypeMapArray &, + const ChangedElementsEvent &) { // create a map to link old elements to new ones std::map old_to_new_elements; for (UInt el = 0; el < old_elements_list.size(); ++el) { AKANTU_DEBUG_ASSERT(old_to_new_elements.find(old_elements_list(el)) == old_to_new_elements.end(), "The same element cannot appear twice in the list"); old_to_new_elements[old_elements_list(el)] = new_elements_list(el); } substituteElements(old_to_new_elements); } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::onElementsRemoved( const Array & element_to_remove, const ElementTypeMapArray & new_numbering, - __attribute__((unused)) const RemovedElementsEvent & event) { + const RemovedElementsEvent &) { AKANTU_DEBUG_IN(); + this->removeElements(element_to_remove); this->renumberElements(new_numbering); + AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::buildPrankToElement() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); prank_to_element.initialize(mesh, _spatial_dimension = spatial_dimension, _element_kind = _ek_not_defined, - _with_nb_element = true, - _default_value = rank); + _with_nb_element = true, _default_value = rank); /// assign prank to all ghost elements - Communications::scheme_iterator recv_it = - communications.begin_recv_scheme(); - Communications::scheme_iterator recv_end = - communications.end_recv_scheme(); + auto recv_it = communications.begin_recv_scheme(); + auto recv_end = communications.end_recv_scheme(); for (; recv_it != recv_end; ++recv_it) { auto & recv = recv_it->second; auto proc = recv_it->first; for (auto & element : recv) { auto & prank_to_el = prank_to_element(element.type, element.ghost_type); prank_to_el(element.element) = proc; } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::filterElementsByKind( ElementSynchronizer * new_synchronizer, ElementKind kind) { AKANTU_DEBUG_IN(); auto filter_list = [&kind](Array & list, Array & new_list) { + auto copy = list; list.resize(0); new_list.resize(0); - Array copy = list; - Array::const_scalar_iterator it = copy.begin(); - Array::const_scalar_iterator end = copy.end(); - for (; it != end; ++it) { - const Element & el = *it; + for (auto && el : copy) { if (el.kind == kind) { new_list.push_back(el); } else { list.push_back(el); } } }; - Communications::scheme_iterator recv_it = - communications.begin_recv_scheme(); - Communications::scheme_iterator recv_end = - communications.end_recv_scheme(); - for (; recv_it != recv_end; ++recv_it) { - UInt proc = recv_it->first; - Array & recv = recv_it->second; - Array & new_recv = - new_synchronizer->communications.createRecvScheme(proc); - - filter_list(recv, new_recv); - } - - Communications::scheme_iterator send_it = - communications.begin_send_scheme(); - Communications::scheme_iterator send_end = - communications.end_send_scheme(); - for (; send_it != send_end; ++send_it) { - UInt proc = send_it->first; - Array & send = send_it->second; - Array & new_send = - new_synchronizer->communications.createSendScheme(proc); - - filter_list(send, new_send); + for (auto && sr : iterate_send_recv) { + for (auto && scheme_pair : communications.iterateSchemes(sr)) { + auto proc = scheme_pair.first; + auto & scheme = scheme_pair.second; + auto & new_scheme = + new_synchronizer->communications.createScheme(proc, sr); + filter_list(scheme, new_scheme); + } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::reset() { AKANTU_DEBUG_IN(); communications.resetSchemes(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::removeElements( const Array & element_to_remove) { AKANTU_DEBUG_IN(); std::vector send_requests; std::map> list_of_elements_per_proc; auto filter_list = [](const Array & keep, Array & list) { Array new_list; for (UInt e = 0; e < keep.size() - 1; ++e) { Element & el = list(keep(e)); new_list.push_back(el); } list.copy(new_list); }; // Handling ghost elements - Communications::scheme_iterator recv_it = - communications.begin_recv_scheme(); - Communications::scheme_iterator recv_end = - communications.end_recv_scheme(); - for (; recv_it != recv_end; ++recv_it) { - Array & recv = recv_it->second; - UInt proc = recv_it->first; - + for (auto && scheme_pair : communications.iterateSchemes(_recv)) { + auto proc = scheme_pair.first; + auto & recv = scheme_pair.second; Array & keep_list = list_of_elements_per_proc[proc]; - Array::const_iterator rem_it = element_to_remove.begin(); - Array::const_iterator rem_end = element_to_remove.end(); + auto rem_it = element_to_remove.begin(); + auto rem_end = element_to_remove.end(); + + for (auto && pair : enumerate(recv)) { + const auto & el = std::get<1>(pair); + auto pos = std::find(rem_it, rem_end, el); - Array::const_scalar_iterator it = recv.begin(); - Array::const_scalar_iterator end = recv.end(); - for (UInt e = 0; it != end; ++it, ++e) { - const Element & el = *it; - Array::const_iterator pos = - std::find(rem_it, rem_end, el); if (pos == rem_end) { - keep_list.push_back(e); + keep_list.push_back(std::get<0>(pair)); } } keep_list.push_back(UInt(-1)); // To no send empty arrays - Tag tag = Tag::genTag(proc, 0, Tag::_MODIFY_SCHEME, this->hash_id); + auto && tag = Tag::genTag(proc, 0, Tag::_MODIFY_SCHEME, this->hash_id); AKANTU_DEBUG_INFO("Sending a message of size " << keep_list.size() << " to proc " << proc << " TAG(" << tag << ")"); send_requests.push_back(this->communicator.asyncSend(keep_list, proc, tag)); - UInt old_size = recv.size(); + auto old_size = recv.size(); filter_list(keep_list, recv); AKANTU_DEBUG_INFO("I had " << old_size << " elements to recv from proc " << proc << " and " << keep_list.size() << " elements to keep. I have " << recv.size() << " elements left."); } - Communications::scheme_iterator send_it = - communications.begin_send_scheme(); - Communications::scheme_iterator send_end = - communications.end_send_scheme(); - for (; send_it != send_end; ++send_it) { - UInt proc = send_it->first; - Array send = send_it->second; + for (auto && scheme_pair : communications.iterateSchemes(_send)) { + auto proc = scheme_pair.first; + auto & send = scheme_pair.second; CommunicationStatus status; - Tag tag = Tag::genTag(rank, 0, Tag::_MODIFY_SCHEME, this->hash_id); + auto && tag = Tag::genTag(rank, 0, Tag::_MODIFY_SCHEME, this->hash_id); AKANTU_DEBUG_INFO("Getting number of elements of proc " << proc << " to keep - TAG(" << tag << ")"); this->communicator.probe(proc, tag, status); Array keep_list(status.size()); AKANTU_DEBUG_INFO("Receiving list of elements (" << keep_list.size() << " elements) to keep for proc " << proc << " TAG(" << tag << ")"); this->communicator.receive(keep_list, proc, tag); - UInt old_size = send.size(); + auto old_size = send.size(); filter_list(keep_list, send); AKANTU_DEBUG_INFO("I had " << old_size << " elements to send to proc " << proc << " and " << keep_list.size() << " elements to keep. I have " << send.size() << " elements left."); } this->communicator.waitAll(send_requests); this->communicator.freeCommunicationRequest(send_requests); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::renumberElements( const ElementTypeMapArray & new_numbering) { - - auto renumber = - [&new_numbering](Communications::scheme_iterator it, - Communications::scheme_iterator end) { - for (; it != end; ++it) { - Array & list = it->second; - Array::scalar_iterator el_it = list.begin(); - Array::scalar_iterator el_end = list.end(); - for (; el_it != el_end; ++el_it) { - Element & el = *el_it; - el.element = new_numbering(el.type, el.ghost_type)(el.element); - } - } - }; - - renumber(communications.begin_recv_scheme(), - communications.end_recv_scheme()); - renumber(communications.begin_send_scheme(), - communications.end_send_scheme()); + for(auto && sr : iterate_send_recv) { + for (auto && scheme_pair : communications.iterateSchemes(sr)) { + auto & list = scheme_pair.second; + for (auto && el : list) { + if(new_numbering.exists(el.type, el.ghost_type)) + el.element = new_numbering(el); + } + } + } } /* -------------------------------------------------------------------------- */ UInt ElementSynchronizer::sanityCheckDataSize( const Array & elements, const SynchronizationTag &) const { return (elements.size() * mesh.getSpatialDimension() * sizeof(Real) + sizeof(SynchronizationTag)); } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::packSanityCheckData( CommunicationDescriptor & comm_desc) const { - CommunicationBuffer & buffer = comm_desc.getBuffer(); + auto & buffer = comm_desc.getBuffer(); buffer << comm_desc.getTag(); - Communications::Scheme & send_element = comm_desc.getScheme(); + auto & send_element = comm_desc.getScheme(); /// pack barycenters in debug mode - Array::const_iterator bit = send_element.begin(); - Array::const_iterator bend = send_element.end(); - for (; bit != bend; ++bit) { - const Element & element = *bit; + for(auto && element : send_element) { Vector barycenter(mesh.getSpatialDimension()); mesh.getBarycenter(element.element, element.type, barycenter.storage(), element.ghost_type); buffer << barycenter; } } /* -------------------------------------------------------------------------- */ void ElementSynchronizer::unpackSanityCheckData( CommunicationDescriptor & comm_desc) const { - CommunicationBuffer & buffer = comm_desc.getBuffer(); - const SynchronizationTag & tag = comm_desc.getTag(); + auto & buffer = comm_desc.getBuffer(); + const auto & tag = comm_desc.getTag(); SynchronizationTag t; buffer >> t; AKANTU_DEBUG_ASSERT( t == tag, "The tag received does not correspond to the tag expected"); - Communications::Scheme & recv_element = comm_desc.getScheme(); - Array::const_iterator bit = recv_element.begin(); - Array::const_iterator bend = recv_element.end(); - - UInt spatial_dimension = mesh.getSpatialDimension(); - - for (; bit != bend; ++bit) { - const Element & element = *bit; + auto & recv_element = comm_desc.getScheme(); + auto spatial_dimension = mesh.getSpatialDimension(); + for(auto && element : recv_element) { Vector barycenter_loc(spatial_dimension); mesh.getBarycenter(element.element, element.type, barycenter_loc.storage(), element.ghost_type); Vector barycenter(spatial_dimension); buffer >> barycenter; for (UInt i = 0; i < spatial_dimension; ++i) { if (!Math::are_float_equal(barycenter_loc(i), barycenter(i))) 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)) << "] - tag: " << tag); } } } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/synchronizer/grid_synchronizer.cc b/src/synchronizer/grid_synchronizer.cc index cd521a566..38a760232 100644 --- a/src/synchronizer/grid_synchronizer.cc +++ b/src/synchronizer/grid_synchronizer.cc @@ -1,538 +1,543 @@ /** * @file grid_synchronizer.cc * * @author Aurelia Isabel Cuba Ramos * @author Nicolas Richart * * @date creation: Mon Oct 03 2011 * @date last modification: Fri Jan 22 2016 * * @brief implementation of the grid synchronizer * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "grid_synchronizer.hh" #include "aka_grid_dynamic.hh" #include "fe_engine.hh" #include "integration_point.hh" #include "mesh.hh" #include "mesh_io.hh" #include "static_communicator.hh" #include /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ template -void GridSynchronizer::createGridSynchronizer( - const SpatialGrid & grid) { +void GridSynchronizer::createGridSynchronizer(const SpatialGrid & grid) { AKANTU_DEBUG_IN(); const StaticCommunicator & comm = this->mesh.getCommunicator(); UInt nb_proc = comm.getNbProc(); UInt my_rank = comm.whoAmI(); - if (nb_proc == 1) return; + if (nb_proc == 1) + return; UInt spatial_dimension = this->mesh.getSpatialDimension(); Tensor3 bounding_boxes(spatial_dimension, 2, nb_proc); Matrix my_bounding_box = bounding_boxes(my_rank); - const Vector & lower = grid.getLowerBounds(); - const Vector & upper = grid.getUpperBounds(); - const Vector & spacing = grid.getSpacing(); + const auto & lower = grid.getLowerBounds(); + const auto & upper = grid.getUpperBounds(); + const auto & spacing = grid.getSpacing(); Vector(my_bounding_box(0)) = lower - spacing; Vector(my_bounding_box(1)) = upper + spacing; AKANTU_DEBUG_INFO( "Exchange of bounding box to detect the overlapping regions."); comm.allGather(bounding_boxes); std::vector intersects_proc(nb_proc); std::fill(intersects_proc.begin(), intersects_proc.end(), true); Matrix first_cells(spatial_dimension, nb_proc); Matrix last_cells(spatial_dimension, nb_proc); std::map> element_per_proc; // check the overlapping between my box and the one from other processors for (UInt p = 0; p < nb_proc; ++p) { if (p == my_rank) continue; Matrix proc_bounding_box = bounding_boxes(p); bool intersects = false; Vector first_cell_p = first_cells(p); Vector last_cell_p = last_cells(p); for (UInt s = 0; s < spatial_dimension; ++s) { // check overlapping of grid intersects = Math::intersects(my_bounding_box(s, 0), my_bounding_box(s, 1), proc_bounding_box(s, 0), proc_bounding_box(s, 1)); intersects_proc[p] = intersects_proc[p] & intersects; if (intersects) { AKANTU_DEBUG_INFO("I intersects with processor " << p << " in direction " << s); // is point 1 of proc p in the dimension s in the range ? bool point1 = Math::is_in_range(proc_bounding_box(s, 0), my_bounding_box(s, 0), my_bounding_box(s, 1)); // is point 2 of proc p in the dimension s in the range ? bool point2 = Math::is_in_range(proc_bounding_box(s, 1), my_bounding_box(s, 0), my_bounding_box(s, 1)); Real start = 0.; Real end = 0.; if (point1 && !point2) { /* |-----------| my_bounding_box(i) * |-----------| proc_bounding_box(i) * 1 2 */ start = proc_bounding_box(s, 0); end = my_bounding_box(s, 1); AKANTU_DEBUG_INFO("Intersection scheme 1 in direction " << s << " with processor " << p << " [" << start << ", " << end << "]"); } else if (point1 && point2) { /* |-----------------| my_bounding_box(i) * |-----------| proc_bounding_box(i) * 1 2 */ start = proc_bounding_box(s, 0); end = proc_bounding_box(s, 1); AKANTU_DEBUG_INFO("Intersection scheme 2 in direction " << s << " with processor " << p << " [" << start << ", " << end << "]"); } else if (!point1 && point2) { /* |-----------| my_bounding_box(i) * |-----------| proc_bounding_box(i) * 1 2 */ start = my_bounding_box(s, 0); end = proc_bounding_box(s, 1); AKANTU_DEBUG_INFO("Intersection scheme 3 in direction " << s << " with processor " << p << " [" << start << ", " << end << "]"); } else { /* |-----------| my_bounding_box(i) * |-----------------| proc_bounding_box(i) * 1 2 */ start = my_bounding_box(s, 0); end = my_bounding_box(s, 1); AKANTU_DEBUG_INFO("Intersection scheme 4 in direction " << s << " with processor " << p << " [" << start << ", " << end << "]"); } first_cell_p(s) = grid.getCellID(start, s); last_cell_p(s) = grid.getCellID(end, s); } } // create the list of cells in the overlapping using CellID = typename SpatialGrid::CellID; std::vector cell_ids; if (intersects_proc[p]) { AKANTU_DEBUG_INFO("I intersects with processor " << p); CellID cell_id(spatial_dimension); // for (UInt i = 0; i < spatial_dimension; ++i) { // if(first_cell_p[i] != 0) --first_cell_p[i]; // if(last_cell_p[i] != 0) ++last_cell_p[i]; // } for (Int fd = first_cell_p(0); fd <= last_cell_p(0); ++fd) { cell_id.setID(0, fd); if (spatial_dimension == 1) { cell_ids.push_back(cell_id); } else { for (Int sd = first_cell_p(1); sd <= last_cell_p(1); ++sd) { cell_id.setID(1, sd); if (spatial_dimension == 2) { cell_ids.push_back(cell_id); } else { for (Int ld = first_cell_p(2); ld <= last_cell_p(2); ++ld) { cell_id.setID(2, ld); cell_ids.push_back(cell_id); } } } } } // get the list of elements in the cells of the overlapping std::set to_send; for (auto & cur_cell_id : cell_ids) { auto & cell = grid.getCell(cur_cell_id); for (auto & element : cell) { to_send.insert(element); } } AKANTU_DEBUG_INFO("I have prepared " << to_send.size() << " elements to send to processor " << p); auto & scheme = this->getCommunications().createSendScheme(p); std::stringstream sstr; sstr << "element_per_proc_" << p; element_per_proc.emplace( std::piecewise_construct, std::forward_as_tuple(p), std::forward_as_tuple(sstr.str(), id, memory_id)); ElementTypeMapArray & elempproc = element_per_proc[p]; for (auto elem : to_send) { ElementType type = elem.type; UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); // /!\ this part must be slow due to the access in the // ElementTypeMapArray if (!elempproc.exists(type, _not_ghost)) elempproc.alloc(0, nb_nodes_per_element, type, _not_ghost); Vector global_connect(nb_nodes_per_element); Vector local_connect = mesh.getConnectivity(type).begin( nb_nodes_per_element)[elem.element]; for (UInt i = 0; i < nb_nodes_per_element; ++i) { global_connect(i) = mesh.getNodeGlobalId(local_connect(i)); AKANTU_DEBUG_ASSERT( global_connect(i) < mesh.getNbGlobalNodes(), "This global node send in the connectivity does not seem correct " << global_connect(i) << " corresponding to " << local_connect(i) << " from element " << elem.element); } elempproc(type).push_back(global_connect); scheme.push_back(elem); } } } AKANTU_DEBUG_INFO("I have finished to compute intersection," << " no it's time to communicate with my neighbors"); /** * Sending loop, sends the connectivity asynchronously to all concerned proc */ std::vector isend_requests; Tensor3 space(2, _max_element_type, nb_proc); for (UInt p = 0; p < nb_proc; ++p) { if (p == my_rank) continue; if (not intersects_proc[p]) continue; Matrix info_proc = space(p); auto & elempproc = element_per_proc[p]; UInt count = 0; for (auto type : elempproc.elementTypes(_all_dimensions, _not_ghost)) { Array & conn = elempproc(type, _not_ghost); Vector info = info_proc((UInt)type); info[0] = (UInt)type; info[1] = conn.size() * conn.getNbComponent(); AKANTU_DEBUG_INFO( "I have " << conn.size() << " elements of type " << type << " to send to processor " << p << " (communication tag : " << Tag::genTag(my_rank, count, DATA_TAG) << ")"); isend_requests.push_back( comm.asyncSend(info, p, Tag::genTag(my_rank, count, SIZE_TAG))); if (info[1] != 0) isend_requests.push_back(comm.asyncSend( conn, p, Tag::genTag(my_rank, count, DATA_TAG))); ++count; } Vector info = info_proc((UInt)_not_defined); info[0] = (UInt)_not_defined; info[1] = 0; isend_requests.push_back( comm.asyncSend(info, p, Tag::genTag(my_rank, count, SIZE_TAG))); } /** * Receives the connectivity and store them in the ghosts elements */ - auto & global_nodes_ids = const_cast &>(mesh.getGlobalNodesIds()); - auto & nodes_type = const_cast &>( - const_cast(mesh).getNodesType()); + MeshAccessor mesh_accessor(mesh); + auto & global_nodes_ids = mesh_accessor.getNodesGlobalIds(); + auto & nodes_type = mesh_accessor.getNodesType(); std::vector isend_nodes_requests; Vector nb_nodes_to_recv(nb_proc); UInt nb_total_nodes_to_recv = 0; UInt nb_current_nodes = global_nodes_ids.size(); NewNodesEvent new_nodes; NewElementsEvent new_elements; std::map> ask_nodes_per_proc; for (UInt p = 0; p < nb_proc; ++p) { nb_nodes_to_recv(p) = 0; if (p == my_rank) continue; if (!intersects_proc[p]) continue; auto & scheme = this->getCommunications().createRecvScheme(p); - ask_nodes_per_proc.emplace( - std::piecewise_construct, std::forward_as_tuple(p), - std::forward_as_tuple(0)); + ask_nodes_per_proc.emplace(std::piecewise_construct, + std::forward_as_tuple(p), + std::forward_as_tuple(0)); auto & ask_nodes = ask_nodes_per_proc[p]; UInt count = 0; ElementType type = _not_defined; do { Vector info(2); comm.receive(info, p, Tag::genTag(p, count, SIZE_TAG)); - type = (ElementType) info[0]; + type = (ElementType)info[0]; - if (type != _not_defined) { - UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); - UInt nb_element = info[1] / nb_nodes_per_element; - - Array tmp_conn(nb_element, nb_nodes_per_element); - tmp_conn.clear(); - if (info[1] != 0) - comm.receive(tmp_conn, p, Tag::genTag(p, count, DATA_TAG)); - - AKANTU_DEBUG_INFO("I will receive " - << nb_element << " elements of type " - << ElementType(info[0]) << " from processor " << p - << " (communication tag : " - << Tag::genTag(p, count, DATA_TAG) << ")"); - - auto & ghost_connectivity = - const_cast &>(mesh.getConnectivity(type, _ghost)); - - UInt nb_ghost_element = ghost_connectivity.size(); - Element element(type, 0, _ghost); - - Vector conn(nb_nodes_per_element); - for (UInt el = 0; el < nb_element; ++el) { - UInt nb_node_to_ask_for_elem = 0; - - for (UInt n = 0; n < nb_nodes_per_element; ++n) { - UInt gn = tmp_conn(el, n); - UInt ln = global_nodes_ids.find(gn); - - AKANTU_DEBUG_ASSERT(gn < mesh.getNbGlobalNodes(), - "This global node seems not correct " - << gn << " from element " << el << " node " - << n); - - if (ln == UInt(-1)) { - global_nodes_ids.push_back(gn); - nodes_type.push_back(_nt_pure_gost); // pure ghost node - ln = nb_current_nodes; - - new_nodes.getList().push_back(ln); - ++nb_current_nodes; - ask_nodes.push_back(gn); - ++nb_node_to_ask_for_elem; - } - conn[n] = ln; - } + if (type == _not_defined) + break; - // all the nodes are already known locally, the element should - // already exists - auto c = UInt(-1); - if (nb_node_to_ask_for_elem == 0) { - c = ghost_connectivity.find(conn); - element.element = c; - } + UInt nb_nodes_per_element = mesh.getNbNodesPerElement(type); + UInt nb_element = info[1] / nb_nodes_per_element; + + Array tmp_conn(nb_element, nb_nodes_per_element); + tmp_conn.clear(); + if (info[1] != 0) + comm.receive(tmp_conn, p, Tag::genTag(p, count, DATA_TAG)); + + AKANTU_DEBUG_INFO("I will receive " + << nb_element << " elements of type " + << ElementType(info[0]) << " from processor " << p + << " (communication tag : " + << Tag::genTag(p, count, DATA_TAG) << ")"); + + auto & ghost_connectivity = mesh_accessor.getConnectivity(type, _ghost); + auto & ghost_counter = mesh_accessor.getGhostsCounters(type, _ghost); + + UInt nb_ghost_element = ghost_connectivity.size(); + Element element(type, 0, _ghost); - if (c == UInt(-1)) { - element.element = nb_ghost_element; - ++nb_ghost_element; - ghost_connectivity.push_back(conn); - new_elements.getList().push_back(element); + Vector conn(nb_nodes_per_element); + for (UInt el = 0; el < nb_element; ++el) { + UInt nb_node_to_ask_for_elem = 0; + + for (UInt n = 0; n < nb_nodes_per_element; ++n) { + UInt gn = tmp_conn(el, n); + UInt ln = global_nodes_ids.find(gn); + + AKANTU_DEBUG_ASSERT(gn < mesh.getNbGlobalNodes(), + "This global node seems not correct " + << gn << " from element " << el << " node " + << n); + + if (ln == UInt(-1)) { + global_nodes_ids.push_back(gn); + nodes_type.push_back(_nt_pure_gost); // pure ghost node + ln = nb_current_nodes; + + new_nodes.getList().push_back(ln); + ++nb_current_nodes; + ask_nodes.push_back(gn); + ++nb_node_to_ask_for_elem; } + conn[n] = ln; + } - scheme.push_back(element); + // all the nodes are already known locally, the element should + // already exists + auto c = UInt(-1); + if (nb_node_to_ask_for_elem == 0) { + c = ghost_connectivity.find(conn); + element.element = c; } + + if (c == UInt(-1)) { + element.element = nb_ghost_element; + ++nb_ghost_element; + ghost_connectivity.push_back(conn); + ghost_counter.push_back(1); + new_elements.getList().push_back(element); + } else { + ++ghost_counter(c); + } + + scheme.push_back(element); } + count++; } while (type != _not_defined); AKANTU_DEBUG_INFO("I have " << ask_nodes.size() << " missing nodes for elements coming from processor " << p << " (communication tag : " << Tag::genTag(my_rank, 0, ASK_NODES_TAG) << ")"); ask_nodes.push_back(UInt(-1)); isend_nodes_requests.push_back( comm.asyncSend(ask_nodes, p, Tag::genTag(my_rank, 0, ASK_NODES_TAG))); nb_nodes_to_recv(p) = ask_nodes.size() - 1; nb_total_nodes_to_recv += nb_nodes_to_recv(p); } comm.waitAll(isend_requests); comm.freeCommunicationRequest(isend_requests); /** * Sends requested nodes to proc */ auto & nodes = const_cast &>(mesh.getNodes()); UInt nb_nodes = nodes.size(); std::vector isend_coordinates_requests; std::map> nodes_to_send_per_proc; for (UInt p = 0; p < nb_proc; ++p) { if (p == my_rank || !intersects_proc[p]) continue; Array asked_nodes; CommunicationStatus status; AKANTU_DEBUG_INFO("Waiting list of nodes to send to processor " << p << "(communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); comm.probe(p, Tag::genTag(p, 0, ASK_NODES_TAG), status); UInt nb_nodes_to_send = status.size(); asked_nodes.resize(nb_nodes_to_send); AKANTU_DEBUG_INFO("I have " << nb_nodes_to_send - 1 << " nodes to send to processor " << p << " (communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); AKANTU_DEBUG_INFO("Getting list of nodes to send to processor " << p << " (communication tag : " << Tag::genTag(p, 0, ASK_NODES_TAG) << ")"); comm.receive(asked_nodes, p, Tag::genTag(p, 0, ASK_NODES_TAG)); nb_nodes_to_send--; asked_nodes.resize(nb_nodes_to_send); - nodes_to_send_per_proc.emplace( - std::piecewise_construct, std::forward_as_tuple(p), - std::forward_as_tuple(0, spatial_dimension)); + nodes_to_send_per_proc.emplace(std::piecewise_construct, + std::forward_as_tuple(p), + std::forward_as_tuple(0, spatial_dimension)); auto & nodes_to_send = nodes_to_send_per_proc[p]; auto node_it = nodes.begin(spatial_dimension); for (UInt n = 0; n < nb_nodes_to_send; ++n) { UInt ln = global_nodes_ids.find(asked_nodes(n)); AKANTU_DEBUG_ASSERT(ln != UInt(-1), "The node [" << asked_nodes(n) << "] requested by proc " << p << " was not found locally!"); nodes_to_send.push_back(node_it + ln); } if (nb_nodes_to_send != 0) { AKANTU_DEBUG_INFO("Sending the " << nb_nodes_to_send << " nodes to processor " << p << " (communication tag : " << Tag::genTag(p, 0, SEND_NODES_TAG) << ")"); isend_coordinates_requests.push_back(comm.asyncSend( nodes_to_send, p, Tag::genTag(my_rank, 0, SEND_NODES_TAG))); } #if not defined(AKANTU_NDEBUG) else { AKANTU_DEBUG_INFO("No nodes to send to processor " << p); } #endif } comm.waitAll(isend_nodes_requests); comm.freeCommunicationRequest(isend_nodes_requests); nodes.resize(nb_total_nodes_to_recv + nb_nodes); for (UInt p = 0; p < nb_proc; ++p) { if ((p != my_rank) && (nb_nodes_to_recv(p) > 0)) { AKANTU_DEBUG_INFO("Receiving the " << nb_nodes_to_recv(p) << " nodes from processor " << p << " (communication tag : " << Tag::genTag(p, 0, SEND_NODES_TAG) << ")"); Vector nodes_to_recv(nodes.storage() + nb_nodes * spatial_dimension, nb_nodes_to_recv(p) * spatial_dimension); comm.receive(nodes_to_recv, p, Tag::genTag(p, 0, SEND_NODES_TAG)); nb_nodes += nb_nodes_to_recv(p); } #if not defined(AKANTU_NDEBUG) else { if (p != my_rank) { AKANTU_DEBUG_INFO("No nodes to receive from processor " << p); } } #endif } comm.waitAll(isend_coordinates_requests); comm.freeCommunicationRequest(isend_coordinates_requests); mesh.sendEvent(new_nodes); mesh.sendEvent(new_elements); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void GridSynchronizer::createGridSynchronizer( const SpatialGrid & grid); template void GridSynchronizer::createGridSynchronizer( const SpatialGrid & grid); } // namespace akantu diff --git a/src/synchronizer/master_element_info_per_processor.cc b/src/synchronizer/master_element_info_per_processor.cc index 194c058d6..19be6953f 100644 --- a/src/synchronizer/master_element_info_per_processor.cc +++ b/src/synchronizer/master_element_info_per_processor.cc @@ -1,482 +1,462 @@ /** * @file master_element_info_per_processor.cc * * @author Nicolas Richart * * @date Fri Mar 11 14:57:13 2016 * * @brief * * @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_iterators.hh" -#include "mesh_iterators.hh" #include "element_group.hh" #include "element_info_per_processor.hh" #include "element_synchronizer.hh" +#include "mesh_iterators.hh" #include "mesh_utils.hh" #include "static_communicator.hh" /* -------------------------------------------------------------------------- */ #include #include #include #include /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ MasterElementInfoPerProc::MasterElementInfoPerProc( ElementSynchronizer & synchronizer, UInt message_cnt, UInt root, ElementType type, const MeshPartition & partition) : ElementInfoPerProc(synchronizer, message_cnt, root, type), partition(partition), all_nb_local_element(nb_proc, 0), all_nb_ghost_element(nb_proc, 0), all_nb_element_to_send(nb_proc, 0) { Vector size(5); size(0) = (UInt)type; if (type != _not_defined) { nb_nodes_per_element = Mesh::getNbNodesPerElement(type); nb_element = mesh.getNbElement(type); - const Array & partition_num = + const auto & partition_num = this->partition.getPartition(this->type, _not_ghost); - const CSR & ghost_partition = + const auto & ghost_partition = this->partition.getGhostPartitionCSR()(this->type, _not_ghost); for (UInt el = 0; el < nb_element; ++el) { this->all_nb_local_element[partition_num(el)]++; - for (CSR::const_iterator part = ghost_partition.begin(el); + for (auto part = ghost_partition.begin(el); part != ghost_partition.end(el); ++part) { this->all_nb_ghost_element[*part]++; } this->all_nb_element_to_send[partition_num(el)] += ghost_partition.getNbCols(el) + 1; } /// tag info std::vector tag_names; this->getMeshData().getTagNames(tag_names, type); this->nb_tags = tag_names.size(); size(4) = nb_tags; for (UInt p = 0; p < nb_proc; ++p) { if (p != root) { size(1) = this->all_nb_local_element[p]; size(2) = this->all_nb_ghost_element[p]; size(3) = this->all_nb_element_to_send[p]; AKANTU_DEBUG_INFO( "Sending connectivities informations to proc " << p << " TAG(" << Tag::genTag(this->rank, this->message_count, Tag::_SIZES) << ")"); comm.send(size, p, Tag::genTag(this->rank, this->message_count, Tag::_SIZES)); } else { this->nb_local_element = this->all_nb_local_element[p]; this->nb_ghost_element = this->all_nb_ghost_element[p]; } } } else { for (UInt p = 0; p < this->nb_proc; ++p) { if (p != this->root) { AKANTU_DEBUG_INFO( "Sending empty connectivities informations to proc " << p << " TAG(" << Tag::genTag(this->rank, this->message_count, Tag::_SIZES) << ")"); comm.send(size, p, Tag::genTag(this->rank, this->message_count, Tag::_SIZES)); } } } } /* ------------------------------------------------------------------------ */ void MasterElementInfoPerProc::synchronizeConnectivities() { - const Array & partition_num = + const auto & partition_num = this->partition.getPartition(this->type, _not_ghost); - const CSR & ghost_partition = + const auto & ghost_partition = this->partition.getGhostPartitionCSR()(this->type, _not_ghost); std::vector> buffers(this->nb_proc); auto conn_it = this->mesh.getConnectivity(this->type, _not_ghost) .begin(this->nb_nodes_per_element); auto conn_end = this->mesh.getConnectivity(this->type, _not_ghost) .end(this->nb_nodes_per_element); /// copying the local connectivity auto part_it = partition_num.begin(); for (; conn_it != conn_end; ++conn_it, ++part_it) { const auto & conn = *conn_it; for (UInt i = 0; i < conn.size(); ++i) { buffers[*part_it].push_back(conn[i]); } } /// copying the connectivity of ghost element conn_it = this->mesh.getConnectivity(this->type, _not_ghost) .begin(this->nb_nodes_per_element); for (UInt el = 0; conn_it != conn_end; ++el, ++conn_it) { for (auto part = ghost_partition.begin(el); part != ghost_partition.end(el); ++part) { UInt proc = *part; const Vector & conn = *conn_it; for (UInt i = 0; i < conn.size(); ++i) { buffers[proc].push_back(conn[i]); } } } #ifndef AKANTU_NDEBUG for (UInt p = 0; p < this->nb_proc; ++p) { UInt size = this->nb_nodes_per_element * (this->all_nb_local_element[p] + this->all_nb_ghost_element[p]); AKANTU_DEBUG_ASSERT( buffers[p].size() == size, "The connectivity data packed in the buffer are not correct"); } #endif /// send all connectivity and ghost information to all processors std::vector requests; for (UInt p = 0; p < this->nb_proc; ++p) { - if (p != this->root) { - AKANTU_DEBUG_INFO( - "Sending connectivities to proc " - << p << " TAG(" - << Tag::genTag(this->rank, this->message_count, Tag::_CONNECTIVITY) - << ")"); - requests.push_back(comm.asyncSend( - buffers[p], p, - Tag::genTag(this->rank, this->message_count, Tag::_CONNECTIVITY))); - } + if (p == this->root) + continue; + auto && tag = + Tag::genTag(this->rank, this->message_count, Tag::_CONNECTIVITY); + AKANTU_DEBUG_INFO("Sending connectivities to proc " << p << " TAG(" << tag + << ")"); + requests.push_back(comm.asyncSend(buffers[p], p, tag)); } Array & old_nodes = this->getNodesGlobalIds(); /// create the renumbered connectivity AKANTU_DEBUG_INFO("Renumbering local connectivities"); MeshUtils::renumberMeshNodes(mesh, buffers[root], all_nb_local_element[root], all_nb_ghost_element[root], type, old_nodes); + comm.waitAll(requests); comm.freeCommunicationRequest(requests); } /* ------------------------------------------------------------------------ */ void MasterElementInfoPerProc::synchronizePartitions() { - const Array & partition_num = + const auto & partition_num = this->partition.getPartition(this->type, _not_ghost); - const CSR & ghost_partition = + const auto & ghost_partition = this->partition.getGhostPartitionCSR()(this->type, _not_ghost); std::vector> buffers(this->partition.getNbPartition()); /// splitting the partition information to send them to processors Vector count_by_proc(nb_proc, 0); for (UInt el = 0; el < nb_element; ++el) { UInt proc = partition_num(el); buffers[proc].push_back(ghost_partition.getNbCols(el)); UInt i(0); - for (CSR::const_iterator part = ghost_partition.begin(el); - part != ghost_partition.end(el); ++part, ++i) { + for (auto part = ghost_partition.begin(el); part != ghost_partition.end(el); + ++part, ++i) { buffers[proc].push_back(*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) { + for (auto part = ghost_partition.begin(el); part != ghost_partition.end(el); + ++part, ++i) { buffers[*part].push_back(partition_num(el)); } } #ifndef AKANTU_NDEBUG for (UInt p = 0; p < this->nb_proc; ++p) { - AKANTU_DEBUG_ASSERT( - buffers[p].size() == - (this->all_nb_ghost_element[p] + this->all_nb_element_to_send[p]), - "Data stored in the buffer are most probably wrong"); + AKANTU_DEBUG_ASSERT(buffers[p].size() == (this->all_nb_ghost_element[p] + + this->all_nb_element_to_send[p]), + "Data stored in the buffer are most probably wrong"); } #endif std::vector requests; /// last data to compute the communication scheme for (UInt p = 0; p < this->nb_proc; ++p) { - if (p != this->root) { - AKANTU_DEBUG_INFO( - "Sending partition informations to proc " - << p << " TAG(" - << Tag::genTag(this->rank, this->message_count, Tag::_PARTITIONS) - << ")"); - requests.push_back(comm.asyncSend( - buffers[p], p, - Tag::genTag(this->rank, this->message_count, Tag::_PARTITIONS))); - } + if (p == this->root) + continue; + + auto && tag = + Tag::genTag(this->rank, this->message_count, Tag::_PARTITIONS); + AKANTU_DEBUG_INFO("Sending partition informations to proc " << p << " TAG(" + << tag << ")"); + requests.push_back(comm.asyncSend(buffers[p], p, tag)); } if (Mesh::getSpatialDimension(this->type) == this->mesh.getSpatialDimension()) { AKANTU_DEBUG_INFO("Creating communications scheme"); this->fillCommunicationScheme(buffers[this->rank]); } comm.waitAll(requests); comm.freeCommunicationRequest(requests); } /* -------------------------------------------------------------------------- */ void MasterElementInfoPerProc::synchronizeTags() { AKANTU_DEBUG_IN(); if (this->nb_tags == 0) { AKANTU_DEBUG_OUT(); return; } UInt mesh_data_sizes_buffer_length; - MeshData & mesh_data = this->getMeshData(); + auto & mesh_data = this->getMeshData(); /// tag info std::vector tag_names; mesh_data.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()); // 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); + for (auto && tag_name : tag_names) { + mesh_data_sizes_buffer << tag_name; + mesh_data_sizes_buffer << mesh_data.getTypeCode(tag_name); + mesh_data_sizes_buffer << mesh_data.getNbComponent(tag_name, type); } mesh_data_sizes_buffer_length = mesh_data_sizes_buffer.size(); 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, 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, root); if (mesh_data_sizes_buffer_length != 0) { // Sending the actual data to each processor - DynamicCommunicationBuffer * buffers = - new DynamicCommunicationBuffer[nb_proc]; - std::vector::const_iterator names_it = tag_names.begin(); - std::vector::const_iterator names_end = tag_names.end(); - + std::vector buffers(nb_proc); // Loop over each tag for the current type - for (; names_it != names_end; ++names_it) { + for (auto && tag_name : tag_names) { // Type code of the current tag (i.e. the tag named *names_it) - this->fillTagBuffer(buffers, *names_it); + this->fillTagBuffer(buffers, tag_name); } std::vector requests; for (UInt p = 0; p < nb_proc; ++p) { - if (p != root) { - AKANTU_DEBUG_INFO("Sending " - << buffers[p].size() - << " bytes of mesh data to proc " << p << " TAG(" - << Tag::genTag(this->rank, this->message_count, - Tag::_MESH_DATA) - << ")"); - - requests.push_back(comm.asyncSend( - buffers[p], p, - Tag::genTag(this->rank, this->message_count, Tag::_MESH_DATA))); - } + if (p == root) + continue; + + auto && tag = + Tag::genTag(this->rank, this->message_count, Tag::_MESH_DATA); + AKANTU_DEBUG_INFO("Sending " << buffers[p].size() + << " bytes of mesh data to proc " << p + << " TAG(" << tag << ")"); + + requests.push_back(comm.asyncSend(buffers[p], p, tag)); } - names_it = tag_names.begin(); // Loop over each tag for the current type - for (; names_it != names_end; ++names_it) { + for (auto && tag_name : tag_names) { // Reinitializing the mesh data on the master - this->fillMeshData(buffers[root], *names_it, - mesh_data.getTypeCode(*names_it), - mesh_data.getNbComponent(*names_it, type)); + this->fillMeshData(buffers[root], tag_name, + mesh_data.getTypeCode(tag_name), + mesh_data.getNbComponent(tag_name, type)); } comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); - delete[] buffers; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void MasterElementInfoPerProc::fillTagBufferTemplated( - DynamicCommunicationBuffer * buffers, const std::string & tag_name) { + std::vector & buffers, + const std::string & tag_name) { MeshData & mesh_data = this->getMeshData(); - const Array & data = mesh_data.getElementalDataArray(tag_name, type); - const Array & partition_num = + const auto & data = mesh_data.getElementalDataArray(tag_name, type); + const auto & partition_num = this->partition.getPartition(this->type, _not_ghost); - const CSR & ghost_partition = + const auto & ghost_partition = this->partition.getGhostPartitionCSR()(this->type, _not_ghost); // Not possible to use the iterator because it potentially triggers the // creation of complex // type templates (such as akantu::Vector< std::vector > which don't // implement the right interface // (e.g. operator<< in that case). // typename Array::template const_iterator< Vector > data_it = // data.begin(data.getNbComponent()); // typename Array::template const_iterator< Vector > data_end = // data.end(data.getNbComponent()); const T * data_it = data.storage(); const T * data_end = data.storage() + data.size() * data.getNbComponent(); const UInt * part = partition_num.storage(); /// copying the data, element by element for (; data_it != data_end; ++part) { for (UInt j(0); j < data.getNbComponent(); ++j, ++data_it) { buffers[*part] << *data_it; } } data_it = data.storage(); /// copying the data for the ghost element for (UInt el(0); data_it != data_end; data_it += data.getNbComponent(), ++el) { - CSR::const_iterator it = ghost_partition.begin(el); - CSR::const_iterator end = ghost_partition.end(el); + auto it = ghost_partition.begin(el); + auto end = ghost_partition.end(el); for (; it != end; ++it) { UInt proc = *it; for (UInt j(0); j < data.getNbComponent(); ++j) { buffers[proc] << data_it[j]; } } } } /* -------------------------------------------------------------------------- */ void MasterElementInfoPerProc::fillTagBuffer( - DynamicCommunicationBuffer * buffers, const std::string & tag_name) { + std::vector & buffers, + const std::string & tag_name) { MeshData & mesh_data = this->getMeshData(); #define AKANTU_DISTRIBUTED_SYNHRONIZER_TAG_DATA(r, extra_param, elem) \ case BOOST_PP_TUPLE_ELEM(2, 0, elem): { \ this->fillTagBufferTemplated(buffers, \ tag_name); \ 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 MasterElementInfoPerProc::synchronizeGroups() { AKANTU_DEBUG_IN(); - DynamicCommunicationBuffer * buffers = - new DynamicCommunicationBuffer[nb_proc]; + std::vector buffers(nb_proc); using ElementToGroup = std::vector>; - ElementToGroup element_to_group; - element_to_group.resize(nb_element); + ElementToGroup element_to_group(nb_element); for (auto & eg : ElementGroupsIterable(mesh)) { - const std::string & name = eg.getName(); + const auto & name = eg.getName(); for (const auto & element : eg.getElements(type, _not_ghost)) { element_to_group[element].push_back(name); } auto eit = eg.begin(type, _not_ghost); if (eit != eg.end(type, _not_ghost)) const_cast &>(eg.getElements(type)).empty(); } const auto & partition_num = this->partition.getPartition(this->type, _not_ghost); const auto & ghost_partition = this->partition.getGhostPartitionCSR()(this->type, _not_ghost); /// copying the data, element by element - ElementToGroup::const_iterator data_it = element_to_group.begin(); - ElementToGroup::const_iterator data_end = element_to_group.end(); - for (auto pair : zip(partition_num, element_to_group)) { + for (auto && pair : zip(partition_num, element_to_group)) { buffers[std::get<0>(pair)] << std::get<1>(pair); } - data_it = element_to_group.begin(); /// copying the data for the ghost element - for (UInt el(0); data_it != data_end; ++data_it, ++el) { - CSR::const_iterator it = ghost_partition.begin(el); - CSR::const_iterator end = ghost_partition.end(el); + for (auto && pair : enumerate(element_to_group)) { + auto && el = std::get<0>(pair); + auto it = ghost_partition.begin(el); + auto end = ghost_partition.end(el); for (; it != end; ++it) { UInt proc = *it; - buffers[proc] << *data_it; + buffers[proc] << std::get<1>(pair); } } std::vector requests; for (UInt p = 0; p < this->nb_proc; ++p) { if (p == this->rank) continue; - AKANTU_DEBUG_INFO("Sending element groups to proc " - << p << " TAG(" - << Tag::genTag(this->rank, p, Tag::_ELEMENT_GROUP) - << ")"); - requests.push_back(comm.asyncSend( - buffers[p], p, Tag::genTag(this->rank, p, Tag::_ELEMENT_GROUP))); + + auto && tag = Tag::genTag(this->rank, p, Tag::_ELEMENT_GROUP); + AKANTU_DEBUG_INFO("Sending element groups to proc " << p << " TAG(" << tag + << ")"); + requests.push_back(comm.asyncSend(buffers[p], p, tag)); } this->fillElementGroupsFromBuffer(buffers[this->rank]); comm.waitAll(requests); comm.freeCommunicationRequest(requests); requests.clear(); - delete[] buffers; AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/synchronizer/real_static_communicator.hh b/src/synchronizer/real_static_communicator.hh index cdc1bbc13..c9fd88e0c 100644 --- a/src/synchronizer/real_static_communicator.hh +++ b/src/synchronizer/real_static_communicator.hh @@ -1,151 +1,135 @@ /** * @file real_static_communicator.hh * * @author Nicolas Richart * * @date creation: Mon Jun 14 2010 * @date last modification: Wed Jan 13 2016 * * @brief empty class just for inheritance * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "aka_common.hh" /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_REAL_STATIC_COMMUNICATOR_HH__ #define __AKANTU_REAL_STATIC_COMMUNICATOR_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ class InternalCommunicationRequest { public: InternalCommunicationRequest(UInt source, UInt dest); virtual ~InternalCommunicationRequest(); virtual void printself(std::ostream & stream, int indent = 0) const; AKANTU_GET_MACRO(Source, source, UInt); AKANTU_GET_MACRO(Destination, destination, UInt); private: UInt source; UInt destination; UInt id; static UInt counter; }; /* -------------------------------------------------------------------------- */ class CommunicationRequest { public: CommunicationRequest( std::shared_ptr request = nullptr) : request(std::move(request)) {} - // CommunicationRequest(CommunicationRequest & other) - // : request(std::move(other.request)) {} - - // CommunicationRequest(CommunicationRequest && other) - // : request(std::move(other.request)) {} - - // CommunicationRequest & operator=(CommunicationRequest & other) { - // request = std::move(other.request); - // return *this; - // } - - // CommunicationRequest & operator=(CommunicationRequest && other) { - // request = std::move(other.request); - // return *this; - // } - virtual void free() { request.reset(); } void printself(std::ostream & stream, int indent = 0) const { request->printself(stream, indent); }; UInt getSource() const { return request->getSource(); } UInt getDestination() const { return request->getDestination(); } bool isFreed() const { return request.get() == nullptr; } InternalCommunicationRequest & getInternal() { return *request; } private: std::shared_ptr request; }; /* -------------------------------------------------------------------------- */ class CommunicationStatus { public: AKANTU_GET_MACRO(Source, source, Int); UInt size() const { return size_; } AKANTU_GET_MACRO(Tag, tag, Int); AKANTU_SET_MACRO(Source, source, Int); AKANTU_SET_MACRO(Size, size_, UInt); AKANTU_SET_MACRO(Tag, tag, Int); private: Int source{0}; UInt size_{0}; Int tag{0}; }; /* -------------------------------------------------------------------------- */ /// Datatype to pack pairs for MPI_{MIN,MAX}LOC template struct SCMinMaxLoc { T1 min_max; T2 loc; }; /* -------------------------------------------------------------------------- */ class StaticCommunicator; /* -------------------------------------------------------------------------- */ class RealStaticCommunicator { public: RealStaticCommunicator(__attribute__((unused)) int & argc, __attribute__((unused)) char **& argv) { prank = -1; psize = -1; }; virtual ~RealStaticCommunicator(){}; friend class StaticCommunicator; Int getNbProc() { return this->psize; } Int whoAmI() { return this->prank; } protected: Int prank; Int psize; }; } // akantu #endif /* __AKANTU_REAL_STATIC_COMMUNICATOR_HH__ */ diff --git a/src/synchronizer/slave_element_info_per_processor.cc b/src/synchronizer/slave_element_info_per_processor.cc index 88c3e9f55..b7746421d 100644 --- a/src/synchronizer/slave_element_info_per_processor.cc +++ b/src/synchronizer/slave_element_info_per_processor.cc @@ -1,197 +1,197 @@ /** * @file slave_element_info_per_processor.cc * * @author Nicolas Richart * * @date Fri Mar 11 14:59:21 2016 * * @brief * * @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 "element_info_per_processor.hh" #include "element_synchronizer.hh" #include "mesh_utils.hh" #include "static_communicator.hh" /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ SlaveElementInfoPerProc::SlaveElementInfoPerProc( ElementSynchronizer & synchronizer, UInt message_cnt, UInt root) : ElementInfoPerProc(synchronizer, message_cnt, root, _not_defined) { Vector size(5); comm.receive(size, this->root, Tag::genTag(this->root, this->message_count, Tag::_SIZES)); this->type = (ElementType)size[0]; this->nb_local_element = size[1]; this->nb_ghost_element = size[2]; this->nb_element_to_receive = size[3]; this->nb_tags = size[4]; if (this->type != _not_defined) this->nb_nodes_per_element = Mesh::getNbNodesPerElement(type); } /* -------------------------------------------------------------------------- */ bool SlaveElementInfoPerProc::needSynchronize() { return this->type != _not_defined; } /* -------------------------------------------------------------------------- */ void SlaveElementInfoPerProc::synchronizeConnectivities() { Array local_connectivity( (this->nb_local_element + this->nb_ghost_element) * this->nb_nodes_per_element); AKANTU_DEBUG_INFO("Receiving connectivities from proc " << root); comm.receive( local_connectivity, this->root, Tag::genTag(this->root, this->message_count, Tag::_CONNECTIVITY)); - Array & old_nodes = this->getNodesGlobalIds(); + auto & old_nodes = this->getNodesGlobalIds(); AKANTU_DEBUG_INFO("Renumbering local connectivities"); MeshUtils::renumberMeshNodes(this->mesh, local_connectivity, this->nb_local_element, this->nb_ghost_element, this->type, old_nodes); } /* -------------------------------------------------------------------------- */ void SlaveElementInfoPerProc::synchronizePartitions() { Array local_partitions(this->nb_element_to_receive + this->nb_ghost_element * 2); AKANTU_DEBUG_INFO("Receiving partition informations from proc " << root); this->comm.receive(local_partitions, this->root, Tag::genTag(root, this->message_count, Tag::_PARTITIONS)); if (Mesh::getSpatialDimension(this->type) == this->mesh.getSpatialDimension()) { AKANTU_DEBUG_INFO("Creating communications scheme"); this->fillCommunicationScheme(local_partitions); } } /* -------------------------------------------------------------------------- */ void SlaveElementInfoPerProc::synchronizeTags() { AKANTU_DEBUG_IN(); if (this->nb_tags == 0) { AKANTU_DEBUG_OUT(); return; } /* --------<<<<-TAGS------------------------------------------------- */ UInt mesh_data_sizes_buffer_length = 0; CommunicationBuffer mesh_data_sizes_buffer; AKANTU_DEBUG_INFO( "Receiving the size of the information about the mesh data tags."); comm.broadcast(mesh_data_sizes_buffer_length, 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, 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, this->message_count, Tag::_MESH_DATA) << ")"); comm.probe(root, Tag::genTag(root, this->message_count, Tag::_MESH_DATA), mesh_data_comm_status); UInt mesh_data_buffer_size(mesh_data_comm_status.size()); AKANTU_DEBUG_INFO("Receiving " << mesh_data_buffer_size << " bytes of mesh data TAG(" << Tag::genTag(root, this->message_count, Tag::_MESH_DATA) << ")"); mesh_data_buffer.resize(mesh_data_buffer_size); comm.receive(mesh_data_buffer, root, Tag::genTag(root, this->message_count, Tag::_MESH_DATA)); // Loop over each tag for the current type UInt k(0); for (; names_it != names_end; ++names_it, ++k) { this->fillMeshData(mesh_data_buffer, *names_it, tag_type_codes[k], tag_nb_component[k]); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SlaveElementInfoPerProc::synchronizeGroups() { AKANTU_DEBUG_IN(); StaticCommunicator & comm = StaticCommunicator::getStaticCommunicator(); UInt my_rank = comm.whoAmI(); AKANTU_DEBUG_INFO("Receiving element groups from proc " << root << " TAG(" << Tag::genTag(root, my_rank, Tag::_ELEMENT_GROUP) << ")"); CommunicationStatus status; comm.probe(root, Tag::genTag(root, my_rank, Tag::_ELEMENT_GROUP), status); CommunicationBuffer buffer(status.size()); comm.receive(buffer, root, Tag::genTag(root, my_rank, Tag::_ELEMENT_GROUP)); this->fillElementGroupsFromBuffer(buffer); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ } // akantu diff --git a/src/synchronizer/static_communicator_mpi.cc b/src/synchronizer/static_communicator_mpi.cc index fb931b9d7..7a6452c7b 100644 --- a/src/synchronizer/static_communicator_mpi.cc +++ b/src/synchronizer/static_communicator_mpi.cc @@ -1,557 +1,559 @@ /** * @file static_communicator_mpi.cc * * @author Nicolas Richart * * @date creation: Sun Sep 26 2010 * @date last modification: Thu Jan 21 2016 * * @brief StaticCommunicatorMPI implementation * * @section LICENSE * * Copyright (©) 2010-2012, 2014, 2015 EPFL (Ecole Polytechnique Fédérale de * Lausanne) Laboratory (LSMS - Laboratoire de Simulation en Mécanique des * Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include /* -------------------------------------------------------------------------- */ +#include "aka_iterators.hh" #include "mpi_type_wrapper.hh" #include "static_communicator_mpi.hh" - /* -------------------------------------------------------------------------- */ namespace akantu { MPI_Op MPITypeWrapper::synchronizer_operation_to_mpi_op[_so_null + 1] = { MPI_SUM, MPI_MIN, MPI_MAX, MPI_PROD, MPI_LAND, MPI_BAND, MPI_LOR, MPI_BOR, MPI_LXOR, MPI_BXOR, MPI_MINLOC, MPI_MAXLOC, MPI_OP_NULL}; class CommunicationRequestMPI : public InternalCommunicationRequest { public: CommunicationRequestMPI(UInt source, UInt dest); MPI_Request & getMPIRequest() { return *request; }; private: std::unique_ptr request; }; /* -------------------------------------------------------------------------- */ /* Implementation */ /* -------------------------------------------------------------------------- */ CommunicationRequestMPI::CommunicationRequestMPI(UInt source, UInt dest) : InternalCommunicationRequest(source, dest), request(new MPI_Request) {} /* -------------------------------------------------------------------------- */ StaticCommunicatorMPI::StaticCommunicatorMPI(int & argc, char **& argv) : RealStaticCommunicator(argc, argv) { int is_initialized = false; MPI_Initialized(&is_initialized); if (!is_initialized) { MPI_Init(&argc, &argv); } this->is_externaly_initialized = is_initialized; mpi_data = new MPITypeWrapper(*this); mpi_data->setMPICommunicator(MPI_COMM_WORLD); } /* -------------------------------------------------------------------------- */ StaticCommunicatorMPI::~StaticCommunicatorMPI() { if (!this->is_externaly_initialized) { MPI_Finalize(); delete this->mpi_data; } } /* -------------------------------------------------------------------------- */ template void StaticCommunicatorMPI::send(T * buffer, Int size, Int receiver, Int tag) { MPI_Comm communicator = mpi_data->getMPICommunicator(); MPI_Datatype type = MPITypeWrapper::getMPIDatatype(); #if !defined(AKANTU_NDEBUG) int ret = #endif MPI_Send(buffer, size, type, receiver, tag, communicator); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Send."); } /* -------------------------------------------------------------------------- */ template void StaticCommunicatorMPI::receive(T * buffer, Int size, Int sender, Int tag) { MPI_Comm communicator = mpi_data->getMPICommunicator(); MPI_Status status; MPI_Datatype type = MPITypeWrapper::getMPIDatatype(); #if !defined(AKANTU_NDEBUG) int ret = #endif MPI_Recv(buffer, size, type, sender, tag, communicator, &status); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Recv."); } /* -------------------------------------------------------------------------- */ template CommunicationRequest StaticCommunicatorMPI::asyncSend(T * buffer, Int size, Int receiver, Int tag) { MPI_Comm communicator = mpi_data->getMPICommunicator(); CommunicationRequestMPI * request = new CommunicationRequestMPI(prank, receiver); MPI_Datatype type = MPITypeWrapper::getMPIDatatype(); MPI_Request & req = request->getMPIRequest(); #if !defined(AKANTU_NDEBUG) int ret = #endif MPI_Isend(buffer, size, type, receiver, tag, communicator, &req); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Isend."); return std::shared_ptr(request); } /* -------------------------------------------------------------------------- */ template CommunicationRequest StaticCommunicatorMPI::asyncReceive(T * buffer, Int size, Int sender, Int tag) { MPI_Comm communicator = mpi_data->getMPICommunicator(); CommunicationRequestMPI * request = new CommunicationRequestMPI(sender, prank); MPI_Datatype type = MPITypeWrapper::getMPIDatatype(); MPI_Request & req = request->getMPIRequest(); #if !defined(AKANTU_NDEBUG) int ret = #endif MPI_Irecv(buffer, size, type, sender, tag, communicator, &req); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Irecv."); return std::shared_ptr(request); } /* -------------------------------------------------------------------------- */ template void StaticCommunicatorMPI::probe(Int sender, Int tag, CommunicationStatus & status) { MPI_Comm communicator = mpi_data->getMPICommunicator(); MPI_Status mpi_status; #if !defined(AKANTU_NDEBUG) int ret = #endif MPI_Probe(sender, tag, communicator, &mpi_status); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Probe."); MPI_Datatype type = MPITypeWrapper::getMPIDatatype(); int count; MPI_Get_count(&mpi_status, type, &count); status.setSource(mpi_status.MPI_SOURCE); status.setTag(mpi_status.MPI_TAG); status.setSize(count); } /* -------------------------------------------------------------------------- */ bool StaticCommunicatorMPI::testRequest(CommunicationRequest & request) { MPI_Status status; int flag; CommunicationRequestMPI & req_mpi = dynamic_cast(request.getInternal()); MPI_Request & req = req_mpi.getMPIRequest(); #if !defined(AKANTU_NDEBUG) int ret = #endif MPI_Test(&req, &flag, &status); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Test."); return (flag != 0); } /* -------------------------------------------------------------------------- */ void StaticCommunicatorMPI::wait(CommunicationRequest & request) { MPI_Status status; CommunicationRequestMPI & req_mpi = dynamic_cast(request.getInternal()); MPI_Request & req = req_mpi.getMPIRequest(); #if !defined(AKANTU_NDEBUG) int ret = #endif MPI_Wait(&req, &status); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Wait."); } /* -------------------------------------------------------------------------- */ void StaticCommunicatorMPI::waitAll( std::vector & requests) { MPI_Status status; std::vector::iterator it; for (it = requests.begin(); it != requests.end(); ++it) { MPI_Request & req = dynamic_cast(it->getInternal()) .getMPIRequest(); #if !defined(AKANTU_NDEBUG) int ret = #endif MPI_Wait(&req, &status); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Wait."); } } /* -------------------------------------------------------------------------- */ UInt StaticCommunicatorMPI::waitAny( std::vector & requests) { MPI_Status status; - std::vector reqs(requests.size()); - UInt r = 0; - for (auto it = requests.begin(); it != requests.end(); ++it, ++r) { - reqs[r] = static_cast(&it->getInternal()) - ->getMPIRequest(); + std::vector mpi_requests(requests.size()); + + for (auto && request_pair : zip(requests, mpi_requests)) { + auto && req = std::get<0>(request_pair); + auto && mpi_req = std::get<1>(request_pair); + mpi_req = dynamic_cast(req.getInternal()).getMPIRequest(); } int pos; #if !defined(AKANTU_NDEBUG) int ret = #endif - MPI_Waitany(requests.size(), reqs.data(), &pos, &status); + MPI_Waitany(mpi_requests.size(), mpi_requests.data(), &pos, &status); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Wait."); if (pos != MPI_UNDEFINED) { return pos; } else { return UInt(-1); } } /* -------------------------------------------------------------------------- */ void StaticCommunicatorMPI::barrier() { MPI_Comm communicator = mpi_data->getMPICommunicator(); MPI_Barrier(communicator); } /* -------------------------------------------------------------------------- */ template void StaticCommunicatorMPI::reduce(T * values, int nb_values, const SynchronizerOperation & op, int root) { MPI_Comm communicator = mpi_data->getMPICommunicator(); MPI_Datatype type = MPITypeWrapper::getMPIDatatype(); #if !defined(AKANTU_NDEBUG) int ret = #endif MPI_Reduce(MPI_IN_PLACE, values, nb_values, type, MPITypeWrapper::getMPISynchronizerOperation(op), root, communicator); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Allreduce."); } /* -------------------------------------------------------------------------- */ template void StaticCommunicatorMPI::allReduce(T * values, int nb_values, const SynchronizerOperation & op) { MPI_Comm communicator = mpi_data->getMPICommunicator(); MPI_Datatype type = MPITypeWrapper::getMPIDatatype(); #if !defined(AKANTU_NDEBUG) int ret = #endif MPI_Allreduce(MPI_IN_PLACE, values, nb_values, type, MPITypeWrapper::getMPISynchronizerOperation(op), communicator); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Allreduce."); } /* -------------------------------------------------------------------------- */ template void StaticCommunicatorMPI::allGather(T * values, int nb_values) { MPI_Comm communicator = mpi_data->getMPICommunicator(); MPI_Datatype type = MPITypeWrapper::getMPIDatatype(); #if !defined(AKANTU_NDEBUG) int ret = #endif MPI_Allgather(MPI_IN_PLACE, nb_values, type, values, nb_values, type, communicator); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Allgather."); } /* -------------------------------------------------------------------------- */ template void StaticCommunicatorMPI::allGatherV(T * values, int * nb_values) { MPI_Comm communicator = mpi_data->getMPICommunicator(); int * displs = new int[psize]; displs[0] = 0; for (int i = 1; i < psize; ++i) { displs[i] = displs[i - 1] + nb_values[i - 1]; } MPI_Datatype type = MPITypeWrapper::getMPIDatatype(); #if !defined(AKANTU_NDEBUG) int ret = #endif MPI_Allgatherv(MPI_IN_PLACE, *nb_values, type, values, nb_values, displs, type, communicator); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Gather."); delete[] displs; } /* -------------------------------------------------------------------------- */ template void StaticCommunicatorMPI::gather(T * values, int nb_values, int root) { MPI_Comm communicator = mpi_data->getMPICommunicator(); T *send_buf = NULL, *recv_buf = NULL; if (prank == root) { send_buf = (T *)MPI_IN_PLACE; recv_buf = values; } else { send_buf = values; } MPI_Datatype type = MPITypeWrapper::getMPIDatatype(); #if !defined(AKANTU_NDEBUG) int ret = #endif MPI_Gather(send_buf, nb_values, type, recv_buf, nb_values, type, root, communicator); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Gather."); } /* -------------------------------------------------------------------------- */ template void StaticCommunicatorMPI::gather(T * values, int nb_values, T * gathered, int nb_gathered) { MPI_Comm communicator = mpi_data->getMPICommunicator(); T * send_buf = values; T * recv_buf = gathered; if (nb_gathered == 0) nb_gathered = nb_values; MPI_Datatype type = MPITypeWrapper::getMPIDatatype(); #if !defined(AKANTU_NDEBUG) int ret = #endif MPI_Gather(send_buf, nb_values, type, recv_buf, nb_gathered, type, this->prank, communicator); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Gather."); } /* -------------------------------------------------------------------------- */ template void StaticCommunicatorMPI::gatherV(T * values, int * nb_values, int root) { MPI_Comm communicator = mpi_data->getMPICommunicator(); int * displs = NULL; if (prank == root) { displs = new int[psize]; displs[0] = 0; for (int i = 1; i < psize; ++i) { displs[i] = displs[i - 1] + nb_values[i - 1]; } } T *send_buf = NULL, *recv_buf = NULL; if (prank == root) { send_buf = (T *)MPI_IN_PLACE; recv_buf = values; } else send_buf = values; MPI_Datatype type = MPITypeWrapper::getMPIDatatype(); #if !defined(AKANTU_NDEBUG) int ret = #endif MPI_Gatherv(send_buf, *nb_values, type, recv_buf, nb_values, displs, type, root, communicator); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Gather."); if (prank == root) { delete[] displs; } } /* -------------------------------------------------------------------------- */ template void StaticCommunicatorMPI::broadcast(T * values, int nb_values, int root) { MPI_Comm communicator = mpi_data->getMPICommunicator(); MPI_Datatype type = MPITypeWrapper::getMPIDatatype(); #if !defined(AKANTU_NDEBUG) int ret = #endif MPI_Bcast(values, nb_values, type, root, communicator); AKANTU_DEBUG_ASSERT(ret == MPI_SUCCESS, "Error in MPI_Gather."); } /* -------------------------------------------------------------------------- */ int StaticCommunicatorMPI::getMaxTag() { return this->mpi_data->getMaxTag(); } /* -------------------------------------------------------------------------- */ int StaticCommunicatorMPI::getMinTag() { return 0; } /* -------------------------------------------------------------------------- */ // template // MPI_Datatype StaticCommunicatorMPI::getMPIDatatype() { // return MPI_DATATYPE_NULL; // } template <> MPI_Datatype MPITypeWrapper::getMPIDatatype() { return MPI_CHAR; } template <> MPI_Datatype MPITypeWrapper::getMPIDatatype() { return MPI_FLOAT; } template <> MPI_Datatype MPITypeWrapper::getMPIDatatype() { return MPI_DOUBLE; } template <> MPI_Datatype MPITypeWrapper::getMPIDatatype() { return MPI_LONG_DOUBLE; } template <> MPI_Datatype MPITypeWrapper::getMPIDatatype() { return MPI_INT; } template <> MPI_Datatype MPITypeWrapper::getMPIDatatype() { return MPITypeWrapper::getMPIDatatype(); } template <> MPI_Datatype MPITypeWrapper::getMPIDatatype() { return MPI_UNSIGNED; } template <> MPI_Datatype MPITypeWrapper::getMPIDatatype() { return MPI_LONG; } template <> MPI_Datatype MPITypeWrapper::getMPIDatatype() { return MPI_UNSIGNED_LONG; } template <> MPI_Datatype MPITypeWrapper::getMPIDatatype() { return MPI_LONG_LONG; } template <> MPI_Datatype MPITypeWrapper::getMPIDatatype() { return MPI_UNSIGNED_LONG_LONG; } template <> MPI_Datatype MPITypeWrapper::getMPIDatatype>() { return MPI_DOUBLE_INT; } template <> MPI_Datatype MPITypeWrapper::getMPIDatatype>() { return MPI_FLOAT_INT; } -template <> -MPI_Datatype MPITypeWrapper::getMPIDatatype() { +template <> MPI_Datatype MPITypeWrapper::getMPIDatatype() { return MPI_CXX_BOOL; } -/* -------------------------------------------------------------------------- */ -/* Template instantiation */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- + */ + /* Template instantiation */ + /* -------------------------------------------------------------------------- + */ #define AKANTU_MPI_COMM_INSTANTIATE(T) \ template void StaticCommunicatorMPI::send(T * buffer, Int size, \ Int receiver, Int tag); \ template void StaticCommunicatorMPI::receive(T * buffer, Int size, \ Int sender, Int tag); \ template CommunicationRequest StaticCommunicatorMPI::asyncSend( \ T * buffer, Int size, Int receiver, Int tag); \ template CommunicationRequest StaticCommunicatorMPI::asyncReceive( \ T * buffer, Int size, Int sender, Int tag); \ template void StaticCommunicatorMPI::probe(Int sender, Int tag, \ CommunicationStatus & status); \ template void StaticCommunicatorMPI::allGather(T * values, \ int nb_values); \ template void StaticCommunicatorMPI::allGatherV(T * values, \ int * nb_values); \ template void StaticCommunicatorMPI::gather(T * values, int nb_values, \ int root); \ template void StaticCommunicatorMPI::gather( \ T * values, int nb_values, T * gathered, int nb_gathered); \ template void StaticCommunicatorMPI::gatherV(T * values, int * nb_values, \ int root); \ template void StaticCommunicatorMPI::broadcast(T * values, int nb_values, \ int root); \ template void StaticCommunicatorMPI::allReduce( \ T * values, int nb_values, const SynchronizerOperation & op) AKANTU_MPI_COMM_INSTANTIATE(bool); AKANTU_MPI_COMM_INSTANTIATE(Real); AKANTU_MPI_COMM_INSTANTIATE(UInt); AKANTU_MPI_COMM_INSTANTIATE(Int); AKANTU_MPI_COMM_INSTANTIATE(char); AKANTU_MPI_COMM_INSTANTIATE(NodeType); template void StaticCommunicatorMPI::send>( SCMinMaxLoc * buffer, Int size, Int receiver, Int tag); template void StaticCommunicatorMPI::receive>( SCMinMaxLoc * buffer, Int size, Int sender, Int tag); template CommunicationRequest StaticCommunicatorMPI::asyncSend>( SCMinMaxLoc * buffer, Int size, Int receiver, Int tag); template CommunicationRequest StaticCommunicatorMPI::asyncReceive>( SCMinMaxLoc * buffer, Int size, Int sender, Int tag); template void StaticCommunicatorMPI::probe>( Int sender, Int tag, CommunicationStatus & status); template void StaticCommunicatorMPI::allGather>( SCMinMaxLoc * values, int nb_values); template void StaticCommunicatorMPI::allGatherV>( SCMinMaxLoc * values, int * nb_values); template void StaticCommunicatorMPI::gather>( SCMinMaxLoc * values, int nb_values, int root); template void StaticCommunicatorMPI::gatherV>( SCMinMaxLoc * values, int * nb_values, int root); template void StaticCommunicatorMPI::broadcast>( SCMinMaxLoc * values, int nb_values, int root); template void StaticCommunicatorMPI::allReduce>( SCMinMaxLoc * values, int nb_values, const SynchronizerOperation & op); #if AKANTU_INTEGER_SIZE > 4 AKANTU_MPI_COMM_INSTANTIATE(int); #endif -} // akantu +} // namespace akantu diff --git a/src/synchronizer/synchronizer_impl_tmpl.hh b/src/synchronizer/synchronizer_impl_tmpl.hh index 745956dee..18563ba05 100644 --- a/src/synchronizer/synchronizer_impl_tmpl.hh +++ b/src/synchronizer/synchronizer_impl_tmpl.hh @@ -1,286 +1,250 @@ /** * @file synchronizer_impl_tmpl.hh * * @author Nicolas Richart * * @date Wed Aug 24 13:29:47 2016 * * @brief Implementation of the SynchronizerImpl * * @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 "synchronizer_impl.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SYNCHRONIZER_IMPL_TMPL_HH__ #define __AKANTU_SYNCHRONIZER_IMPL_TMPL_HH__ namespace akantu { /* -------------------------------------------------------------------------- */ template SynchronizerImpl::SynchronizerImpl(const ID & id, MemoryID memory_id, const StaticCommunicator & comm) : Synchronizer(id, memory_id, comm), communications(comm) {} /* -------------------------------------------------------------------------- */ template void SynchronizerImpl::synchronizeOnceImpl( DataAccessor & data_accessor, const SynchronizationTag & tag) const { - AKANTU_DEBUG_IN(); - // no need to synchronize - if (this->nb_proc == 1) { - AKANTU_DEBUG_OUT(); + if (this->nb_proc == 1) return; - } - typedef std::vector CommunicationRequests; - typedef std::map CommunicationBuffers; + using CommunicationRequests = std::vector; + using CommunicationBuffers = std::map; CommunicationRequests send_requests, recv_requests; CommunicationBuffers send_buffers, recv_buffers; auto postComm = [&](const CommunicationSendRecv & sr, CommunicationBuffers & buffers, CommunicationRequests & requests) -> void { - auto sit = this->communications.begin_scheme(sr); - auto send = this->communications.end_scheme(sr); - - for (; sit != send; ++sit) { - const auto & scheme = sit->second; - auto & proc = sit->first; + for (auto && pair : communications.iterateSchemes(sr)) { + auto & proc = pair.first; + const auto & scheme = pair.second; auto & buffer = buffers[proc]; UInt buffer_size = data_accessor.getNbData(scheme, tag); buffer.resize(buffer_size); if (sr == _recv) { requests.push_back(communicator.asyncReceive( buffer, proc, Tag::genTag(this->rank, 0, Tag::_SYNCHRONIZE, this->hash_id))); } else { data_accessor.packData(buffer, scheme, tag); send_requests.push_back(communicator.asyncSend( buffer, proc, Tag::genTag(proc, 0, Tag::_SYNCHRONIZE, this->hash_id))); } } }; // post the receive requests postComm(_recv, recv_buffers, recv_requests); - // send the data + // post the send data requests postComm(_send, send_buffers, send_requests); // treat the receive requests UInt request_ready; while ((request_ready = communicator.waitAny(recv_requests)) != UInt(-1)) { CommunicationRequest & req = recv_requests[request_ready]; UInt proc = req.getSource(); CommunicationBuffer & buffer = recv_buffers[proc]; const auto & scheme = this->communications.getScheme(proc, _recv); data_accessor.unpackData(buffer, scheme, tag); req.free(); recv_requests.erase(recv_requests.begin() + request_ready); } communicator.waitAll(send_requests); communicator.freeCommunicationRequest(send_requests); - //communicator.freeCommunicationRequest(recv_requests); - AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void SynchronizerImpl::asynchronousSynchronizeImpl( const DataAccessor & data_accessor, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); if (!this->communications.hasCommunication(tag)) this->computeBufferSize(data_accessor, tag); this->communications.incrementCounter(tag); // Posting the receive ------------------------------------------------------- if (this->communications.hasPendingRecv(tag)) { AKANTU_CUSTOM_EXCEPTION_INFO( debug::CommunicationException(), "There must still be some pending receive communications." << " Tag is " << tag << " Cannot start new ones"); } - auto recv_it = this->communications.begin_recv(tag); - auto recv_end = this->communications.end_recv(tag); - for (; recv_it != recv_end; ++recv_it) { - auto comm_desc = *recv_it; + for (auto && comm_desc : this->communications.iterateRecv(tag)) { comm_desc.postRecv(this->hash_id); } // Posting the sends ------------------------------------------------------- if (communications.hasPendingSend(tag)) { AKANTU_CUSTOM_EXCEPTION_INFO( debug::CommunicationException(), "There must be some pending sending communications." << " Tag is " << tag); } - auto send_it = communications.begin_send(tag); - auto send_end = communications.end_send(tag); - for (; send_it != send_end; ++send_it) { - auto comm_desc = *send_it; + for (auto && comm_desc : this->communications.iterateSend(tag)) { comm_desc.resetBuffer(); #ifndef AKANTU_NDEBUG this->packSanityCheckData(comm_desc); #endif comm_desc.packData(data_accessor); comm_desc.postSend(this->hash_id); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void SynchronizerImpl::waitEndSynchronizeImpl( DataAccessor & data_accessor, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); #ifndef AKANTU_NDEBUG if (this->communications.begin_recv(tag) != - this->communications.end_recv(tag) && + this->communications.end_recv(tag) && !this->communications.hasPendingRecv(tag)) - AKANTU_CUSTOM_EXCEPTION_INFO(debug::CommunicationException(), + AKANTU_CUSTOM_EXCEPTION_INFO(debug::CommunicationException(), "No pending communication with the tag \"" << tag); #endif auto recv_end = this->communications.end_recv(tag); decltype(recv_end) recv_it; while ((recv_it = this->communications.waitAnyRecv(tag)) != recv_end) { - auto comm_desc = *recv_it; + auto && comm_desc = *recv_it; #ifndef AKANTU_NDEBUG this->unpackSanityCheckData(comm_desc); #endif comm_desc.unpackData(data_accessor); comm_desc.resetBuffer(); comm_desc.freeRequest(); } this->communications.waitAllSend(tag); this->communications.freeSendRequests(tag); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template void SynchronizerImpl::computeAllBufferSizes( const DataAccessor & data_accessor) { - auto it = this->communications.begin_tag(); - auto end = this->communications.end_tag(); - - for (; it != end; ++it) { - auto tag = *it; + for (auto && tag : this->communications.iterateTags()) { this->computeBufferSize(data_accessor, tag); } } /* -------------------------------------------------------------------------- */ template void SynchronizerImpl::computeBufferSizeImpl( const DataAccessor & data_accessor, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); this->communications.initializeCommunications(tag); AKANTU_DEBUG_ASSERT(communications.hasCommunication(tag) == true, "Communications where not properly initialized"); - auto recv_it = this->communications.begin_recv_scheme(); - auto recv_end = this->communications.end_recv_scheme(); - for (; recv_it != recv_end; ++recv_it) { - auto proc = recv_it->first; - auto & scheme = recv_it->second; - UInt srecv = 0; + for (auto && sr : iterate_send_recv) { + for (auto && pair : this->communications.iterateSchemes(sr)) { + auto proc = pair.first; + auto & scheme = pair.second; + UInt size = 0; #ifndef AKANTU_NDEBUG - srecv += this->sanityCheckDataSize(scheme, tag); + size += this->sanityCheckDataSize(scheme, tag); #endif - srecv += data_accessor.getNbData(scheme, tag); - AKANTU_DEBUG_INFO("I have " << srecv << "(" << printMemorySize(srecv) - << " - " << scheme.size() - << " element(s)) data to receive from " << proc - << " for tag " << tag); - this->communications.setRecvCommunicationSize(tag, proc, srecv); - } - - auto send_it = this->communications.begin_send_scheme(); - auto send_end = this->communications.end_send_scheme(); - for (; send_it != send_end; ++send_it) { - auto proc = send_it->first; - auto & scheme = send_it->second; - UInt ssend = 0; -#ifndef AKANTU_NDEBUG - ssend += this->sanityCheckDataSize(scheme, tag); -#endif - ssend += data_accessor.getNbData(scheme, tag); - AKANTU_DEBUG_INFO("I have " << ssend << "(" << printMemorySize(ssend) - << " - " << scheme.size() - << " element(s)) data to send to " << proc - << " for tag " << tag); - this->communications.setSendCommunicationSize(tag, proc, ssend); + size += data_accessor.getNbData(scheme, tag); + AKANTU_DEBUG_INFO("I have " + << size << "(" << printMemorySize(size) << " - " + << scheme.size() << " element(s)) data to " + << std::string(sr == _recv ? "receive from" : "send to") + << proc << " for tag " << tag); + this->communications.setCommunicationSize(tag, proc, size, sr); + } } - AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ template UInt SynchronizerImpl::sanityCheckDataSize( const Array &, const SynchronizationTag &) const { return 0; } /* -------------------------------------------------------------------------- */ template void SynchronizerImpl::packSanityCheckData( CommunicationDescriptor &) const {} /* -------------------------------------------------------------------------- */ template void SynchronizerImpl::unpackSanityCheckData( CommunicationDescriptor &) const {} /* -------------------------------------------------------------------------- */ -} // akantu +} // namespace akantu #endif /* __AKANTU_SYNCHRONIZER_IMPL_TMPL_HH__ */ diff --git a/test/test_model/test_non_local_toolbox/test_build_neighborhood_parallel.cc b/test/test_model/test_non_local_toolbox/test_build_neighborhood_parallel.cc index 08cb77e51..756685754 100644 --- a/test/test_model/test_non_local_toolbox/test_build_neighborhood_parallel.cc +++ b/test/test_model/test_non_local_toolbox/test_build_neighborhood_parallel.cc @@ -1,195 +1,191 @@ /** * @file test_build_neighborhood_parallel.cc * * @author Aurelia Isabel Cuba Ramos * * @date creation: Sat Sep 26 2015 * @date last modification: Wed Nov 25 2015 * * @brief test in parallel for the class NonLocalNeighborhood * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "dumper_paraview.hh" #include "non_local_neighborhood_base.hh" #include "solid_mechanics_model.hh" #include "test_material.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; /* -------------------------------------------------------------------------- */ int main(int argc, char * argv[]) { akantu::initialize("material_parallel_test.dat", argc, argv); - StaticCommunicator & comm = - akantu::StaticCommunicator::getStaticCommunicator(); + auto & comm = akantu::StaticCommunicator::getStaticCommunicator(); Int psize = comm.getNbProc(); Int prank = comm.whoAmI(); // some configuration variables const UInt spatial_dimension = 2; // mesh creation and read Mesh mesh(spatial_dimension); if (prank == 0) { mesh.read("parallel_test.msh"); } mesh.distribute(); /// model creation SolidMechanicsModel model(mesh); /// dump the ghost elements before the non-local part is intialized DumperParaview dumper_ghost("ghost_elements"); dumper_ghost.registerMesh(mesh, spatial_dimension, _ghost); if (psize > 1) { dumper_ghost.dump(); } /// creation of material selector - MeshDataMaterialSelector * mat_selector; - mat_selector = - new MeshDataMaterialSelector("physical_names", model); - model.setMaterialSelector(*mat_selector); + MeshDataMaterialSelector mat_selector("physical_names", model); + model.setMaterialSelector(mat_selector); /// dump material index in paraview model.addDumpField("partitions"); model.dump(); /// model initialization changed to use our material model.initFull(); /// dump the ghost elements after ghosts for non-local have been added if (psize > 1) dumper_ghost.dump(); model.addDumpField("grad_u"); model.addDumpField("grad_u non local"); model.addDumpField("material_index"); /// apply constant strain field everywhere in the plate Matrix applied_strain(spatial_dimension, spatial_dimension); applied_strain.clear(); for (UInt i = 0; i < spatial_dimension; ++i) applied_strain(i, i) = 2.; ElementType element_type = _triangle_3; GhostType ghost_type = _not_ghost; /// apply constant grad_u field in all elements for (UInt m = 0; m < model.getNbMaterials(); ++m) { - Material & mat = model.getMaterial(m); - Array & grad_u = const_cast &>( + auto & mat = model.getMaterial(m); + auto & grad_u = const_cast &>( mat.getInternal("grad_u")(element_type, ghost_type)); - Array::iterator> grad_u_it = - grad_u.begin(spatial_dimension, spatial_dimension); - Array::iterator> grad_u_end = - grad_u.end(spatial_dimension, spatial_dimension); + auto grad_u_it = grad_u.begin(spatial_dimension, spatial_dimension); + auto grad_u_end = grad_u.end(spatial_dimension, spatial_dimension); for (; grad_u_it != grad_u_end; ++grad_u_it) - (*grad_u_it) += applied_strain; + (*grad_u_it) = -1. * applied_strain; } /// double the strain in the center: find the closed gauss point to the center /// compute the quadrature points ElementTypeMapReal quad_coords("quad_coords"); quad_coords.initialize(mesh, _nb_component = spatial_dimension, - _spatial_dimension = spatial_dimension, _with_nb_element = true); + _spatial_dimension = spatial_dimension, + _with_nb_element = true); model.getFEEngine().computeIntegrationPointsCoordinates(quad_coords); Vector center(spatial_dimension, 0.); Mesh::type_iterator it = mesh.firstType(spatial_dimension, _not_ghost, _ek_regular); Mesh::type_iterator last_type = mesh.lastType(spatial_dimension, _not_ghost, _ek_regular); Real min_distance = 2; IntegrationPoint q_min; for (; it != last_type; ++it) { ElementType type = *it; UInt nb_elements = mesh.getNbElement(type, _not_ghost); UInt nb_quads = model.getFEEngine().getNbIntegrationPoints(type); Array & coords = quad_coords(type, _not_ghost); Array::const_vector_iterator coord_it = coords.begin(spatial_dimension); for (UInt e = 0; e < nb_elements; ++e) { for (UInt q = 0; q < nb_quads; ++q, ++coord_it) { Real dist = center.distance(*coord_it); if (dist < min_distance) { min_distance = dist; q_min.element = e; q_min.num_point = q; q_min.global_num = nb_elements * nb_quads + q; q_min.type = type; } } } } Real global_min = min_distance; comm.allReduce(global_min, _so_min); if (Math::are_float_equal(global_min, min_distance)) { UInt mat_index = model.getMaterialByElement(q_min.type, _not_ghost) .begin()[q_min.element]; Material & mat = model.getMaterial(mat_index); UInt nb_quads = model.getFEEngine().getNbIntegrationPoints(q_min.type); UInt local_el_index = model.getMaterialLocalNumbering(q_min.type, _not_ghost) .begin()[q_min.element]; UInt local_num = (local_el_index * nb_quads) + q_min.num_point; Array & grad_u = const_cast &>( mat.getInternal("grad_u")(q_min.type, _not_ghost)); Array::iterator> grad_u_it = grad_u.begin(spatial_dimension, spatial_dimension); grad_u_it += local_num; Matrix & g_u = *grad_u_it; g_u += applied_strain; } /// compute the non-local strains model.assembleInternalForces(); model.dump(); /// damage the element with higher grad_u completely, so that it is /// not taken into account for the averaging if (Math::are_float_equal(global_min, min_distance)) { UInt mat_index = model.getMaterialByElement(q_min.type, _not_ghost) .begin()[q_min.element]; Material & mat = model.getMaterial(mat_index); UInt nb_quads = model.getFEEngine().getNbIntegrationPoints(q_min.type); UInt local_el_index = model.getMaterialLocalNumbering(q_min.type, _not_ghost) .begin()[q_min.element]; UInt local_num = (local_el_index * nb_quads) + q_min.num_point; Array & damage = const_cast &>( mat.getInternal("damage")(q_min.type, _not_ghost)); Real * dam_ptr = damage.storage(); dam_ptr += local_num; *dam_ptr = 0.9; } /// compute the non-local strains model.assembleInternalForces(); model.dump(); finalize(); return EXIT_SUCCESS; } diff --git a/test/test_model/test_non_local_toolbox/test_material.cc b/test/test_model/test_non_local_toolbox/test_material.cc index 31d6851ec..09ddac51c 100644 --- a/test/test_model/test_non_local_toolbox/test_material.cc +++ b/test/test_model/test_non_local_toolbox/test_material.cc @@ -1,56 +1,56 @@ /** * @file test_material.cc * * @author Aurelia Isabel Cuba Ramos * * @date creation: Sat Sep 26 2015 * @date last modification: Wed Nov 25 2015 * * @brief Implementation of test material for the non-local neighborhood base * test * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "test_material.hh" /* -------------------------------------------------------------------------- */ template TestMaterial::TestMaterial(SolidMechanicsModel & model, const ID & id) : Parent(model, id), grad_u_nl("grad_u non local", *this) { this->is_non_local = true; this->grad_u_nl.initialize(dim * dim); } /* -------------------------------------------------------------------------- */ template void TestMaterial::registerNonLocalVariables() { this->model.getNonLocalManager().registerNonLocalVariable( this->gradu.getName(), grad_u_nl.getName(), dim * dim); - this->model.getNonLocalManager().getNeighborhood("test_region") + this->model.getNonLocalManager().getNeighborhood(this->getNeighborhoodName()) .registerNonLocalVariable(grad_u_nl.getName()); } /* -------------------------------------------------------------------------- */ // Instantiate the material for the 3 dimensions INSTANTIATE_MATERIAL(test_material, TestMaterial); /* -------------------------------------------------------------------------- */ diff --git a/test/test_model/test_non_local_toolbox/test_material_damage.hh b/test/test_model/test_non_local_toolbox/test_material_damage.hh index 3e1d5b4b8..34fd74407 100644 --- a/test/test_model/test_non_local_toolbox/test_material_damage.hh +++ b/test/test_model/test_non_local_toolbox/test_material_damage.hh @@ -1,72 +1,72 @@ /** * @file test_material_damage.hh * * @author Aurelia Isabel Cuba Ramos * * @date creation: Thu Feb 21 2013 * @date last modification: Thu Oct 15 2015 * * @brief test material damage for the non-local remove damage test * * @section LICENSE * * Copyright (©) 2014, 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "material_damage.hh" #include "material_damage_non_local.hh" /* -------------------------------------------------------------------------- */ #ifndef __TEST_MATERIAL_DAMAGE_HH__ #define __TEST_MATERIAL_DAMAGE_HH__ using namespace akantu; template class TestMaterialDamage : public MaterialDamageNonLocal> { using Parent = MaterialDamageNonLocal>; /* ------------------------------------------------------------------------ */ /* Constructor/Destructor */ /* ------------------------------------------------------------------------ */ public: TestMaterialDamage(SolidMechanicsModel & model, const ID & id); /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: void registerNonLocalVariables() override final; void computeNonLocalStress(ElementType, GhostType) override final {}; void insertQuadsInNeighborhoods(GhostType ghost_type); protected: - ID getNeighborhoodName() override { return "test_region"; } + //ID getNeighborhoodName() override { return "test_region"; } /* ------------------------------------------------------------------------ */ /* Members */ /* ------------------------------------------------------------------------ */ private: InternalField grad_u_nl; }; #endif /* __TEST_MATERIAL_DAMAGE_HH__ */ diff --git a/test/test_model/test_non_local_toolbox/test_remove_damage_weight_function.cc b/test/test_model/test_non_local_toolbox/test_remove_damage_weight_function.cc index ff647fca1..77c2a3fa4 100644 --- a/test/test_model/test_non_local_toolbox/test_remove_damage_weight_function.cc +++ b/test/test_model/test_non_local_toolbox/test_remove_damage_weight_function.cc @@ -1,198 +1,189 @@ /** * @file test_remove_damage_weight_function.cc * * @author Aurelia Isabel Cuba Ramos * * @date creation: Wed Oct 07 2015 * * @brief Test the damage weight funcion for non local computations * * @section LICENSE * * Copyright (©) 2015 EPFL (Ecole Polytechnique Fédérale de Lausanne) Laboratory * (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "dumper_paraview.hh" #include "non_local_manager.hh" #include "non_local_neighborhood.hh" #include "solid_mechanics_model.hh" #include "test_material_damage.hh" /* -------------------------------------------------------------------------- */ using namespace akantu; /* -------------------------------------------------------------------------- */ int main(int argc, char * argv[]) { akantu::initialize("material_remove_damage.dat", argc, argv); // some configuration variables const UInt spatial_dimension = 2; ElementType element_type = _quadrangle_4; GhostType ghost_type = _not_ghost; // mesh creation and read Mesh mesh(spatial_dimension); mesh.read("plate.msh"); /// model creation SolidMechanicsModel model(mesh); /// creation of material selector MeshDataMaterialSelector * mat_selector; mat_selector = - new MeshDataMaterialSelector("physical_names", model); + new MeshDataMaterialSelector("physical_names", model); model.setMaterialSelector(*mat_selector); /// model initialization changed to use our material model.initFull(); /// dump material index in paraview model.addDumpField("material_index"); model.addDumpField("grad_u"); model.addDumpField("grad_u non local"); model.addDumpField("damage"); model.dump(); /// apply constant strain field in all elements except element 3 and 15 Matrix applied_strain(spatial_dimension, spatial_dimension); applied_strain.clear(); for (UInt i = 0; i < spatial_dimension; ++i) applied_strain(i, i) = 2.; /// apply different strain in element 3 and 15 Matrix modified_strain(spatial_dimension, spatial_dimension); modified_strain.clear(); for (UInt i = 0; i < spatial_dimension; ++i) modified_strain(i, i) = 1.; /// apply constant grad_u field in all elements for (UInt m = 0; m < model.getNbMaterials(); ++m) { Material & mat = model.getMaterial(m); Array & grad_u = const_cast &>( - mat.getInternal("grad_u")(element_type, ghost_type)); + mat.getInternal("eigen_grad_u")(element_type, ghost_type)); - Array::iterator > grad_u_it = - grad_u.begin(spatial_dimension, spatial_dimension); - Array::iterator > grad_u_end = - grad_u.end(spatial_dimension, spatial_dimension); + auto grad_u_it = grad_u.begin(spatial_dimension, spatial_dimension); + auto grad_u_end = grad_u.end(spatial_dimension, spatial_dimension); UInt element_counter = 0; for (; grad_u_it != grad_u_end; ++grad_u_it, ++element_counter) if (element_counter == 12 || element_counter == 13 || element_counter == 14 || element_counter == 15) - (*grad_u_it) += modified_strain; + (*grad_u_it) = -1. * modified_strain; else - (*grad_u_it) += applied_strain; + (*grad_u_it) = -1. * applied_strain; } /// compute the non-local strains model.assembleInternalForces(); model.dump(); /// save the weights in a file - NonLocalNeighborhood & neighborhood_1 = - dynamic_cast &>( - model.getNonLocalManager().getNeighborhood("mat_1")); - NonLocalNeighborhood & neighborhood_2 = - dynamic_cast &>( - model.getNonLocalManager().getNeighborhood("mat_2")); + auto & neighborhood_1 = model.getNonLocalManager().getNeighborhood("mat_1"); + auto & neighborhood_2 = model.getNonLocalManager().getNeighborhood("mat_2"); neighborhood_1.saveWeights("before_0"); neighborhood_2.saveWeights("before_1"); for (UInt n = 0; n < 2; ++n) { /// print results to screen for validation std::stringstream sstr; sstr << "before_" << n << ".0"; std::ifstream weights; weights.open(sstr.str()); std::string current_line; while (getline(weights, current_line)) std::cout << current_line << std::endl; weights.close(); } /// apply damage to not have the elements with lower strain impact the /// averaging for (UInt m = 0; m < model.getNbMaterials(); ++m) { - MaterialDamage & mat = + auto & mat = dynamic_cast &>(model.getMaterial(m)); - Array & damage = const_cast &>( + auto & damage = const_cast &>( mat.getInternal("damage")(element_type, ghost_type)); - Array::scalar_iterator dam_it = damage.begin(); - Array::scalar_iterator dam_end = damage.end(); + auto dam_it = damage.begin(); + auto dam_end = damage.end(); UInt element_counter = 0; for (; dam_it != dam_end; ++dam_it, ++element_counter) if (element_counter == 12 || element_counter == 13 || element_counter == 14 || element_counter == 15) *dam_it = 0.9; } /// compute the non-local strains model.assembleInternalForces(); neighborhood_1.saveWeights("after_0"); neighborhood_2.saveWeights("after_1"); for (UInt n = 0; n < 2; ++n) { /// print results to screen for validation std::stringstream sstr; sstr << "after_" << n << ".0"; std::ifstream weights; weights.open(sstr.str()); std::string current_line; while (getline(weights, current_line)) std::cout << current_line << std::endl; weights.close(); } model.dump(); /// verify the result: non-local averaging over constant field must /// yield same constant field Real test_result = 0.; Matrix difference(spatial_dimension, spatial_dimension, 0.); Matrix difference_in_damaged_elements(spatial_dimension, spatial_dimension, 0.); for (UInt m = 0; m < model.getNbMaterials(); ++m) { difference_in_damaged_elements.clear(); - auto & mat = - model.getMaterial(m); - Array & grad_u_nl = const_cast &>( + auto & mat = model.getMaterial(m); + auto & grad_u_nl = const_cast &>( mat.getInternal("grad_u non local")(element_type, ghost_type)); - Array::iterator > grad_u_nl_it = - grad_u_nl.begin(spatial_dimension, spatial_dimension); - Array::iterator > grad_u_nl_end = - grad_u_nl.end(spatial_dimension, spatial_dimension); + auto grad_u_nl_it = grad_u_nl.begin(spatial_dimension, spatial_dimension); + auto grad_u_nl_end = grad_u_nl.end(spatial_dimension, spatial_dimension); UInt element_counter = 0; for (; grad_u_nl_it != grad_u_nl_end; ++grad_u_nl_it, ++element_counter) { if (element_counter == 12 || element_counter == 13 || element_counter == 14 || element_counter == 15) difference_in_damaged_elements += (*grad_u_nl_it); else difference = (*grad_u_nl_it) - applied_strain; test_result += difference.norm(); } difference_in_damaged_elements *= (1 / 4.); difference_in_damaged_elements -= (1.41142 * modified_strain); test_result += difference_in_damaged_elements.norm(); } if (test_result > 10.e-5) { std::cout << "the total norm is: " << test_result << std::endl; return EXIT_FAILURE; } finalize(); return EXIT_SUCCESS; }