diff --git a/src/mesh_utils/cohesive_element_inserter.cc b/src/mesh_utils/cohesive_element_inserter.cc index 8de3b7efa..da3189a4f 100644 --- a/src/mesh_utils/cohesive_element_inserter.cc +++ b/src/mesh_utils/cohesive_element_inserter.cc @@ -1,269 +1,272 @@ /** * @file cohesive_element_inserter.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Dec 04 2013 * @date last modification: Mon Feb 19 2018 * * @brief Cohesive element inserter functions * * @section LICENSE * * Copyright (©) 2014-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "cohesive_element_inserter.hh" #include "communicator.hh" #include "element_group.hh" #include "global_ids_updater.hh" #include "mesh_accessor.hh" #include "mesh_iterators.hh" +#include "element_synchronizer.hh" /* -------------------------------------------------------------------------- */ #include <algorithm> #include <limits> /* -------------------------------------------------------------------------- */ namespace akantu { CohesiveElementInserter::CohesiveElementInserter(Mesh & mesh, const ID & id) : Parsable(ParserType::_cohesive_inserter), id(id), mesh(mesh), mesh_facets(mesh.initMeshFacets()), insertion_facets("insertion_facets", id), insertion_limits(mesh.getSpatialDimension(), 2), check_facets("check_facets", id) { this->registerParam("cohesive_surfaces", physical_groups, _pat_parsable, "List of groups to consider for insertion"); this->registerParam("bounding_box", insertion_limits, _pat_parsable, "Global limit for insertion"); UInt spatial_dimension = mesh.getSpatialDimension(); MeshUtils::resetFacetToDouble(mesh_facets); /// init insertion limits for (UInt dim = 0; dim < spatial_dimension; ++dim) { insertion_limits(dim, 0) = std::numeric_limits<Real>::max() * Real(-1.); insertion_limits(dim, 1) = std::numeric_limits<Real>::max(); } insertion_facets.initialize(mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _default_value = false); } /* -------------------------------------------------------------------------- */ CohesiveElementInserter::~CohesiveElementInserter() = default; /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::parseSection(const ParserSection & section) { Parsable::parseSection(section); if (is_extrinsic) limitCheckFacets(this->check_facets); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::limitCheckFacets() { limitCheckFacets(this->check_facets); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::setLimit(SpacialDirection axis, Real first_limit, Real second_limit) { AKANTU_DEBUG_ASSERT( axis < mesh.getSpatialDimension(), "You are trying to limit insertion in a direction that doesn't exist"); insertion_limits(axis, 0) = std::min(first_limit, second_limit); insertion_limits(axis, 1) = std::max(first_limit, second_limit); } /* -------------------------------------------------------------------------- */ UInt CohesiveElementInserter::insertIntrinsicElements() { limitCheckFacets(insertion_facets); return insertElements(); } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::limitCheckFacets( ElementTypeMapArray<bool> & check_facets) { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); check_facets.initialize(mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _default_value = true); check_facets.set(true); // remove the pure ghost elements for_each_element( mesh_facets, [&](auto && facet) { const auto & element_to_facet = mesh_facets.getElementToSubelement( facet.type, facet.ghost_type)(facet.element); auto & left = element_to_facet[0]; auto & right = element_to_facet[1]; if (right == ElementNull || (left.ghost_type == _ghost && right.ghost_type == _ghost)) { check_facets(facet) = false; return; } if (left.kind() == _ek_cohesive or right.kind() == _ek_cohesive) { check_facets(facet) = false; } }, _spatial_dimension = spatial_dimension - 1); auto tolerance = Math::getTolerance(); Vector<Real> bary_facet(spatial_dimension); // set the limits to the bounding box for_each_element( mesh_facets, [&](auto && facet) { auto & need_check = check_facets(facet); if (not need_check) return; mesh_facets.getBarycenter(facet, bary_facet); UInt coord_in_limit = 0; while (coord_in_limit < spatial_dimension and bary_facet(coord_in_limit) > (insertion_limits(coord_in_limit, 0) - tolerance) and bary_facet(coord_in_limit) < (insertion_limits(coord_in_limit, 1) + tolerance)) ++coord_in_limit; if (coord_in_limit != spatial_dimension) need_check = false; }, _spatial_dimension = spatial_dimension - 1); if (physical_groups.size() == 0) { AKANTU_DEBUG_OUT(); return; } if (not mesh_facets.hasData("physical_names")) { AKANTU_DEBUG_ASSERT( physical_groups.size() == 0, "No physical names in the mesh but insertion limited to a group"); AKANTU_DEBUG_OUT(); return; } const auto & physical_ids = mesh_facets.getData<std::string>("physical_names"); // set the limits to the physical surfaces for_each_element(mesh_facets, [&](auto && facet) { auto & need_check = check_facets(facet); if (not need_check) return; const auto & physical_id = physical_ids(facet); auto it = find(physical_groups.begin(), physical_groups.end(), physical_id); need_check = (it != physical_groups.end()); }, _spatial_dimension = spatial_dimension - 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ UInt CohesiveElementInserter::insertElements(bool only_double_facets) { - CohesiveNewNodesEvent node_event; NewElementsEvent element_event; Array<UInt> new_pairs(0, 2); + mesh_facets.getElementSynchronizer().synchronizeOnce( + *this, _gst_ce_groups); + UInt nb_new_elements = MeshUtils::insertCohesiveElements( mesh, mesh_facets, insertion_facets, new_pairs, element_event.getList(), only_double_facets); UInt nb_new_nodes = new_pairs.size(); node_event.getList().reserve(nb_new_nodes); node_event.getOldNodesList().reserve(nb_new_nodes); for (UInt n = 0; n < nb_new_nodes; ++n) { node_event.getList().push_back(new_pairs(n, 1)); node_event.getOldNodesList().push_back(new_pairs(n, 0)); } if (nb_new_elements > 0) { updateInsertionFacets(); } MeshAccessor mesh_accessor(mesh); std::tie(nb_new_nodes, nb_new_elements) = mesh_accessor.updateGlobalData(node_event, element_event); return nb_new_elements; } /* -------------------------------------------------------------------------- */ void CohesiveElementInserter::updateInsertionFacets() { AKANTU_DEBUG_IN(); UInt spatial_dimension = mesh.getSpatialDimension(); for (auto && facet_gt : ghost_types) { for (auto && facet_type : mesh_facets.elementTypes(spatial_dimension - 1, facet_gt)) { auto & ins_facets = insertion_facets(facet_type, facet_gt); // this is the intrinsic case if (not is_extrinsic) continue; auto & f_check = check_facets(facet_type, facet_gt); for (auto && pair : zip(ins_facets, f_check)) { bool & ins = std::get<0>(pair); bool & check = std::get<1>(pair); if (ins) ins = check = false; } } } // resize for the newly added facets insertion_facets.initialize(mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _default_value = false); // resize for the newly added facets if (is_extrinsic) { check_facets.initialize(mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _default_value = false); } else { insertion_facets.set(false); } AKANTU_DEBUG_OUT(); } } // namespace akantu diff --git a/src/mesh_utils/cohesive_element_inserter.hh b/src/mesh_utils/cohesive_element_inserter.hh index ab10d11a5..187125069 100644 --- a/src/mesh_utils/cohesive_element_inserter.hh +++ b/src/mesh_utils/cohesive_element_inserter.hh @@ -1,181 +1,171 @@ /** * @file cohesive_element_inserter.hh * * @author Fabian Barras <fabian.barras@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Dec 04 2013 * @date last modification: Sun Feb 04 2018 * * @brief Cohesive element inserter * * @section LICENSE * * Copyright (©) 2014-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "data_accessor.hh" #include "mesh_utils.hh" #include "parsable.hh" /* -------------------------------------------------------------------------- */ #include <numeric> /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COHESIVE_ELEMENT_INSERTER_HH__ #define __AKANTU_COHESIVE_ELEMENT_INSERTER_HH__ namespace akantu { class GlobalIdsUpdater; class FacetSynchronizer; } // akantu namespace akantu { class CohesiveElementInserter : public DataAccessor<Element>, public Parsable { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: CohesiveElementInserter(Mesh & mesh, const ID & id = "cohesive_element_inserter"); ~CohesiveElementInserter() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// set range limitation for intrinsic cohesive element insertion void setLimit(SpacialDirection axis, Real first_limit, Real second_limit); /// insert intrinsic cohesive elements in a predefined range UInt insertIntrinsicElements(); /// insert extrinsic cohesive elements (returns the number of new /// cohesive elements) UInt insertElements(bool only_double_facets = false); /// limit check facets to match given insertion limits void limitCheckFacets(); protected: void parseSection(const ParserSection & section) override; protected: /// internal version of limitCheckFacets void limitCheckFacets(ElementTypeMapArray<bool> & check_facets); /// update facet insertion arrays after facets doubling void updateInsertionFacets(); /// functions for parallel communications inline UInt getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const override; inline void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) override; - - template <bool pack_mode> - inline void - packUnpackGlobalConnectivity(CommunicationBuffer & buffer, - const Array<Element> & elements) const; - - template <bool pack_mode> - inline void - packUnpackGroupedInsertionData(CommunicationBuffer & buffer, - const Array<Element> & elements) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO_NOT_CONST(InsertionFacetsByElement, insertion_facets, ElementTypeMapArray<bool> &); AKANTU_GET_MACRO(InsertionFacetsByElement, insertion_facets, const ElementTypeMapArray<bool> &); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(InsertionFacets, insertion_facets, bool); AKANTU_GET_MACRO(CheckFacets, check_facets, const ElementTypeMapArray<bool> &); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(CheckFacets, check_facets, bool); AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(CheckFacets, check_facets, bool); AKANTU_GET_MACRO(MeshFacets, mesh_facets, const Mesh &); AKANTU_GET_MACRO_NOT_CONST(MeshFacets, mesh_facets, Mesh &); AKANTU_SET_MACRO(IsExtrinsic, is_extrinsic, bool); public: friend class SolidMechanicsModelCohesive; /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: /// object id ID id; /// main mesh where to insert cohesive elements Mesh & mesh; /// mesh containing facets Mesh & mesh_facets; /// list of facets where to insert elements ElementTypeMapArray<bool> insertion_facets; /// limits for element insertion Matrix<Real> insertion_limits; /// list of groups to consider for insertion, ignored if empty std::vector<ID> physical_groups; /// vector containing facets in which extrinsic cohesive elements can be /// inserted ElementTypeMapArray<bool> check_facets; /// global connectivity ids updater std::unique_ptr<GlobalIdsUpdater> global_ids_updater; /// is this inserter used in extrinsic bool is_extrinsic{false}; }; class CohesiveNewNodesEvent : public NewNodesEvent { public: CohesiveNewNodesEvent() = default; ~CohesiveNewNodesEvent() override = default; AKANTU_GET_MACRO_NOT_CONST(OldNodesList, old_nodes, Array<UInt> &); AKANTU_GET_MACRO(OldNodesList, old_nodes, const Array<UInt> &); private: Array<UInt> old_nodes; }; } // akantu #include "cohesive_element_inserter_inline_impl.cc" #endif /* __AKANTU_COHESIVE_ELEMENT_INSERTER_HH__ */ diff --git a/src/mesh_utils/cohesive_element_inserter_inline_impl.cc b/src/mesh_utils/cohesive_element_inserter_inline_impl.cc index d53f12d16..bf9aeee9d 100644 --- a/src/mesh_utils/cohesive_element_inserter_inline_impl.cc +++ b/src/mesh_utils/cohesive_element_inserter_inline_impl.cc @@ -1,121 +1,89 @@ /** * @file cohesive_element_inserter_inline_impl.cc * * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Nov 05 2014 * @date last modification: Fri Dec 08 2017 * * @brief Cohesive element inserter inline functions * * @section LICENSE * * Copyright (©) 2015-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "cohesive_element_inserter.hh" /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_COHESIVE_ELEMENT_INSERTER_INLINE_IMPL_CC__ #define __AKANTU_COHESIVE_ELEMENT_INSERTER_INLINE_IMPL_CC__ namespace akantu { /* -------------------------------------------------------------------------- */ inline UInt CohesiveElementInserter::getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); UInt size = 0; if (tag == _gst_ce_groups) { - size = elements.size() * (sizeof(bool) + sizeof(unsigned int)); + size = elements.size() * sizeof(bool); } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ inline void CohesiveElementInserter::packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); - if (tag == _gst_ce_groups) - packUnpackGroupedInsertionData<true>(buffer, elements); - + if (tag == _gst_ce_groups) { + for (const auto & el : elements) { + const bool & data = insertion_facets(el); + buffer << data; + } + } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ inline void CohesiveElementInserter::unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); - if (tag == _gst_ce_groups) - packUnpackGroupedInsertionData<false>(buffer, elements); - - AKANTU_DEBUG_OUT(); -} - -/* -------------------------------------------------------------------------- */ -template <bool pack_mode> -inline void CohesiveElementInserter::packUnpackGroupedInsertionData( - CommunicationBuffer & buffer, const Array<Element> & elements) const { - - AKANTU_DEBUG_IN(); - - auto current_element_type = _not_defined; - auto current_ghost_type = _casper; - auto & physical_names = mesh_facets.registerData<UInt>("physical_names"); - - Array<bool> * vect = nullptr; - Array<UInt> * vect2 = nullptr; - - for (const auto & el : elements) { - if (el.type != current_element_type || - el.ghost_type != current_ghost_type) { - current_element_type = el.type; - current_ghost_type = el.ghost_type; - vect = - &const_cast<Array<bool> &>(insertion_facets(el.type, el.ghost_type)); - vect2 = &(physical_names(el.type, el.ghost_type)); - } - - Vector<bool> data(vect->storage() + el.element, 1); - Vector<unsigned int> data2(vect2->storage() + el.element, 1); - if (pack_mode) { - buffer << data; - buffer << data2; - } else { + if (tag == _gst_ce_groups) { + for (const auto & el : elements) { + bool & data = insertion_facets(el); buffer >> data; - buffer >> data2; } } - AKANTU_DEBUG_OUT(); } } // namespace akantu #endif /* __AKANTU_COHESIVE_ELEMENT_INSERTER_INLINE_IMPL_CC__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc index e7613b780..477729d24 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.cc @@ -1,759 +1,705 @@ /** * @file solid_mechanics_model_cohesive.cc * * @author Fabian Barras <fabian.barras@epfl.ch> * @author Mauro Corrado <mauro.corrado@epfl.ch> * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue May 08 2012 * @date last modification: Wed Feb 21 2018 * * @brief Solid mechanics model for cohesive elements * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "solid_mechanics_model_cohesive.hh" #include "aka_iterators.hh" #include "cohesive_element_inserter.hh" #include "element_synchronizer.hh" #include "facet_synchronizer.hh" #include "fe_engine_template.hh" #include "global_ids_updater.hh" #include "integrator_gauss.hh" #include "material_cohesive.hh" #include "mesh_accessor.hh" #include "mesh_global_data_updater.hh" #include "parser.hh" #include "shape_cohesive.hh" /* -------------------------------------------------------------------------- */ #include "dumpable_inline_impl.hh" #ifdef AKANTU_USE_IOHELPER #include "dumper_iohelper_paraview.hh" #endif /* -------------------------------------------------------------------------- */ #include <algorithm> /* -------------------------------------------------------------------------- */ namespace akantu { class CohesiveMeshGlobalDataUpdater : public MeshGlobalDataUpdater { public: CohesiveMeshGlobalDataUpdater(SolidMechanicsModelCohesive & model) : model(model), mesh(model.getMesh()), global_ids_updater(model.getMesh(), *model.cohesive_synchronizer) {} /* ------------------------------------------------------------------------ */ std::tuple<UInt, UInt> updateData(NewNodesEvent & nodes_event, NewElementsEvent & elements_event) override { auto cohesive_nodes_event = dynamic_cast<CohesiveNewNodesEvent *>(&nodes_event); if (not cohesive_nodes_event) return std::make_tuple(nodes_event.getList().size(), elements_event.getList().size()); /// update nodes type auto & new_nodes = cohesive_nodes_event->getList(); auto & old_nodes = cohesive_nodes_event->getOldNodesList(); UInt local_nb_new_nodes = new_nodes.size(); MeshAccessor mesh_accessor(mesh); auto & nodes_type = mesh_accessor.getNodesType(); UInt nb_old_nodes = nodes_type.size(); nodes_type.resize(nb_old_nodes + local_nb_new_nodes); for (auto && data : zip(old_nodes, new_nodes)) { UInt old_node, new_node; std::tie(old_node, new_node) = data; nodes_type(new_node) = nodes_type(old_node); } model.updateCohesiveSynchronizers(); UInt nb_new_nodes = global_ids_updater.updateGlobalIDs(new_nodes.size()); Vector<UInt> nb_new_stuff = {nb_new_nodes, elements_event.getList().size()}; const auto & comm = mesh.getCommunicator(); comm.allReduce(nb_new_stuff, SynchronizerOperation::_sum); if (nb_new_stuff(1) > 0) { mesh.sendEvent(elements_event); MeshUtils::resetFacetToDouble(mesh.getMeshFacets()); } if (nb_new_nodes > 0) { mesh.sendEvent(nodes_event); // mesh.sendEvent(global_ids_updater.getChangedNodeEvent()); } return std::make_tuple(nb_new_nodes, nb_new_stuff(1)); } private: SolidMechanicsModelCohesive & model; Mesh & mesh; GlobalIdsUpdater global_ids_updater; }; /* -------------------------------------------------------------------------- */ SolidMechanicsModelCohesive::SolidMechanicsModelCohesive( Mesh & mesh, UInt dim, const ID & id, const MemoryID & memory_id) : SolidMechanicsModel(mesh, dim, id, memory_id, ModelType::_solid_mechanics_model_cohesive), tangents("tangents", id), facet_stress("facet_stress", id), facet_material("facet_material", id) { AKANTU_DEBUG_IN(); registerFEEngineObject<MyFEEngineCohesiveType>("CohesiveFEEngine", mesh, Model::spatial_dimension); auto && tmp_material_selector = std::make_shared<DefaultMaterialCohesiveSelector>(*this); tmp_material_selector->setFallback(this->material_selector); this->material_selector = tmp_material_selector; #if defined(AKANTU_USE_IOHELPER) this->mesh.registerDumper<DumperParaview>("cohesive elements", id); this->mesh.addDumpMeshToDumper("cohesive elements", mesh, Model::spatial_dimension, _not_ghost, _ek_cohesive); #endif if (this->mesh.isDistributed()) { /// create the distributed synchronizer for cohesive elements this->cohesive_synchronizer = std::make_unique<ElementSynchronizer>( mesh, "cohesive_distributed_synchronizer"); auto & synchronizer = mesh.getElementSynchronizer(); this->cohesive_synchronizer->split(synchronizer, [](auto && el) { return Mesh::getKind(el.type) == _ek_cohesive; }); this->registerSynchronizer(*cohesive_synchronizer, _gst_material_id); this->registerSynchronizer(*cohesive_synchronizer, _gst_smm_stress); this->registerSynchronizer(*cohesive_synchronizer, _gst_smm_boundary); } this->inserter = std::make_unique<CohesiveElementInserter>( this->mesh, id + ":cohesive_element_inserter"); registerFEEngineObject<MyFEEngineFacetType>( "FacetsFEEngine", mesh.getMeshFacets(), Model::spatial_dimension - 1); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ SolidMechanicsModelCohesive::~SolidMechanicsModelCohesive() = default; /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::setTimeStep(Real time_step, const ID & solver_id) { SolidMechanicsModel::setTimeStep(time_step, solver_id); #if defined(AKANTU_USE_IOHELPER) this->mesh.getDumper("cohesive elements").setTimeStep(time_step); #endif } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initFullImpl(const ModelOptions & options) { AKANTU_DEBUG_IN(); const auto & smmc_options = dynamic_cast<const SolidMechanicsModelCohesiveOptions &>(options); this->is_extrinsic = smmc_options.extrinsic; inserter->setIsExtrinsic(is_extrinsic); if (mesh.isDistributed()) { auto & mesh_facets = inserter->getMeshFacets(); auto & synchronizer = dynamic_cast<FacetSynchronizer &>(mesh_facets.getElementSynchronizer()); - this->registerSynchronizer(synchronizer, _gst_smmc_facets); + // this->registerSynchronizer(synchronizer, _gst_smmc_facets); // this->registerSynchronizer(synchronizer, _gst_smmc_facets_conn); synchronizeGhostFacetsConnectivity(); /// create the facet synchronizer for extrinsic simulations if (is_extrinsic) { facet_stress_synchronizer = std::make_unique<ElementSynchronizer>( synchronizer, id + ":facet_stress_synchronizer"); facet_stress_synchronizer->swapSendRecv(); this->registerSynchronizer(*facet_stress_synchronizer, _gst_smmc_facets_stress); } MeshAccessor mesh_accessor(mesh); mesh_accessor.registerGlobalDataUpdater( std::make_unique<CohesiveMeshGlobalDataUpdater>(*this)); } ParserSection section; bool is_empty; std::tie(section, is_empty) = this->getParserSection(); if (not is_empty) { auto inserter_section = section.getSubSections(ParserType::_cohesive_inserter); if (inserter_section.begin() != inserter_section.end()) { inserter->parseSection(*inserter_section.begin()); } } SolidMechanicsModel::initFullImpl(options); AKANTU_DEBUG_OUT(); } // namespace akantu /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initMaterials() { AKANTU_DEBUG_IN(); // make sure the material are instantiated if (!are_materials_instantiated) instantiateMaterials(); /// find the first cohesive material UInt cohesive_index = UInt(-1); for (auto && material : enumerate(materials)) { if (dynamic_cast<MaterialCohesive *>(std::get<1>(material).get())) { cohesive_index = std::get<0>(material); break; } } if (cohesive_index == UInt(-1)) AKANTU_EXCEPTION("No cohesive materials in the material input file"); material_selector->setFallback(cohesive_index); // set the facet information in the material in case of dynamic insertion // to know what material to call for stress checks - if (is_extrinsic) { - this->initExtrinsicMaterials(); - } else { - this->initIntrinsicMaterials(); - } - - AKANTU_DEBUG_OUT(); -} // namespace akantu -/* -------------------------------------------------------------------------- */ -void SolidMechanicsModelCohesive::initExtrinsicMaterials() { const Mesh & mesh_facets = inserter->getMeshFacets(); facet_material.initialize( mesh_facets, _spatial_dimension = spatial_dimension - 1, _with_nb_element = true, _default_value = material_selector->getFallbackValue()); for_each_element( mesh_facets, [&](auto && element) { auto mat_index = (*material_selector)(element); auto & mat = dynamic_cast<MaterialCohesive &>(*materials[mat_index]); facet_material(element) = mat_index; - mat.addFacet(element); + if (is_extrinsic) { + mat.addFacet(element); + } }, _spatial_dimension = spatial_dimension - 1, _ghost_type = _not_ghost); SolidMechanicsModel::initMaterials(); - this->initAutomaticInsertion(); -} - -/* -------------------------------------------------------------------------- */ -#if 0 -void SolidMechanicsModelCohesive::initIntrinsicCohesiveMaterials( - const std::string & cohesive_surfaces) { - - AKANTU_DEBUG_IN(); - -#if defined(AKANTU_PARALLEL_COHESIVE_ELEMENT) - if (facet_synchronizer != nullptr) - inserter->initParallel(facet_synchronizer, cohesive_element_synchronizer); -// inserter->initParallel(facet_synchronizer, synch_parallel); -#endif - std::istringstream split(cohesive_surfaces); - std::string physname; - while (std::getline(split, physname, ',')) { - AKANTU_DEBUG_INFO( - "Pre-inserting cohesive elements along facets from physical surface: " - << physname); - insertElementsFromMeshData(physname); - } - - synchronizeInsertionData(); - - SolidMechanicsModel::initMaterials(); - - auto && tmp = std::make_shared<MeshDataMaterialCohesiveSelector>(*this); - tmp->setFallback(material_selector->getFallbackValue()); - tmp->setFallback(material_selector->getFallbackSelector()); - material_selector = tmp; - - // UInt nb_new_elements = - inserter->insertElements(); - // if (nb_new_elements > 0) { - // this->reinitializeSolver(); - // } - - AKANTU_DEBUG_OUT(); -} -#endif -/* -------------------------------------------------------------------------- */ -void SolidMechanicsModelCohesive::synchronizeInsertionData() { - if (inserter->getMeshFacets().isDistributed()) { - inserter->getMeshFacets().getElementSynchronizer().synchronizeOnce( - *inserter, _gst_ce_groups); + if (is_extrinsic) { + this->initAutomaticInsertion(); + } else { + this->insertIntrinsicElements(); } -} - -/* -------------------------------------------------------------------------- */ -void SolidMechanicsModelCohesive::initIntrinsicMaterials() { - AKANTU_DEBUG_IN(); - - SolidMechanicsModel::initMaterials(); - - this->insertIntrinsicElements(); AKANTU_DEBUG_OUT(); -} +} // namespace akantu /* -------------------------------------------------------------------------- */ /** * Initialize the model,basically it pre-compute the shapes, shapes derivatives * and jacobian */ void SolidMechanicsModelCohesive::initModel() { AKANTU_DEBUG_IN(); SolidMechanicsModel::initModel(); /// add cohesive type connectivity ElementType type = _not_defined; for (auto && type_ghost : ghost_types) { for (const auto & tmp_type : mesh.elementTypes(spatial_dimension, type_ghost)) { const auto & connectivity = mesh.getConnectivity(tmp_type, type_ghost); if (connectivity.size() == 0) continue; type = tmp_type; auto type_facet = Mesh::getFacetType(type); auto type_cohesive = FEEngine::getCohesiveElementType(type_facet); mesh.addConnectivityType(type_cohesive, type_ghost); } } AKANTU_DEBUG_ASSERT(type != _not_defined, "No elements in the mesh"); getFEEngine("CohesiveFEEngine").initShapeFunctions(_not_ghost); getFEEngine("CohesiveFEEngine").initShapeFunctions(_ghost); if (is_extrinsic) { getFEEngine("FacetsFEEngine").initShapeFunctions(_not_ghost); getFEEngine("FacetsFEEngine").initShapeFunctions(_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::insertIntrinsicElements() { AKANTU_DEBUG_IN(); inserter->insertIntrinsicElements(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initAutomaticInsertion() { AKANTU_DEBUG_IN(); this->inserter->limitCheckFacets(); this->updateFacetStressSynchronizer(); this->resizeFacetStress(); /// compute normals on facets this->computeNormals(); this->initStressInterpolation(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::updateAutomaticInsertion() { AKANTU_DEBUG_IN(); this->inserter->limitCheckFacets(); this->updateFacetStressSynchronizer(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::initStressInterpolation() { Mesh & mesh_facets = inserter->getMeshFacets(); /// compute quadrature points coordinates on facets Array<Real> & position = mesh.getNodes(); ElementTypeMapArray<Real> quad_facets("quad_facets", id); quad_facets.initialize(mesh_facets, _nb_component = Model::spatial_dimension, _spatial_dimension = Model::spatial_dimension - 1); // mesh_facets.initElementTypeMapArray(quad_facets, Model::spatial_dimension, // Model::spatial_dimension - 1); getFEEngine("FacetsFEEngine") .interpolateOnIntegrationPoints(position, quad_facets); /// compute elements quadrature point positions and build /// element-facet quadrature points data structure ElementTypeMapArray<Real> elements_quad_facets("elements_quad_facets", id); elements_quad_facets.initialize( mesh, _nb_component = Model::spatial_dimension, _spatial_dimension = Model::spatial_dimension); // mesh.initElementTypeMapArray(elements_quad_facets, // Model::spatial_dimension, // Model::spatial_dimension); for (auto elem_gt : ghost_types) { for (auto & type : mesh.elementTypes(Model::spatial_dimension, elem_gt)) { UInt nb_element = mesh.getNbElement(type, elem_gt); if (nb_element == 0) continue; /// compute elements' quadrature points and list of facet /// quadrature points positions by element const auto & facet_to_element = mesh_facets.getSubelementToElement(type, elem_gt); auto & el_q_facet = elements_quad_facets(type, elem_gt); auto facet_type = Mesh::getFacetType(type); auto nb_quad_per_facet = getFEEngine("FacetsFEEngine").getNbIntegrationPoints(facet_type); auto nb_facet_per_elem = facet_to_element.getNbComponent(); // small hack in the loop to skip boundary elements, they are silently // initialized to NaN to see if this causes problems el_q_facet.resize(nb_element * nb_facet_per_elem * nb_quad_per_facet, std::numeric_limits<Real>::quiet_NaN()); for (auto && data : zip(make_view(facet_to_element), make_view(el_q_facet, spatial_dimension, nb_quad_per_facet))) { const auto & global_facet = std::get<0>(data); auto & el_q = std::get<1>(data); if (global_facet == ElementNull) continue; Matrix<Real> quad_f = make_view(quad_facets(global_facet.type, global_facet.ghost_type), spatial_dimension, nb_quad_per_facet) .begin()[global_facet.element]; el_q = quad_f; // for (UInt q = 0; q < nb_quad_per_facet; ++q) { // for (UInt s = 0; s < Model::spatial_dimension; ++s) { // el_q_facet(el * nb_facet_per_elem * nb_quad_per_facet + // f * nb_quad_per_facet + q, // s) = quad_f(global_facet * nb_quad_per_facet + q, // s); // } // } //} } } } /// loop over non cohesive materials for (auto && material : materials) { if (dynamic_cast<MaterialCohesive *>(material.get())) continue; /// initialize the interpolation function material->initElementalFieldInterpolation(elements_quad_facets); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::assembleInternalForces() { AKANTU_DEBUG_IN(); // f_int += f_int_cohe for (auto & material : this->materials) { try { auto & mat = dynamic_cast<MaterialCohesive &>(*material); mat.computeTraction(_not_ghost); } catch (std::bad_cast & bce) { } } SolidMechanicsModel::assembleInternalForces(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::computeNormals() { AKANTU_DEBUG_IN(); Mesh & mesh_facets = this->inserter->getMeshFacets(); this->getFEEngine("FacetsFEEngine") .computeNormalsOnIntegrationPoints(_not_ghost); /** * @todo store tangents while computing normals instead of * recomputing them as follows: */ /* ------------------------------------------------------------------------ */ UInt tangent_components = Model::spatial_dimension * (Model::spatial_dimension - 1); tangents.initialize(mesh_facets, _nb_component = tangent_components, _spatial_dimension = Model::spatial_dimension - 1); // mesh_facets.initElementTypeMapArray(tangents, tangent_components, // Model::spatial_dimension - 1); for (auto facet_type : mesh_facets.elementTypes(Model::spatial_dimension - 1)) { const Array<Real> & normals = this->getFEEngine("FacetsFEEngine") .getNormalsOnIntegrationPoints(facet_type); Array<Real> & tangents = this->tangents(facet_type); Math::compute_tangents(normals, tangents); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::interpolateStress() { ElementTypeMapArray<Real> by_elem_result("temporary_stress_by_facets", id); for (auto & material : materials) { auto * mat = dynamic_cast<MaterialCohesive *>(material.get()); if (mat == nullptr) /// interpolate stress on facet quadrature points positions material->interpolateStressOnFacets(facet_stress, by_elem_result); } this->synchronize(_gst_smmc_facets_stress); } /* -------------------------------------------------------------------------- */ UInt SolidMechanicsModelCohesive::checkCohesiveStress() { AKANTU_DEBUG_IN(); + if (not is_extrinsic) { + AKANTU_EXCEPTION( + "This function can only be used for extrinsic cohesive elements"); + } + interpolateStress(); for (auto & mat : materials) { auto * mat_cohesive = dynamic_cast<MaterialCohesive *>(mat.get()); if (mat_cohesive) { /// check which not ghost cohesive elements are to be created mat_cohesive->checkInsertion(); } } /// communicate data among processors - this->synchronize(_gst_smmc_facets); + // this->synchronize(_gst_smmc_facets); /// insert cohesive elements UInt nb_new_elements = inserter->insertElements(); // if (nb_new_elements > 0) { // this->reinitializeSolver(); // } AKANTU_DEBUG_OUT(); return nb_new_elements; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onElementsAdded( const Array<Element> & element_list, const NewElementsEvent & event) { AKANTU_DEBUG_IN(); SolidMechanicsModel::onElementsAdded(element_list, event); if (is_extrinsic) resizeFacetStress(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onNodesAdded(const Array<UInt> & new_nodes, const NewNodesEvent & event) { AKANTU_DEBUG_IN(); SolidMechanicsModel::onNodesAdded(new_nodes, event); const CohesiveNewNodesEvent * cohesive_event; - if ((cohesive_event = dynamic_cast<const CohesiveNewNodesEvent *>(&event)) == nullptr) + if ((cohesive_event = dynamic_cast<const CohesiveNewNodesEvent *>(&event)) == + nullptr) return; const auto & old_nodes = cohesive_event->getOldNodesList(); auto copy = [this, &new_nodes, &old_nodes](auto & arr) { UInt new_node, old_node; auto view = make_view(arr, spatial_dimension); auto begin = view.begin(); for (auto && pair : zip(new_nodes, old_nodes)) { std::tie(new_node, old_node) = pair; auto old_ = begin + old_node; auto new_ = begin + new_node; *new_ = *old_; } }; copy(*displacement); copy(*blocked_dofs); if (velocity) copy(*velocity); if (acceleration) copy(*acceleration); if (current_position) copy(*current_position); if (previous_displacement) copy(*previous_displacement); // if (external_force) // copy(*external_force); // if (internal_force) // copy(*internal_force); if (displacement_increment) copy(*displacement_increment); copy(getDOFManager().getSolution("displacement")); // this->assembleMassLumped(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onEndSolveStep(const AnalysisMethod &) { AKANTU_DEBUG_IN(); /* * This is required because the Cauchy stress is the stress measure that * is used to check the insertion of cohesive elements */ for (auto & mat : materials) { if (mat->isFiniteDeformation()) mat->computeAllCauchyStresses(_not_ghost); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::printself(std::ostream & stream, int indent) const { std::string space; for (Int i = 0; i < indent; i++, space += AKANTU_INDENT) ; stream << space << "SolidMechanicsModelCohesive [" << std::endl; SolidMechanicsModel::printself(stream, indent + 1); stream << space << "]" << std::endl; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::resizeFacetStress() { AKANTU_DEBUG_IN(); this->facet_stress.initialize(getFEEngine("FacetsFEEngine"), _nb_component = 2 * spatial_dimension * spatial_dimension, _spatial_dimension = spatial_dimension - 1); // for (auto && ghost_type : ghost_types) { // for (const auto & type : // mesh_facets.elementTypes(spatial_dimension - 1, ghost_type)) { // UInt nb_facet = mesh_facets.getNbElement(type, ghost_type); // UInt nb_quadrature_points = getFEEngine("FacetsFEEngine") // .getNbIntegrationPoints(type, // ghost_type); // UInt new_size = nb_facet * nb_quadrature_points; // facet_stress(type, ghost_type).resize(new_size); // } // } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::addDumpGroupFieldToDumper( const std::string & dumper_name, const std::string & field_id, const std::string & group_name, const ElementKind & element_kind, bool padding_flag) { AKANTU_DEBUG_IN(); UInt spatial_dimension = Model::spatial_dimension; ElementKind _element_kind = element_kind; if (dumper_name == "cohesive elements") { _element_kind = _ek_cohesive; } else if (dumper_name == "facets") { spatial_dimension = Model::spatial_dimension - 1; } SolidMechanicsModel::addDumpGroupFieldToDumper(dumper_name, field_id, group_name, spatial_dimension, _element_kind, padding_flag); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::onDump() { this->flattenAllRegisteredInternals(_ek_cohesive); SolidMechanicsModel::onDump(); } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh index d94ab18b8..2a49a56da 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive.hh @@ -1,321 +1,312 @@ /** * @file solid_mechanics_model_cohesive.hh * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Tue May 08 2012 * @date last modification: Mon Feb 05 2018 * * @brief Solid mechanics model for cohesive elements * * @section LICENSE * * Copyright (©) 2010-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "cohesive_element_inserter.hh" #include "material_selector_cohesive.hh" #include "random_internal_field.hh" // included to have the specialization of #include "solid_mechanics_model.hh" #include "solid_mechanics_model_event_handler.hh" // ParameterTyped::operator Real() /* -------------------------------------------------------------------------- */ #ifndef __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_HH__ #define __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_HH__ /* -------------------------------------------------------------------------- */ namespace akantu { class FacetSynchronizer; class FacetStressSynchronizer; class ElementSynchronizer; } // namespace akantu namespace akantu { /* -------------------------------------------------------------------------- */ struct FacetsCohesiveIntegrationOrderFunctor { template <ElementType type, ElementType cohesive_type = CohesiveFacetProperty<type>::cohesive_type> struct _helper { static constexpr int get() { return ElementClassProperty<cohesive_type>::polynomial_degree; } }; template <ElementType type> struct _helper<type, _not_defined> { static constexpr int get() { return ElementClassProperty<type>::polynomial_degree; } }; template <ElementType type> static inline constexpr int getOrder() { return _helper<type>::get(); } }; /* -------------------------------------------------------------------------- */ /* Solid Mechanics Model for Cohesive elements */ /* -------------------------------------------------------------------------- */ class SolidMechanicsModelCohesive : public SolidMechanicsModel, public SolidMechanicsModelEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: class NewCohesiveNodesEvent : public NewNodesEvent { public: AKANTU_GET_MACRO_NOT_CONST(OldNodesList, old_nodes, Array<UInt> &); AKANTU_GET_MACRO(OldNodesList, old_nodes, const Array<UInt> &); protected: Array<UInt> old_nodes; }; using MyFEEngineCohesiveType = FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_cohesive>; using MyFEEngineFacetType = FEEngineTemplate<IntegratorGauss, ShapeLagrange, _ek_regular, FacetsCohesiveIntegrationOrderFunctor>; SolidMechanicsModelCohesive(Mesh & mesh, UInt spatial_dimension = _all_dimensions, const ID & id = "solid_mechanics_model_cohesive", const MemoryID & memory_id = 0); ~SolidMechanicsModelCohesive() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ protected: /// initialize the cohesive model void initFullImpl(const ModelOptions & options) override; public: /// set the value of the time step void setTimeStep(Real time_step, const ID & solver_id = "") override; /// assemble the residual for the explicit scheme void assembleInternalForces() override; /// function to perform a stress check on each facet and insert /// cohesive elements if needed (returns the number of new cohesive /// elements) UInt checkCohesiveStress(); /// interpolate stress on facets void interpolateStress(); /// update automatic insertion after a change in the element inserter void updateAutomaticInsertion(); /// insert intrinsic cohesive elements void insertIntrinsicElements(); // template <SolveConvergenceMethod cmethod, SolveConvergenceCriteria // criteria> bool solveStepCohesive(Real tolerance, Real & error, UInt // max_iteration = 100, // bool load_reduction = false, // Real tol_increase_factor = 1.0, // bool do_not_factorize = false); protected: /// initialize stress interpolation void initStressInterpolation(); /// initialize the model void initModel() override; /// initialize cohesive material void initMaterials() override; /// init facet filters for cohesive materials void initFacetFilter(); - // synchronize facets physical data before insertion along physical surfaces - void synchronizeInsertionData(); - /// function to print the contain of the class void printself(std::ostream & stream, int indent = 0) const override; private: - /// initialize cohesive material with extrinsic insertion - void initExtrinsicMaterials(); - - /// initialize cohesive material with intrinsic insertion - void initIntrinsicMaterials(); - /// insert cohesive elements along a given physical surface of the mesh void insertElementsFromMeshData(const std::string & physical_name); /// initialize completely the model for extrinsic elements void initAutomaticInsertion(); /// compute facets' normals void computeNormals(); /// resize facet stress void resizeFacetStress(); /// init facets_check array void initFacetsCheck(); /* ------------------------------------------------------------------------ */ /* Mesh Event Handler inherited members */ /* ------------------------------------------------------------------------ */ protected: void onNodesAdded(const Array<UInt> & nodes_list, const NewNodesEvent & event) override; void onElementsAdded(const Array<Element> & nodes_list, const NewElementsEvent & event) override; /* ------------------------------------------------------------------------ */ /* SolidMechanicsModelEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: void onEndSolveStep(const AnalysisMethod & method) override; /* ------------------------------------------------------------------------ */ /* Dumpable interface */ /* ------------------------------------------------------------------------ */ public: void onDump() override; void addDumpGroupFieldToDumper(const std::string & dumper_name, const std::string & field_id, const std::string & group_name, const ElementKind & element_kind, bool padding_flag) override; public: /// register the tags associated with the parallel synchronizer for /// cohesive elements // void initParallel(MeshPartition * partition, // DataAccessor * data_accessor = NULL, // bool extrinsic = false); protected: void synchronizeGhostFacetsConnectivity(); void updateCohesiveSynchronizers(); void updateFacetStressSynchronizer(); friend class CohesiveElementInserter; /* ------------------------------------------------------------------------ */ /* Data Accessor inherited members */ /* ------------------------------------------------------------------------ */ public: UInt getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const override; void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const override; void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) override; protected: UInt getNbQuadsForFacetCheck(const Array<Element> & elements) const; template <typename T> void packFacetStressDataHelper(const ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & elements) const; template <typename T> void unpackFacetStressDataHelper(ElementTypeMapArray<T> & data_to_unpack, CommunicationBuffer & buffer, const Array<Element> & elements) const; template <typename T, bool pack_helper> void packUnpackFacetStressDataHelper(ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & element) const; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get facet mesh AKANTU_GET_MACRO(MeshFacets, mesh.getMeshFacets(), const Mesh &); /// get stress on facets vector AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(StressOnFacets, facet_stress, Real); /// get facet material AKANTU_GET_MACRO_BY_ELEMENT_TYPE(FacetMaterial, facet_material, UInt); /// get facet material AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(FacetMaterial, facet_material, UInt); /// get facet material AKANTU_GET_MACRO(FacetMaterial, facet_material, const ElementTypeMapArray<UInt> &); /// @todo THIS HAS TO BE CHANGED AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Tangents, tangents, Real); /// get element inserter AKANTU_GET_MACRO_NOT_CONST(ElementInserter, *inserter, CohesiveElementInserter &); /// get is_extrinsic boolean AKANTU_GET_MACRO(IsExtrinsic, is_extrinsic, bool); /// get cohesive elements synchronizer AKANTU_GET_MACRO(CohesiveSynchronizer, *cohesive_synchronizer, const ElementSynchronizer &); /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ private: friend class CohesiveMeshGlobalDataUpdater; /// @todo store tangents when normals are computed: ElementTypeMapArray<Real> tangents; /// stress on facets on the two sides by quadrature point ElementTypeMapArray<Real> facet_stress; /// material to use if a cohesive element is created on a facet ElementTypeMapArray<UInt> facet_material; bool is_extrinsic; /// cohesive element inserter std::unique_ptr<CohesiveElementInserter> inserter; /// facet stress synchronizer std::unique_ptr<ElementSynchronizer> facet_stress_synchronizer; /// cohesive elements synchronizer std::unique_ptr<ElementSynchronizer> cohesive_synchronizer; }; } // namespace akantu #include "solid_mechanics_model_cohesive_inline_impl.cc" #endif /* __AKANTU_SOLID_MECHANICS_MODEL_COHESIVE_HH__ */ diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc index 412cc689f..b5a02f27d 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/solid_mechanics_model_cohesive_parallel.cc @@ -1,547 +1,549 @@ /** * @file solid_mechanics_model_cohesive_parallel.cc * * @author Nicolas Richart <nicolas.richart@epfl.ch> * @author Marco Vocialta <marco.vocialta@epfl.ch> * * @date creation: Wed Nov 05 2014 * @date last modification: Tue Feb 20 2018 * * @brief Functions for parallel cohesive elements * * @section LICENSE * * Copyright (©) 2015-2018 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see <http://www.gnu.org/licenses/>. * */ /* -------------------------------------------------------------------------- */ #include "communicator.hh" #include "element_synchronizer.hh" #include "material_cohesive.hh" #include "solid_mechanics_model_cohesive.hh" #include "solid_mechanics_model_tmpl.hh" /* -------------------------------------------------------------------------- */ #include <type_traits> /* -------------------------------------------------------------------------- */ namespace akantu { class FacetConnectivitySynchronizer : public DataAccessor<Element> { public: FacetConnectivitySynchronizer(Mesh & mesh) : global_connectivity("global_connectivity", "facet_connectivity_synchronizer") { global_connectivity.initialize( mesh, _spatial_dimension = _all_dimensions, _with_nb_element = true, _with_nb_nodes_per_element = true, _element_kind = _ek_regular); mesh.getGlobalConnectivity(global_connectivity); } UInt getNbData(const Array<Element> & elements, const SynchronizationTag & tag) const { UInt size = 0; if (tag == _gst_smmc_facets_conn) { UInt nb_nodes = Mesh::getNbNodesPerElementList(elements); size += nb_nodes * sizeof(UInt); } return size; } void packData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { if (tag == _gst_smmc_facets_conn) { for (const auto & element : elements) { auto & conns = global_connectivity(element.type, element.ghost_type); for (auto n : arange(conns.getNbComponent())) { buffer << conns(element.element, n); } } } } void unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { if (tag == _gst_smmc_facets_conn) { for (const auto & element : elements) { auto & conns = global_connectivity(element.type, element.ghost_type); for (auto n : arange(conns.getNbComponent())) { buffer >> conns(element.element, n); } } } } AKANTU_GET_MACRO(GlobalConnectivity, (global_connectivity), decltype(auto)); protected: ElementTypeMapArray<UInt> global_connectivity; }; /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::synchronizeGhostFacetsConnectivity() { AKANTU_DEBUG_IN(); const Communicator & comm = mesh.getCommunicator(); Int psize = comm.getNbProc(); if (psize == 1) { AKANTU_DEBUG_OUT(); return; } /// get global connectivity for not ghost facets auto & mesh_facets = inserter->getMeshFacets(); FacetConnectivitySynchronizer data_accessor(mesh_facets); /// communicate mesh_facets.getElementSynchronizer().synchronizeOnce(data_accessor, _gst_smmc_facets_conn); /// flip facets MeshUtils::flipFacets(mesh_facets, data_accessor.getGlobalConnectivity(), _ghost); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::updateCohesiveSynchronizers() { /// update synchronizers if needed if (not mesh.isDistributed()) return; auto & mesh_facets = inserter->getMeshFacets(); auto & facet_synchronizer = mesh_facets.getElementSynchronizer(); const auto & cfacet_synchronizer = facet_synchronizer; // update the cohesive element synchronizer cohesive_synchronizer->updateSchemes([&](auto && scheme, auto && proc, auto && direction) { auto & facet_scheme = cfacet_synchronizer.getCommunications().getScheme(proc, direction); for (auto && facet : facet_scheme) { const auto & cohesive_element = const_cast<const Mesh &>(mesh_facets) .getElementToSubelement(facet)[1]; if (cohesive_element == ElementNull or cohesive_element.kind() != _ek_cohesive) continue; auto && cohesive_type = FEEngine::getCohesiveElementType(facet.type); auto old_nb_cohesive_elements = mesh.getNbElement(cohesive_type, facet.ghost_type); old_nb_cohesive_elements -= mesh_facets .getData<UInt>("facet_to_double", facet.type, facet.ghost_type) .size(); if (cohesive_element.element >= old_nb_cohesive_elements) { scheme.push_back(cohesive_element); } } }); if (not facet_stress_synchronizer) return; const auto & element_synchronizer = mesh.getElementSynchronizer(); const auto & comm = mesh.getCommunicator(); auto && my_rank = comm.whoAmI(); // update the facet stress synchronizer facet_stress_synchronizer->updateSchemes([&](auto && scheme, auto && proc, auto && /*direction*/) { auto it_element = scheme.begin(); for (auto && element : scheme) { auto && facet_check = inserter->getCheckFacets( element.type, element.ghost_type)(element.element); // slow access // here if (facet_check) { auto && connected_elements = mesh_facets.getElementToSubelement( element.type, element.ghost_type)(element.element); // slow access // here auto && rank_left = element_synchronizer.getRank(connected_elements[0]); auto && rank_right = element_synchronizer.getRank(connected_elements[1]); // keep element if the element is still a boundary element between two // processors if ((rank_left == Int(proc) and rank_right == my_rank) or (rank_left == my_rank and rank_right == Int(proc))) { *it_element = element; ++it_element; } } } scheme.resize(it_element - scheme.begin()); }); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::updateFacetStressSynchronizer() { if (facet_stress_synchronizer != nullptr) { const auto & rank_to_element = mesh.getElementSynchronizer().getElementToRank(); const auto & facet_checks = inserter->getCheckFacets(); const auto & mesh_facets = inserter->getMeshFacets(); const auto & element_to_facet = mesh_facets.getElementToSubelement(); UInt rank = mesh.getCommunicator().whoAmI(); facet_stress_synchronizer->updateSchemes( [&](auto & scheme, auto & proc, auto & /*direction*/) { UInt el = 0; for (auto && element : scheme) { if (not facet_checks(element)) continue; const auto & next_el = element_to_facet(element); UInt rank_left = rank_to_element(next_el[0]); UInt rank_right = rank_to_element(next_el[1]); if ((rank_left == rank and rank_right == proc) or (rank_left == proc and rank_right == rank)) { scheme[el] = element; ++el; } } scheme.resize(el); }); } } /* -------------------------------------------------------------------------- */ template <typename T> void SolidMechanicsModelCohesive::packFacetStressDataHelper( const ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & elements) const { packUnpackFacetStressDataHelper<T, true>( const_cast<ElementTypeMapArray<T> &>(data_to_pack), buffer, elements); } /* -------------------------------------------------------------------------- */ template <typename T> void SolidMechanicsModelCohesive::unpackFacetStressDataHelper( ElementTypeMapArray<T> & data_to_unpack, CommunicationBuffer & buffer, const Array<Element> & elements) const { packUnpackFacetStressDataHelper<T, false>(data_to_unpack, buffer, elements); } /* -------------------------------------------------------------------------- */ template <typename T, bool pack_helper> void SolidMechanicsModelCohesive::packUnpackFacetStressDataHelper( ElementTypeMapArray<T> & data_to_pack, CommunicationBuffer & buffer, const Array<Element> & elements) const { ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; UInt nb_quad_per_elem = 0; UInt sp2 = spatial_dimension * spatial_dimension; UInt nb_component = sp2 * 2; bool element_rank = false; Mesh & mesh_facets = inserter->getMeshFacets(); Array<T> * vect = nullptr; Array<std::vector<Element>> * element_to_facet = nullptr; auto & fe_engine = this->getFEEngine("FacetsFEEngine"); for (auto && el : elements) { if (el.type == _not_defined) AKANTU_EXCEPTION( "packUnpackFacetStressDataHelper called with wrong inputs"); if (el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; vect = &data_to_pack(el.type, el.ghost_type); element_to_facet = &(mesh_facets.getElementToSubelement(el.type, el.ghost_type)); nb_quad_per_elem = fe_engine.getNbIntegrationPoints(el.type, el.ghost_type); } if (pack_helper) element_rank = (*element_to_facet)(el.element)[0].ghost_type != _not_ghost; else element_rank = (*element_to_facet)(el.element)[0].ghost_type == _not_ghost; for (UInt q = 0; q < nb_quad_per_elem; ++q) { Vector<T> data(vect->storage() + (el.element * nb_quad_per_elem + q) * nb_component + element_rank * sp2, sp2); if (pack_helper) buffer << data; else buffer >> data; } } } /* -------------------------------------------------------------------------- */ UInt SolidMechanicsModelCohesive::getNbQuadsForFacetCheck( const Array<Element> & elements) const { UInt nb_quads = 0; UInt nb_quad_per_facet = 0; ElementType current_element_type = _not_defined; GhostType current_ghost_type = _casper; auto & fe_engine = this->getFEEngine("FacetsFEEngine"); for (auto & el : elements) { if (el.type != current_element_type || el.ghost_type != current_ghost_type) { current_element_type = el.type; current_ghost_type = el.ghost_type; nb_quad_per_facet = fe_engine.getNbIntegrationPoints(el.type, el.ghost_type); } nb_quads += nb_quad_per_facet; } return nb_quads; } /* -------------------------------------------------------------------------- */ UInt SolidMechanicsModelCohesive::getNbData( const Array<Element> & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); UInt size = 0; if (elements.size() == 0) return 0; /// regular element case if (elements(0).kind() == _ek_regular) { switch (tag) { - case _gst_smmc_facets: { - size += elements.size() * sizeof(bool); - break; - } + // case _gst_smmc_facets: { + // size += elements.size() * sizeof(bool); + // break; + // } case _gst_smmc_facets_stress: { UInt nb_quads = getNbQuadsForFacetCheck(elements); size += nb_quads * spatial_dimension * spatial_dimension * sizeof(Real); break; } case _gst_material_id: { for (auto && element : elements) { if (Mesh::getSpatialDimension(element.type) == (spatial_dimension - 1)) size += sizeof(UInt); } size += SolidMechanicsModel::getNbData(elements, tag); break; } default: { size += SolidMechanicsModel::getNbData(elements, tag); } } } /// cohesive element case else if (elements(0).kind() == _ek_cohesive) { switch (tag) { case _gst_material_id: { size += elements.size() * sizeof(UInt); break; } case _gst_smm_boundary: { UInt nb_nodes_per_element = 0; for (auto && el : elements) { nb_nodes_per_element += Mesh::getNbNodesPerElement(el.type); } // force, displacement, boundary size += nb_nodes_per_element * spatial_dimension * (2 * sizeof(Real) + sizeof(bool)); break; } default: break; } if (tag != _gst_material_id && tag != _gst_smmc_facets) { splitByMaterial(elements, [&](auto && mat, auto && elements) { size += mat.getNbData(elements, tag); }); } } AKANTU_DEBUG_OUT(); return size; } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::packData( CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) const { AKANTU_DEBUG_IN(); if (elements.size() == 0) return; if (elements(0).kind() == _ek_regular) { switch (tag) { - case _gst_smmc_facets: { - packElementalDataHelper(inserter->getInsertionFacetsByElement(), buffer, - elements, false, getFEEngine()); - break; - } + // case _gst_smmc_facets: { + // packElementalDataHelper(inserter->getInsertionFacetsByElement(), buffer, + // elements, false, getFEEngine()); + // break; + // } case _gst_smmc_facets_stress: { packFacetStressDataHelper(facet_stress, buffer, elements); break; } case _gst_material_id: { for (auto && element : elements) { if (Mesh::getSpatialDimension(element.type) != (spatial_dimension - 1)) continue; buffer << material_index(element); } SolidMechanicsModel::packData(buffer, elements, tag); break; } default: { SolidMechanicsModel::packData(buffer, elements, tag); } } AKANTU_DEBUG_OUT(); return; } if (elements(0).kind() == _ek_cohesive) { switch (tag) { case _gst_material_id: { packElementalDataHelper(material_index, buffer, elements, false, getFEEngine("CohesiveFEEngine")); break; } case _gst_smm_boundary: { packNodalDataHelper(*internal_force, buffer, elements, mesh); packNodalDataHelper(*velocity, buffer, elements, mesh); packNodalDataHelper(*blocked_dofs, buffer, elements, mesh); break; } default: {} } if (tag != _gst_material_id && tag != _gst_smmc_facets) { splitByMaterial(elements, [&](auto && mat, auto && elements) { mat.packData(buffer, elements, tag); }); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void SolidMechanicsModelCohesive::unpackData(CommunicationBuffer & buffer, const Array<Element> & elements, const SynchronizationTag & tag) { AKANTU_DEBUG_IN(); if (elements.size() == 0) return; if (elements(0).kind() == _ek_regular) { switch (tag) { - case _gst_smmc_facets: { - unpackElementalDataHelper(inserter->getInsertionFacetsByElement(), buffer, - elements, false, getFEEngine()); - break; - } + // case _gst_smmc_facets: { + // unpackElementalDataHelper(inserter->getInsertionFacetsByElement(), buffer, + // elements, false, getFEEngine()); + // break; + // } case _gst_smmc_facets_stress: { unpackFacetStressDataHelper(facet_stress, buffer, elements); break; } case _gst_material_id: { for (auto && element : elements) { if (Mesh::getSpatialDimension(element.type) != (spatial_dimension - 1)) continue; UInt recv_mat_index; buffer >> recv_mat_index; UInt & mat_index = material_index(element); if (mat_index != UInt(-1)) continue; // add ghosts element to the correct material mat_index = recv_mat_index; auto & mat = dynamic_cast<MaterialCohesive &>(*materials[mat_index]); - mat.addFacet(element); + if (is_extrinsic) { + mat.addFacet(element); + } facet_material(element) = recv_mat_index; } SolidMechanicsModel::unpackData(buffer, elements, tag); break; } default: { SolidMechanicsModel::unpackData(buffer, elements, tag); } } AKANTU_DEBUG_OUT(); return; } if (elements(0).kind() == _ek_cohesive) { 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; // add ghosts element to the correct material mat_index = recv_mat_index; UInt index = materials[mat_index]->addElement(element); material_local_numbering(element) = index; } break; } case _gst_smm_boundary: { unpackNodalDataHelper(*internal_force, buffer, elements, mesh); unpackNodalDataHelper(*velocity, buffer, elements, mesh); unpackNodalDataHelper(*blocked_dofs, buffer, elements, mesh); break; } default: {} } if (tag != _gst_material_id && tag != _gst_smmc_facets) { splitByMaterial(elements, [&](auto && mat, auto && elements) { mat.unpackData(buffer, elements, tag); }); } } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ } // namespace akantu