diff --git a/doc/dev-doc/akantu.dox.j2 b/doc/dev-doc/akantu.dox.j2 index 1af6a6939..cfd839795 100644 --- a/doc/dev-doc/akantu.dox.j2 +++ b/doc/dev-doc/akantu.dox.j2 @@ -1,52 +1,55 @@ PROJECT_NAME = Akantu #PROJECT_NUMBER = {{ akantu_version }} STRIP_FROM_PATH = {{ akantu_source_path }} STRIP_FROM_INC_PATH = {{ akantu_source_path }} TAB_SIZE = 4 ALIASES = "rst=\verbatim embed:rst" \ "endrst=\endverbatim" QUIET = NO WARN_IF_UNDOCUMENTED = NO WARN_IF_DOC_ERROR = NO WARN_AS_ERROR = NO INPUT = {{ akantu_source_path }}/src \ {{ akantu_source_path }}/test/ci/includes_for_ci FILE_PATTERNS = *.c *.cc *.hh *.py EXCLUDE = {{ akantu_source_path }}/src/common/aka_fwd.hh \ {{ akantu_source_path }}/src/io/dumper/dumpable_dummy.hh {{ akantu_source_path }}/src/common/aka_config.hh.in RECURSIVE = YES EXAMPLE_PATH = {{ akantu_source_path }}/examples EXAMPLE_RECURSIVE = YES SOURCE_BROWSER = NO -GENERATE_HTML = NO +GENERATE_HTML = YES +HTML_OUTPUT = html_dox +CALL_GRAPH = YES +CALLER_GRAPH = YES GENERATE_HTMLHELP = NO USE_MATHJAX = YES GENERATE_LATEX = NO GENERATE_XML = YES XML_OUTPUT = xml DOXYGEN_INCLUDE_PATH = {{ akantu_source_path }}/src/common \ {{ akantu_source_path }}/src/fe_engine \ {{ akantu_source_path }}/src/mesh \ {{ akantu_source_path }}/src/model \ {{ akantu_source_path }}/test/ci/includes_for_ci ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES PREDEFINED = DOXYGEN \ __cplusplus=201402L \ "AKANTU_GET_MACRO(name, value, type) = type get##name() const;" \ "AKANTU_GET_MACRO_NOT_CONST(name, value, type) = type get##name();" EXPAND_AS_DEFINED = __BEGIN_AKANTU__ \ __END_AKANTU__ \ __BEGIN_AKANTU_DUMPER__ \ __END_AKANTU_DUMPER__ \ AKANTU_SET_MACRO \ AKANTU_GET_MACRO_DEREF_PTR \ AKANTU_GET_MACRO_BY_ELEMENT_TYPE \ AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST COLLABORATION_GRAPH = NO UML_LOOK = YES TEMPLATE_RELATIONS = YES CALL_GRAPH = YES CALLER_GRAPH = YES LOOKUP_CACHE_SIZE = 0 diff --git a/python/py_fe_engine.cc b/python/py_fe_engine.cc index dde7d3640..720717c50 100644 --- a/python/py_fe_engine.cc +++ b/python/py_fe_engine.cc @@ -1,258 +1,269 @@ /** * @file py_fe_engine.cc * * @author Guillaume Anciaux * @author Nicolas Richart * * @date creation: Wed Nov 27 2019 * @date last modification: Sat Dec 12 2020 * * @brief pybind11 interface to FEEngine * * * @section LICENSE * * Copyright (©) 2018-2021 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 "py_aka_array.hh" #include "py_aka_common.hh" /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ namespace py = pybind11; /* -------------------------------------------------------------------------- */ namespace akantu { void register_fe_engine(py::module & mod) { py::class_(mod, "Element") .def(py::init([](ElementType type, UInt id) { return new Element{type, id, _not_ghost}; })) .def(py::init([](ElementType type, UInt id, GhostType ghost_type) { return new Element{type, id, ghost_type}; })) .def("__lt__", [](Element & self, const Element & other) { return (self < other); }) .def("__repr__", [](Element & self) { return std::to_string(self); }); mod.attr("ElementNull") = ElementNull; py::class_(mod, "FEEngine") .def( "getNbIntegrationPoints", [](FEEngine & fem, const ElementType & type, const GhostType & ghost_type) { return fem.getNbIntegrationPoints(type, ghost_type); }, py::arg("type"), py::arg("ghost_type") = _not_ghost) .def( "gradientOnIntegrationPoints", [](FEEngine & fem, const Array & u, Array & nablauq, UInt nb_degree_of_freedom, ElementType type, GhostType ghost_type, const Array * filter_elements) { if (filter_elements == nullptr) { // This is due to the ArrayProxy that looses the // empty_filter information filter_elements = &empty_filter; } fem.gradientOnIntegrationPoints(u, nablauq, nb_degree_of_freedom, type, ghost_type, *filter_elements); }, py::arg("u"), py::arg("nablauq"), py::arg("nb_degree_of_freedom"), py::arg("type"), py::arg("ghost_type") = _not_ghost, py::arg("filter_elements") = nullptr) .def( "gradientOnIntegrationPoints", [](FEEngine & fem, const Array & u, Array & nablauq, UInt nb_degree_of_freedom, ElementType type, GhostType ghost_type) { fem.gradientOnIntegrationPoints(u, nablauq, nb_degree_of_freedom, type, ghost_type); }, py::arg("u"), py::arg("nablauq"), py::arg("nb_degree_of_freedom"), py::arg("type"), py::arg("ghost_type") = _not_ghost) .def( "interpolateOnIntegrationPoints", [](FEEngine & self, Array & u, Array & uq, UInt nb_degree_of_freedom, ElementType type, GhostType ghost_type) { self.interpolateOnIntegrationPoints(u, uq, nb_degree_of_freedom, type, ghost_type); }, py::arg("u"), py::arg("uq"), py::arg("nb_degree_of_freedom"), py::arg("type"), py::arg("ghost_type") = _not_ghost) .def( "interpolateOnIntegrationPoints", [](FEEngine & self, Array & u, Array & uq, UInt nb_degree_of_freedom, ElementType type, GhostType ghost_type, const Array * filter_elements) { if (filter_elements == nullptr) { // This is due to the ArrayProxy that looses the // empty_filter information filter_elements = &empty_filter; } self.interpolateOnIntegrationPoints(u, uq, nb_degree_of_freedom, type, ghost_type, *filter_elements); }, py::arg("u"), py::arg("uq"), py::arg("nb_degree_of_freedom"), py::arg("type"), py::arg("ghost_type") = _not_ghost, py::arg("filter_elements") = nullptr) .def( "interpolateOnIntegrationPoints", [](FEEngine & self, const Array & u, ElementTypeMapArray & uq, const ElementTypeMapArray * filter_elements) { self.interpolateOnIntegrationPoints(u, uq, filter_elements); }, py::arg("u"), py::arg("uq"), py::arg("filter_elements") = nullptr) .def( "computeIntegrationPointsCoordinates", [](FEEngine & self, ElementTypeMapArray & coordinates, const ElementTypeMapArray * filter_elements) -> decltype(auto) { return self.computeIntegrationPointsCoordinates(coordinates, filter_elements); }, py::arg("coordinates"), py::arg("filter_elements") = nullptr) + .def( + "computeIntegrationPointsCoordinates", + [](FEEngine & self, Array & coordinates, ElementType type, + GhostType ghost_type, + const Array & filter_elements) -> decltype(auto) { + return self.computeIntegrationPointsCoordinates( + coordinates, type, ghost_type, filter_elements); + }, + py::arg("coordinates"), py::arg("type"), + py::arg("ghost_type") = _not_ghost, + py::arg("filter_elements") = nullptr) .def( "assembleFieldLumped", [](FEEngine & fem, const std::function &, const Element &)> & field_funct, const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager, ElementType type, GhostType ghost_type) { fem.assembleFieldLumped(field_funct, matrix_id, dof_id, dof_manager, type, ghost_type); }, py::arg("field_funct"), py::arg("matrix_id"), py::arg("dof_id"), py::arg("dof_manager"), py::arg("type"), py::arg("ghost_type") = _not_ghost) .def( "assembleFieldMatrix", [](FEEngine & fem, const std::function &, const Element &)> & field_funct, const ID & matrix_id, const ID & dof_id, DOFManager & dof_manager, ElementType type, GhostType ghost_type = _not_ghost) { fem.assembleFieldMatrix(field_funct, matrix_id, dof_id, dof_manager, type, ghost_type); }, py::arg("field_funct"), py::arg("matrix_id"), py::arg("dof_id"), py::arg("dof_manager"), py::arg("type"), py::arg("ghost_type") = _not_ghost) .def("getElementInradius", [](FEEngine & self, const Element & element) { return self.getElementInradius(element); }) .def("getNormalsOnIntegrationPoints", &FEEngine::getNormalsOnIntegrationPoints, py::arg("type"), py::arg("ghost_type") = _not_ghost, py::return_value_policy::reference) .def( "computeNtb", [](FEEngine & fem, const Array & bs, Array & Ntbs, ElementType type, GhostType ghost_type) { fem.computeNtb(bs, Ntbs, type, ghost_type); }, py::arg("bs"), py::arg("Ntbs"), py::arg("type"), py::arg("ghost_type") = _not_ghost) .def( "computeNtb", [](FEEngine & fem, const Array & bs, Array & Ntbs, ElementType type, GhostType ghost_type, const Array * filter_elements) { if (filter_elements == nullptr) { // This is due to the ArrayProxy that looses the // empty_filter information filter_elements = &empty_filter; } fem.computeNtb(bs, Ntbs, type, ghost_type, *filter_elements); }, py::arg("Ds"), py::arg("BtDs"), py::arg("type"), py::arg("ghost_type") = _not_ghost, py::arg("filter_elements") = nullptr) .def( "computeBtD", [](FEEngine & fem, const Array & Ds, Array & BtDs, ElementType type, GhostType ghost_type) { fem.computeBtD(Ds, BtDs, type, ghost_type); }, py::arg("Ds"), py::arg("BtDs"), py::arg("type"), py::arg("ghost_type") = _not_ghost) .def( "computeBtD", [](FEEngine & fem, const Array & Ds, Array & BtDs, ElementType type, GhostType ghost_type, const Array * filter_elements) { if (filter_elements == nullptr) { // This is due to the ArrayProxy that looses the // empty_filter information filter_elements = &empty_filter; } fem.computeBtD(Ds, BtDs, type, ghost_type, *filter_elements); }, py::arg("Ds"), py::arg("BtDs"), py::arg("type"), py::arg("ghost_type") = _not_ghost, py::arg("filter_elements") = nullptr) .def("getShapes", &FEEngine::getShapes, py::arg("type"), py::arg("ghost_type") = _not_ghost, py::arg("id") = 0, py::return_value_policy::reference) .def("getShapesDerivatives", &FEEngine::getShapesDerivatives, py::arg("type"), py::arg("ghost_type") = _not_ghost, py::arg("id") = 0, py::return_value_policy::reference) .def( "integrate", [](FEEngine & fem, const Array & f, Array & intf, UInt nb_degree_of_freedom, ElementType type, GhostType ghost_type) { fem.integrate(f, intf, nb_degree_of_freedom, type, ghost_type); }, py::arg("f"), py::arg("intf"), py::arg("nb_degree_of_feedom"), py::arg("type"), py::arg("ghost_type") = _not_ghost) .def( "integrate", [](FEEngine & fem, const Array & f, Array & intf, UInt nb_degree_of_freedom, ElementType type, GhostType ghost_type, const Array * filter_elements) { if (filter_elements == nullptr) { // This is due to the ArrayProxy that looses the // empty_filter information filter_elements = &empty_filter; } fem.integrate(f, intf, nb_degree_of_freedom, type, ghost_type, *filter_elements); }, py::arg("f"), py::arg("intf"), py::arg("nb_degree_of_feedom"), py::arg("type"), py::arg("ghost_type") = _not_ghost, py::arg("filter_elements") = nullptr) .def("getCohesiveElementType", &FEEngine::getCohesiveElementType); py::class_(mod, "IntegrationPoint"); } } // namespace akantu diff --git a/python/py_material.cc b/python/py_material.cc index 1dfa2df7e..5d9e26dc2 100644 --- a/python/py_material.cc +++ b/python/py_material.cc @@ -1,404 +1,446 @@ /** * @file py_material.cc * * @author Guillaume Anciaux * @author Mohit Pundir * @author Nicolas Richart * * @date creation: Thu Jun 20 2019 * @date last modification: Fri Apr 09 2021 * * @brief pybind11 interface to Material * * * @section LICENSE * * Copyright (©) 2018-2021 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 "py_aka_array.hh" #include "py_akantu_pybind11_compatibility.hh" /* -------------------------------------------------------------------------- */ #include #include #if defined(AKANTU_COHESIVE_ELEMENT) +#include #include #include #include #endif #include /* -------------------------------------------------------------------------- */ #include #include #include /* -------------------------------------------------------------------------- */ namespace py = pybind11; /* -------------------------------------------------------------------------- */ namespace akantu { namespace { template class PyMaterial : public _Material { public: /* Inherit the constructors */ using _Material::_Material; ~PyMaterial() override = default; void initMaterial() override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, _Material, initMaterial, ); }; void computeStress(ElementType el_type, GhostType ghost_type = _not_ghost) override { // NOLINTNEXTLINE PYBIND11_OVERRIDE_PURE(void, _Material, computeStress, el_type, ghost_type); } void computeTangentModuli(ElementType el_type, Array & tangent_matrix, GhostType ghost_type = _not_ghost) override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, _Material, computeTangentModuli, el_type, tangent_matrix, ghost_type); } void computePotentialEnergy(ElementType el_type) override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, _Material, computePotentialEnergy, el_type); } Real getPushWaveSpeed(const Element & element) const override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(Real, _Material, getPushWaveSpeed, element); } Real getShearWaveSpeed(const Element & element) const override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(Real, _Material, getShearWaveSpeed, element); } - template - void registerInternal(const std::string & name, UInt nb_component) { - auto && internal = std::make_shared>(name, *this); - AKANTU_DEBUG_INFO("alloc internal " << name << " " - << &this->internals[name]); + // template + // void registerInternal(const std::string & name, UInt nb_component) { + // auto && internal = std::make_shared>(name, *this); + // AKANTU_DEBUG_INFO("alloc internal " << name << " " + // << &this->internals[name]); - internal->initialize(nb_component); - this->internals[name] = internal; - } + // internal->initialize(nb_component); + // this->internals[name] = internal; + // } - protected: - std::map> internals; + // protected: + // std::map> internals; }; /* ------------------------------------------------------------------------ */ template void register_material_classes(py::module & mod, const std::string & name) { py::class_<_Material, Material, Parsable, PyMaterial<_Material>>( mod, name.c_str(), py::multiple_inheritance()) .def(py::init()); } #if defined(AKANTU_COHESIVE_ELEMENT) // trampoline for the cohesive materials template class PyMaterialCohesive : public _Material { public: /* Inherit the constructors */ using _Material::_Material; ~PyMaterialCohesive() override = default; void initMaterial() override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, _Material, initMaterial, ); }; void computeStress(ElementType el_type, GhostType ghost_type = _not_ghost) final {} void checkInsertion(bool check_only) override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, _Material, checkInsertion, check_only); } void computeTraction(const Array & normal, ElementType el_type, GhostType ghost_type = _not_ghost) override { // NOLINTNEXTLINE PYBIND11_OVERRIDE_PURE(void, _Material, computeTraction, normal, el_type, ghost_type); } void computeTangentModuli(ElementType el_type, Array & tangent_matrix, GhostType ghost_type = _not_ghost) final {} void computeTangentTraction(ElementType el_type, Array & tangent_matrix, const Array & normal, GhostType ghost_type = _not_ghost) override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, _Material, computeTangentTraction, el_type, tangent_matrix, normal, ghost_type); } - template - void registerInternal(const std::string & name, UInt nb_component) { - auto && internal = - std::make_shared>(name, *this); - AKANTU_DEBUG_INFO("alloc internal " << name << " " - << &this->internals[name]); + // template + // void registerInternal(const std::string & name, UInt nb_component) { + // auto && internal = + // std::make_shared>(name, *this); + // AKANTU_DEBUG_INFO("alloc internal " << name << " " + // << &this->internals[name]); - internal->initialize(nb_component); - this->internals[name] = internal; - } + // internal->initialize(nb_component); + // this->internals[name] = internal; + // } - protected: - std::map> internals; + // protected: + // std::map> internals; }; // trampoline for the cohesive material inheritance where computeTraction is // not pure virtual template - class PyMaterialCohesiveDaughters : public PyMaterialCohesive<_Material> { + class PyMaterialCohesiveDaughter : public PyMaterialCohesive<_Material> { public: /* Inherit the constructors */ using PyMaterialCohesive<_Material>::PyMaterialCohesive; - ~PyMaterialCohesiveDaughters() override = default; + ~PyMaterialCohesiveDaughter() override = default; void computeTraction(const Array & normal, ElementType el_type, GhostType ghost_type = _not_ghost) override { // NOLINTNEXTLINE PYBIND11_OVERRIDE(void, _Material, computeTraction, normal, el_type, ghost_type); } }; template void register_material_cohesive_classes(py::module & mod, const std::string & name) { py::class_<_Material, MaterialCohesive, - PyMaterialCohesiveDaughters<_Material>>( + PyMaterialCohesiveDaughter<_Material>>( mod, name.c_str(), py::multiple_inheritance()) - .def(py::init()); + .def(py::init()) + .def("computeTraction", [](_Material & self, const Array & normal, + ElementType el_type, GhostType ghost_type) { + auto & ref = + dynamic_cast &>(self); + return ref.computeTraction(normal, el_type, ghost_type); + }); } #endif /* ------------------------------------------------------------------------ */ template void register_internal_field(py::module & mod, const std::string & name) { py::class_, ElementTypeMapArray, std::shared_ptr>>( mod, ("InternalField" + name).c_str()); } - } // namespace /* -------------------------------------------------------------------------- */ void register_material(py::module & mod) { py::class_(mod, "MaterialFactory") .def_static( "getInstance", []() -> MaterialFactory & { return Material::getFactory(); }, py::return_value_policy::reference) .def("registerAllocator", [](MaterialFactory & self, const std::string id, py::function func) { self.registerAllocator( id, [func, id](UInt dim, const ID & /*unused*/, SolidMechanicsModel & model, const ID & option) -> std::unique_ptr { py::object obj = func(dim, id, model, option); auto & ptr = py::cast(obj); obj.release(); return std::unique_ptr(&ptr); }); }) .def("getPossibleAllocators", &MaterialFactory::getPossibleAllocators); register_internal_field(mod, "Real"); register_internal_field(mod, "UInt"); py::class_>( mod, "Material", py::multiple_inheritance()) .def(py::init()) .def( "getGradU", [](Material & self, ElementType el_type, GhostType ghost_type = _not_ghost) -> decltype(auto) { return self.getGradU(el_type, ghost_type); }, py::arg("el_type"), py::arg("ghost_type") = _not_ghost, py::return_value_policy::reference) .def( "getStress", [](Material & self, ElementType el_type, GhostType ghost_type = _not_ghost) -> decltype(auto) { return self.getStress(el_type, ghost_type); }, py::arg("el_type"), py::arg("ghost_type") = _not_ghost, py::return_value_policy::reference) .def( "getPotentialEnergy", [](Material & self, ElementType el_type) -> decltype(auto) { return self.getPotentialEnergy(el_type); }, py::arg("el_type"), py::return_value_policy::reference) .def( "getPotentialEnergy", [](Material & self, ElementType el_type, UInt index) -> Real { return self.getPotentialEnergy(el_type, index); }, py::arg("el_type"), py::arg("index")) .def("getPotentialEnergy", [](Material & self) -> Real { return self.getPotentialEnergy(); }) .def("initMaterial", &Material::initMaterial) .def("getModel", &Material::getModel) .def("registerInternalReal", [](Material & self, const std::string & name, UInt nb_component) { - return dynamic_cast &>(self) - .registerInternal(name, nb_component); + return self.registerInternal(name, nb_component); }) .def("registerInternalUInt", [](Material & self, const std::string & name, UInt nb_component) { - return dynamic_cast &>(self) - .registerInternal(name, nb_component); + return self.registerInternal(name, nb_component); }) + // .def("registerInternalReal", + // [](Material & self, const std::string & name, UInt nb_component) { + // return dynamic_cast &>(self) + // .registerInternal(name, nb_component); + // }) + // .def("registerInternalUInt", + // [](Material & self, const std::string & name, UInt nb_component) { + // return dynamic_cast &>(self) + // .registerInternal(name, nb_component); + // }) .def( "getInternalReal", [](Material & self, const ID & id) -> decltype(auto) { return self.getInternal(id); }, py::arg("id"), py::return_value_policy::reference) .def( "getInternalUInt", [](Material & self, const ID & id) -> decltype(auto) { return self.getInternal(id); }, py::arg("id"), py::return_value_policy::reference) .def( "getElementFilter", [](Material & self) -> decltype(auto) { return self.getElementFilter(); }, py::return_value_policy::reference) /* * These functions override the `Parsable` interface. * This ensure that the `updateInternalParameters()` function is called. */ .def( "setReal", [](Material & self, const ID & name, const Real value) -> void { self.setParam(name, value); return; }, py::arg("name"), py::arg("value")) .def( "setBool", [](Material & self, const ID & name, const bool value) -> void { self.setParam(name, value); return; }, py::arg("name"), py::arg("value")) .def( "setString", [](Material & self, const ID & name, const std::string & value) -> void { self.setParam(name, value); return; }, py::arg("name"), py::arg("value")) .def( "setInt", [](Material & self, const ID & name, const int value) -> void { self.setParam(name, value); return; }, py::arg("name"), py::arg("value")) - + .def( + "setDefaultValueToInternalReal", + [](Material & self, const ID & int_id, const Real value) -> void { + return self.setDefaultValueToInternal(int_id, value); + }, + py::arg("int_id"), py::arg("value")) + .def( + "setDefaultValueToInternalUInt", + [](Material & self, const ID & int_id, const UInt value) -> void { + return self.setDefaultValueToInternal(int_id, value); + }, + py::arg("int_id"), py::arg("value")) .def("getPushWaveSpeed", &Material::getPushWaveSpeed) .def("getShearWaveSpeed", &Material::getShearWaveSpeed) .def("__repr__", [](Material & self) { std::stringstream sstr; sstr << self; return sstr.str(); }); register_material_classes>(mod, "MaterialElastic2D"); register_material_classes>(mod, "MaterialElastic3D"); #if defined(AKANTU_COHESIVE_ELEMENT) /* ------------------------------------------------------------------------ */ - py::class_>( - mod, "MaterialCohesive", py::multiple_inheritance()) + py::class_>(mod, "MaterialCohesive", + py::multiple_inheritance()) .def(py::init()) .def("registerInternalReal", [](MaterialCohesive & self, const std::string & name, UInt nb_component) { - auto & ref = - dynamic_cast &>( - self); - return ref.registerInternal(name, nb_component); + return self.registerCohesiveInternal(name, nb_component); }) .def("registerInternalUInt", [](MaterialCohesive & self, const std::string & name, UInt nb_component) { - return dynamic_cast &>(self) - .registerInternal(name, nb_component); + return self.registerCohesiveInternal(name, nb_component); }) + // .def("registerInternalReal", + // [](MaterialCohesive & self, const std::string & name, + // UInt nb_component) { + // auto & ref = + // dynamic_cast &>(self); + // return ref.registerInternal(name, nb_component); + // }) + // .def("registerInternalUInt", + // [](MaterialCohesive & self, const std::string & name, + // UInt nb_component) { + // return dynamic_cast + // &>(self) + // .registerInternal(name, nb_component); .def( "getFacetFilter", [](MaterialCohesive & self) -> decltype(auto) { return self.getFacetFilter(); }, py::return_value_policy::reference) .def( "getFacetFilter", [](MaterialCohesive & self, ElementType type, GhostType ghost_type) -> decltype(auto) { return self.getFacetFilter(type, ghost_type); }, py::arg("type"), py::arg("ghost_type") = _not_ghost, py::return_value_policy::reference) .def( "getOpening", [](MaterialCohesive & self, ElementType type, GhostType ghost_type) -> decltype(auto) { return self.getOpening(type, ghost_type); }, py::arg("type"), py::arg("ghost_type") = _not_ghost, py::return_value_policy::reference) .def( "getTraction", [](MaterialCohesive & self, ElementType type, GhostType ghost_type) -> decltype(auto) { return self.getTraction(type, ghost_type); }, py::arg("type"), py::arg("ghost_type") = _not_ghost, - py::return_value_policy::reference); + py::return_value_policy::reference) + .def( + "computeTraction", + [](MaterialCohesive & self, GhostType ghost_type) { + return self.computeTraction(ghost_type); + }, + py::arg("ghost_type") = _not_ghost) + .def("getNormalsAtQuads", &MaterialCohesive::getNormalsAtQuads); register_material_cohesive_classes>( mod, "MaterialCohesiveLinear2D"); register_material_cohesive_classes>( mod, "MaterialCohesiveLinear3D"); register_material_cohesive_classes>( mod, "MaterialCohesiveLinearFriction2D"); register_material_cohesive_classes>( mod, "MaterialCohesiveLinearFriction3D"); #endif } } // namespace akantu diff --git a/src/model/solid_mechanics/material.cc b/src/model/solid_mechanics/material.cc index deb835bdf..a7e9f8ff1 100644 --- a/src/model/solid_mechanics/material.cc +++ b/src/model/solid_mechanics/material.cc @@ -1,1214 +1,1298 @@ /** * @file material.cc * * @author Guillaume Anciaux * @author Fabian Barras * @author Aurelia Isabel Cuba Ramos * @author Lucas Frerot * @author Daniel Pino Muñoz * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Tue Jul 27 2010 * @date last modification: Fri Apr 09 2021 * * @brief Implementation of the common part of the material class * * * @section LICENSE * * Copyright (©) 2010-2021 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 "mesh_iterators.hh" #include "solid_mechanics_model.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ Material::Material(SolidMechanicsModel & model, const ID & id) : Parsable(ParserType::_material, id), id(id), fem(model.getFEEngine()), model(model), spatial_dimension(this->model.getSpatialDimension()), element_filter("element_filter", 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), interpolation_inverse_coordinates("interpolation inverse coordinates", *this), interpolation_points_matrices("interpolation points matrices", *this), eigen_grad_u(model.getSpatialDimension(), model.getSpatialDimension(), 0.) { AKANTU_DEBUG_IN(); this->registerParam("eigen_grad_u", eigen_grad_u, _pat_parsable, "EigenGradU"); /// for each connectivity types allocate the element filer array of the /// material element_filter.initialize(model.getMesh(), _spatial_dimension = spatial_dimension, _element_kind = _ek_regular); this->initialize(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Material::Material(SolidMechanicsModel & model, UInt dim, const Mesh & mesh, FEEngine & fe_engine, const ID & id) : Parsable(ParserType::_material, id), id(id), fem(fe_engine), model(model), spatial_dimension(dim), element_filter("element_filter", 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("piola_kirchhoff_2", *this, dim, fe_engine, this->element_filter), potential_energy("potential_energy", *this, dim, fe_engine, this->element_filter), 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), eigen_grad_u(dim, dim, 0.) { AKANTU_DEBUG_IN(); element_filter.initialize(mesh, _spatial_dimension = spatial_dimension, _element_kind = _ek_regular); this->initialize(); 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(); } this->resizeInternals(); auto dim = spatial_dimension; for (const auto & type : element_filter.elementTypes(_element_kind = _ek_regular)) { for (auto & eigen_gradu : make_view(eigengradu(type), dim, dim)) { eigen_gradu = eigen_grad_u; } } is_init = true; updateInternalParameters(); AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ +template +void registerInternal(const std::string & name, UInt nb_component) { + AKANTU_TO_IMPLEMENT(); +}; + +template <> +void Material::registerInternal(const std::string & name, + UInt nb_component) { + auto && internal = std::make_shared>(name, *this); + internal->initialize(nb_component); + this->internals[name] = internal; +} +template <> +void Material::registerInternal(const std::string & name, + UInt nb_component) { + auto && internal = std::make_shared>(name, *this); + internal->initialize(nb_component); + this->internals[name] = internal; +} + +/* -------------------------------------------------------------------------- + */ +template +void Material::setDefaultValueToInternal(const ID & int_id, const T value) { + AKANTU_TO_IMPLEMENT(); +}; + +template <> +void Material::setDefaultValueToInternal(const ID & int_id, + const Real value) { + auto & internal_field = this->getInternal(int_id); + internal_field.setDefaultValue(value); +}; + +template <> +void Material::setDefaultValueToInternal(const ID & int_id, + const UInt value) { + auto & internal_field = this->getInternal(int_id); + internal_field.setDefaultValue(value); +}; + +// template <> +// void Material::setDefaultValueToInternal(const ID & int_id, +// const bool value) { +// auto & internal_field = this->getInternal(int_id); +// internal_field.setDefaultValue(value); +// }; + +/* -------------------------------------------------------------------------- + */ void Material::savePreviousState() { AKANTU_DEBUG_IN(); for (auto pair : internal_vectors_real) { if (pair.second->hasHistory()) { pair.second->saveCurrentValues(); } } AKANTU_DEBUG_OUT(); } -/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- + */ void Material::restorePreviousState() { AKANTU_DEBUG_IN(); for (auto pair : internal_vectors_real) { if (pair.second->hasHistory()) { pair.second->restorePreviousValues(); } } AKANTU_DEBUG_OUT(); } -/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- + */ /** - * Compute the internal forces by assembling @f$\int_{e} \sigma_e \frac{\partial - * \varphi}{\partial X} dX @f$ + * Compute the internal forces by assembling @f$\int_{e} \sigma_e + * \frac{\partial \varphi}{\partial X} dX @f$ * * @param[in] ghost_type compute the internal forces for _ghost or _not_ghost * element */ void Material::assembleInternalForces(GhostType ghost_type) { AKANTU_DEBUG_IN(); UInt spatial_dimension = model.getSpatialDimension(); if (!finite_deformation) { auto & internal_force = const_cast &>(model.getInternalForce()); // Mesh & mesh = fem.getMesh(); for (auto && type : element_filter.elementTypes(spatial_dimension, ghost_type)) { Array & elem_filter = element_filter(type, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element == 0) { continue; } const Array & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); UInt size_of_shapes_derivatives = shapes_derivatives.getNbComponent(); UInt nb_quadrature_points = fem.getNbIntegrationPoints(type, ghost_type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); /// compute @f$\sigma \frac{\partial \varphi}{\partial X}@f$ by /// @f$\mathbf{B}^t \mathbf{\sigma}_q@f$ auto * sigma_dphi_dx = new Array(nb_element * nb_quadrature_points, size_of_shapes_derivatives, "sigma_x_dphi_/_dX"); fem.computeBtD(stress(type, ghost_type), *sigma_dphi_dx, type, ghost_type, elem_filter); /** * 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$ */ auto * 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, type, ghost_type, elem_filter); delete sigma_dphi_dx; /// assemble model.getDOFManager().assembleElementalArrayLocalArray( *int_sigma_dphi_dx, internal_force, type, 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] 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.empty()) { 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->StoCauchy<1>(type, ghost_type); break; case 2: this->StoCauchy<2>(type, ghost_type); break; case 3: this->StoCauchy<3>(type, ghost_type); break; } } AKANTU_DEBUG_OUT(); } -/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- + */ template void Material::StoCauchy(ElementType el_type, GhostType ghost_type) { AKANTU_DEBUG_IN(); auto gradu_it = this->gradu(el_type, ghost_type).begin(dim, dim); auto gradu_end = this->gradu(el_type, ghost_type).end(dim, dim); auto piola_it = this->piola_kirchhoff_2(el_type, ghost_type).begin(dim, dim); auto stress_it = this->stress(el_type, ghost_type).begin(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; auto F_tensor = gradUToF(grad_u); this->StoCauchy(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$ + * Compute the stiffness matrix by assembling @f$\int_{\omega} B^t \times + * D \times B d\omega @f$ * * @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(ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); Array & elem_filter = element_filter(type, ghost_type); if (elem_filter.empty()) { AKANTU_DEBUG_OUT(); return; } // 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); auto * tangent_stiffness_matrix = new Array(nb_element * nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); tangent_stiffness_matrix->zero(); computeTangentModuli(type, *tangent_stiffness_matrix, ghost_type); /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_d_b_size = dim * nb_nodes_per_element; auto * bt_d_b = new Array(nb_element * nb_quadrature_points, bt_d_b_size * bt_d_b_size, "B^t*D*B"); fem.computeBtDB(*tangent_stiffness_matrix, *bt_d_b, 4, type, ghost_type, elem_filter); delete tangent_stiffness_matrix; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ auto * 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(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); auto * shapes_derivatives_filtered = new Array( nb_element * nb_quadrature_points, dim * nb_nodes_per_element, "shapes derivatives filtered"); FEEngine::filterElementalData(fem.getMesh(), shapes_derivatives, *shapes_derivatives_filtered, type, ghost_type, elem_filter); /// compute @f$\mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ UInt bt_s_b_size = dim * nb_nodes_per_element; auto * 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); auto shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin( spatial_dimension, nb_nodes_per_element); auto Bt_S_B_it = bt_s_b->begin(bt_s_b_size, bt_s_b_size); auto Bt_S_B_end = bt_s_b->end(bt_s_b_size, bt_s_b_size); auto 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) { auto & Bt_S_B = *Bt_S_B_it; const auto & Piola_kirchhoff_matrix = *piola_it; setCauchyStressMatrix(Piola_kirchhoff_matrix, S); VoigtHelper::transferBMatrixToBNL(*shapes_derivatives_filtered_it, B, nb_nodes_per_element); Bt_S.template mul(B, S); Bt_S_B.template mul(Bt_S, B); } delete shapes_derivatives_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ auto * 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(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); auto * tangent_stiffness_matrix = new Array(nb_element * nb_quadrature_points, tangent_size * tangent_size, "tangent_stiffness_matrix"); tangent_stiffness_matrix->zero(); computeTangentModuli(type, *tangent_stiffness_matrix, ghost_type); auto * shapes_derivatives_filtered = new Array( nb_element * nb_quadrature_points, dim * nb_nodes_per_element, "shapes derivatives filtered"); FEEngine::filterElementalData(fem.getMesh(), shapes_derivatives, *shapes_derivatives_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; auto * 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); auto shapes_derivatives_filtered_it = shapes_derivatives_filtered->begin( spatial_dimension, nb_nodes_per_element); auto Bt_D_B_it = bt_d_b->begin(bt_d_b_size, bt_d_b_size); auto grad_u_it = gradu_vect.begin(dim, dim); auto D_it = tangent_stiffness_matrix->begin(tangent_size, tangent_size); auto 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) { const auto & grad_u = *grad_u_it; const auto & D = *D_it; auto & 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.template mul(B, D); Bt_D_B.template 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$ auto * 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(_ghost_type = ghost_type)) { const Array & shapes_derivatives = fem.getShapesDerivatives(type, ghost_type); Array & elem_filter = element_filter(type, ghost_type); if (elem_filter.empty()) { 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); auto * 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; auto * bt_s = new Array(nb_element * nb_quadrature_points, bt_s_size, "B^t*S"); auto grad_u_it = this->gradu(type, ghost_type).begin(dim, dim); auto grad_u_end = this->gradu(type, ghost_type).end(dim, dim); auto 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 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) { auto & grad_u = *grad_u_it; auto & r = *bt_s_it; auto & S = *stress_it; 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; auto S_vect = Material::stressToVoigt(S); Matrix S_voigt(S_vect.storage(), stress_size, 1); r.template mul(B_tensor, S_voigt); } delete shapesd_filtered; /// compute @f$ k_e = \int_e \mathbf{B}^t * \mathbf{D} * \mathbf{B}@f$ auto * 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::computePotentialEnergyByElements() { AKANTU_DEBUG_IN(); for (auto type : element_filter.elementTypes(spatial_dimension, _not_ghost)) { computePotentialEnergy(type); } AKANTU_DEBUG_OUT(); } -/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- + */ void Material::computePotentialEnergy(ElementType /*unused*/) { AKANTU_DEBUG_IN(); AKANTU_TO_IMPLEMENT(); 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(const std::string & type) { AKANTU_DEBUG_IN(); if (type == "potential") { return getPotentialEnergy(); } AKANTU_DEBUG_OUT(); return 0.; } -/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- + */ Real Material::getEnergy(const 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 = nullptr; GhostType current_ghost_type = _casper; Array * result_vec = nullptr; 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() + static_cast(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); } } } } } -/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- + */ void Material::addElements(const Array & elements_to_add) { AKANTU_DEBUG_IN(); UInt mat_id = model.getMaterialIndex(name); for (const auto & element : elements_to_add) { auto index = this->addElement(element); model.material_index(element) = mat_id; model.material_local_numbering(element) = index; } this->resizeInternals(); AKANTU_DEBUG_OUT(); } -/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- + */ void Material::removeElements(const Array & elements_to_remove) { AKANTU_DEBUG_IN(); auto el_begin = elements_to_remove.begin(); auto el_end = elements_to_remove.end(); if (elements_to_remove.empty()) { return; } auto & mesh = this->model.getMesh(); ElementTypeMapArray material_local_new_numbering( "remove mat filter elem", id); material_local_new_numbering.initialize( mesh, _element_filter = &element_filter, _element_kind = _ek_not_defined, _with_nb_element = true); ElementTypeMapArray element_filter_tmp("element_filter_tmp", id); element_filter_tmp.initialize(mesh, _element_filter = &element_filter, _element_kind = _ek_not_defined); ElementTypeMap new_ids, element_ids; for_each_element( mesh, [&](auto && el) { if (not new_ids(el.type, el.ghost_type)) { element_ids(el.type, el.ghost_type) = 0; } auto & element_id = element_ids(el.type, el.ghost_type); auto l_el = Element{el.type, element_id, el.ghost_type}; if (std::find(el_begin, el_end, el) != el_end) { material_local_new_numbering(l_el) = UInt(-1); return; } element_filter_tmp(el.type, el.ghost_type).push_back(el.element); if (not new_ids(el.type, el.ghost_type)) { new_ids(el.type, el.ghost_type) = 0; } auto & new_id = new_ids(el.type, el.ghost_type); material_local_new_numbering(l_el) = new_id; model.material_local_numbering(el) = new_id; ++new_id; ++element_id; }, _element_filter = &element_filter, _element_kind = _ek_not_defined); for (auto ghost_type : ghost_types) { for (const auto & type : element_filter.elementTypes( _ghost_type = ghost_type, _element_kind = _ek_not_defined)) { element_filter(type, ghost_type) .copy(element_filter_tmp(type, ghost_type)); } } for (auto it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) { it->second->removeIntegrationPoints(material_local_new_numbering); } for (auto it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) { it->second->removeIntegrationPoints(material_local_new_numbering); } for (auto 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 (auto it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) { it->second->resize(); } for (auto it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) { it->second->resize(); } for (auto it = internal_vectors_bool.begin(); it != internal_vectors_bool.end(); ++it) { it->second->resize(); } AKANTU_DEBUG_OUT(); } -/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- + */ void Material::onElementsAdded(const Array & /*unused*/, const NewElementsEvent & /*unused*/) { this->resizeInternals(); } -/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- + */ void Material::onElementsRemoved( const Array & element_list, const ElementTypeMapArray & new_numbering, [[gnu::unused]] const RemovedElementsEvent & event) { UInt my_num = model.getInternalIndexFromID(getID()); ElementTypeMapArray material_local_new_numbering( "remove mat filter elem", getID()); auto el_begin = element_list.begin(); auto el_end = element_list.end(); for (auto && gt : ghost_types) { for (auto && type : new_numbering.elementTypes(_all_dimensions, gt, _ek_not_defined)) { if (not element_filter.exists(type, gt) || element_filter(type, gt).empty()) { continue; } auto & elem_filter = element_filter(type, gt); auto & mat_indexes = this->model.material_index(type, gt); auto & mat_loc_num = this->model.material_local_numbering(type, gt); auto 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); } auto & mat_renumbering = material_local_new_numbering(type, gt); const auto & renumbering = new_numbering(type, gt); Array elem_filter_tmp; UInt ni = 0; Element el{type, 0, gt}; 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 (auto it = internal_vectors_real.begin(); it != internal_vectors_real.end(); ++it) { it->second->removeIntegrationPoints(material_local_new_numbering); } for (auto it = internal_vectors_uint.begin(); it != internal_vectors_uint.end(); ++it) { it->second->removeIntegrationPoints(material_local_new_numbering); } for (auto 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(bool converged) { if (not converged) { this->restorePreviousState(); return; } for (const auto & type : element_filter.elementTypes( _all_dimensions, _not_ghost, _ek_not_defined)) { this->updateEnergies(type); } } -/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- + */ void Material::onDamageIteration() { this->savePreviousState(); } -/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- + */ void Material::onDamageUpdate() { for (const auto & type : element_filter.elementTypes( _all_dimensions, _not_ghost, _ek_not_defined)) { this->updateEnergiesAfterDamage(type); } } -/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- + */ void Material::onDump() { if (this->isFiniteDeformation()) { this->computeAllCauchyStresses(_not_ghost); } } -/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- + */ void Material::printself(std::ostream & stream, int indent) const { std::string space(indent, 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, [[gnu::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).empty()) { continue; } for (auto & eigengradu : make_view(this->eigengradu(type, ghost_type), spatial_dimension, spatial_dimension)) { eigengradu = prescribed_eigen_grad_u; } } } -/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- + */ MaterialFactory & Material::getFactory() { return MaterialFactory::getInstance(); } } // namespace akantu diff --git a/src/model/solid_mechanics/material.hh b/src/model/solid_mechanics/material.hh index 7f8155aa4..70e973298 100644 --- a/src/model/solid_mechanics/material.hh +++ b/src/model/solid_mechanics/material.hh @@ -1,720 +1,731 @@ /** * @file material.hh * * @author Fabian Barras * @author Aurelia Isabel Cuba Ramos * @author Lucas Frerot * @author Enrico Milanese * @author Daniel Pino Muñoz * @author Nicolas Richart * @author Marco Vocialta * * @date creation: Fri Jun 18 2010 * @date last modification: Fri Apr 09 2021 * * @brief Mother class for all materials * * * @section LICENSE * * Copyright (©) 2010-2021 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; class Material; } // namespace akantu namespace akantu { using MaterialFactory = Factory; /** * 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(ElementType el_type, * Array & tangent_matrix, * GhostType ghost_type = _not_ghost); * \endcode * */ class Material : public DataAccessor, public Parsable, public MeshEventHandler, protected SolidMechanicsModelEventHandler { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: Material(const Material & mat) = delete; Material & operator=(const Material & mat) = delete; /// 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 ~Material() override; protected: void initialize(); /* ------------------------------------------------------------------------ */ /* Function that materials can/should reimplement */ /* ------------------------------------------------------------------------ */ protected: /// constitutive law virtual void computeStress(ElementType /* el_type */, GhostType /* ghost_type */ = _not_ghost) { AKANTU_TO_IMPLEMENT(); } /// compute the tangent stiffness matrix virtual void computeTangentModuli(ElementType /*el_type*/, Array & /*tangent_matrix*/, GhostType /*ghost_type*/ = _not_ghost) { AKANTU_TO_IMPLEMENT(); } /// compute the potential energy virtual void computePotentialEnergy(ElementType el_type); /// compute the potential energy for an element virtual void computePotentialEnergyByElement(ElementType /*type*/, UInt /*index*/, Vector & /*epot_on_quad_points*/) { AKANTU_TO_IMPLEMENT(); } virtual void updateEnergies(ElementType /*el_type*/) {} virtual void updateEnergiesAfterDamage(ElementType /*el_type*/) {} /// set the material to steady state (to be implemented for materials that /// need it) virtual void setToSteadyState(ElementType /*el_type*/, 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(const Element & /*element*/) const { AKANTU_TO_IMPLEMENT(); } /// compute the s-wave speed in the material virtual Real getShearWaveSpeed(const Element & /*element*/) const { AKANTU_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(InternalField & /*vect*/) { AKANTU_TO_IMPLEMENT(); } template void unregisterInternal(InternalField & /*vect*/) { AKANTU_TO_IMPLEMENT(); } + template + void registerInternal(const std::string & name, UInt nb_component); + + template + void setDefaultValueToInternal(const ID & int_id, const T value); + /// 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(); /// restore the stress from previous_stress if needed virtual void restorePreviousState(); /// 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(ElementType type, UInt element, 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 void printself(std::ostream & stream, int indent = 0) const override; /** * interpolate stress on given positions for each element by means * of a geometrical interpolation on quadrature points */ void interpolateStress(ElementTypeMapArray & result, 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, 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: /* ------------------------------------------------------------------------ */ static inline UInt getTangentStiffnessVoigtSize(UInt dim); /// 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); template void computeAllStressesFromTangentModuli(ElementType type, GhostType ghost_type); template void assembleStiffnessMatrix(ElementType type, GhostType ghost_type); /// assembling in finite deformation template void assembleStiffnessMatrixNL(ElementType type, GhostType ghost_type); template void assembleStiffnessMatrixL2(ElementType type, GhostType ghost_type); /* ------------------------------------------------------------------------ */ /* Conversion functions */ /* ------------------------------------------------------------------------ */ public: /// Size of the Stress matrix for the case of finite deformation see: Bathe et /// al, IJNME, Vol 9, 353-386, 1975 static inline UInt getCauchyStressMatrixSize(UInt dim); /// Sets the stress matrix according to Bathe et al, IJNME, Vol 9, 353-386, /// 1975 template static inline void setCauchyStressMatrix(const Matrix & S_t, Matrix & sigma); /// write the stress tensor in the Voigt notation. template static inline decltype(auto) stressToVoigt(const Matrix & stress) { return VoigtHelper::matrixToVoigt(stress); } /// write the strain tensor in the Voigt notation. template static inline decltype(auto) strainToVoigt(const Matrix & strain) { return VoigtHelper::matrixToVoigtWithFactors(strain); } /// write a voigt vector to stress template static inline void voigtToStress(const Vector & voigt, Matrix & stress) { VoigtHelper::voigtToMatrix(voigt, stress); } /// Computation of Cauchy stress tensor in the case of finite deformation from /// the 2nd Piola-Kirchhoff for a given element type template void StoCauchy(ElementType el_type, GhostType ghost_type = _not_ghost); /// Computation the Cauchy stress the 2nd Piola-Kirchhoff and the deformation /// gradient template inline void StoCauchy(const Matrix & F, const Matrix & S, Matrix & sigma, const Real & C33 = 1.0) const; template static inline void gradUToF(const Matrix & grad_u, Matrix & F); template static inline decltype(auto) gradUToF(const Matrix & grad_u); 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 decltype(auto) gradUToEpsilon(const Matrix & grad_u); template static inline void gradUToE(const Matrix & grad_u, Matrix & epsilon); template static inline decltype(auto) gradUToE(const Matrix & grad_u); 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: inline UInt getNbData(const Array & elements, const SynchronizationTag & tag) const override; inline void packData(CommunicationBuffer & buffer, const Array & elements, const SynchronizationTag & tag) const override; inline void unpackData(CommunicationBuffer & buffer, const Array & elements, const SynchronizationTag & tag) override; 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: /* ------------------------------------------------------------------------ */ void onNodesAdded(const Array & /*unused*/, const NewNodesEvent & /*unused*/) override{}; void onNodesRemoved(const Array & /*unused*/, const Array & /*unused*/, const RemovedNodesEvent & /*unused*/) override{}; void onElementsAdded(const Array & element_list, const NewElementsEvent & event) override; void onElementsRemoved(const Array & element_list, const ElementTypeMapArray & new_numbering, const RemovedElementsEvent & event) override; void onElementsChanged(const Array & /*unused*/, const Array & /*unused*/, const ElementTypeMapArray & /*unused*/, const ChangedElementsEvent & /*unused*/) override{}; /* ------------------------------------------------------------------------ */ /* SolidMechanicsModelEventHandler inherited members */ /* ------------------------------------------------------------------------ */ public: virtual void beforeSolveStep(); virtual void afterSolveStep(bool converged = true); void onDamageIteration() override; void onDamageUpdate() override; void onDump() override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: AKANTU_GET_MACRO(Name, name, const std::string &); AKANTU_SET_MACRO(Name, name, const std::string &); AKANTU_GET_MACRO(Model, model, const SolidMechanicsModel &) AKANTU_GET_MACRO(ID, id, 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(const std::string & type); /// return the energy (identified by id) for the provided element virtual Real getEnergy(const 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, ElementType type, GhostType ghost_type = _not_ghost) const; template Array & getArray(const ID & id, ElementType type, 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, ElementKind element_kind) const; template ElementTypeMap getInternalDataPerElem(const ID & id, 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, GhostType ghost_type = _not_ghost, ElementKind element_kind = _ek_not_defined) const; template void inflateInternal(const std::string & field_id, const ElementTypeMapArray & field, GhostType ghost_type = _not_ghost, ElementKind element_kind = _ek_not_defined); /// apply a constant eigengrad_u everywhere in the material virtual void applyEigenGradU(const Matrix & prescribed_eigen_grad_u, GhostType /*ghost_type*/ = _not_ghost); bool hasMatrixChanged(const ID & id) { if (id == "K") { return hasStiffnessMatrixChanged() or finite_deformation; } return true; } MatrixType getMatrixType(const ID & id) { if (id == "K") { return getTangentType(); } if (id == "M") { return _symmetric; } return _mt_not_defined; } /// specify if the matrix need to be recomputed for this material virtual bool hasStiffnessMatrixChanged() { return true; } /// specify the type of matrix, if not overloaded the material is not valid /// for static or implicit computations virtual MatrixType getTangentType() { return _mt_not_defined; } /// static method to reteive the material factory static MaterialFactory & getFactory(); protected: bool isInit() const { return is_init; } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// boolean to know if the material has been initialized bool is_init{false}; std::map *> internal_vectors_real; std::map *> internal_vectors_uint; std::map *> internal_vectors_bool; protected: + /// std map to store pointers to the user-defined internals (have problem with + /// keeping pointers alive when registering them in internal_fields of + /// Material) + std::map> internals; + ID id; /// Link to the fem object in the model FEEngine & fem; /// Finite deformation bool finite_deformation{false}; /// Finite deformation bool inelastic_deformation{false}; /// material name std::string name; /// The model to witch the material belong SolidMechanicsModel & model; /// density : rho Real rho{0.}; /// 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{false}; /// tell if the material need the previous stress state bool use_previous_stress{false}; /// tell if the material need the previous strain state bool use_previous_gradu{false}; /// 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; private: /// eigen_grad_u for the parser Matrix eigen_grad_u; }; /// 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.hh" #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) \ auto && grad_u_view = \ make_view(this->gradu(el_type, ghost_type), this->spatial_dimension, \ this->spatial_dimension); \ \ auto stress_view = \ make_view(this->stress(el_type, ghost_type), this->spatial_dimension, \ this->spatial_dimension); \ \ if (this->isFiniteDeformation()) { \ stress_view = make_view(this->piola_kirchhoff_2(el_type, ghost_type), \ this->spatial_dimension, this->spatial_dimension); \ } \ \ for (auto && data : zip(grad_u_view, stress_view)) { \ [[gnu::unused]] Matrix & grad_u = std::get<0>(data); \ [[gnu::unused]] Matrix & sigma = std::get<1>(data) #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) \ auto && grad_u_view = \ make_view(this->gradu(el_type, ghost_type), this->spatial_dimension, \ this->spatial_dimension); \ \ auto && stress_view = \ make_view(this->stress(el_type, ghost_type), this->spatial_dimension, \ this->spatial_dimension); \ \ auto tangent_size = \ this->getTangentStiffnessVoigtSize(this->spatial_dimension); \ \ auto && tangent_view = make_view(tangent_mat, tangent_size, tangent_size); \ \ for (auto && data : zip(grad_u_view, stress_view, tangent_view)) { \ [[gnu::unused]] Matrix & grad_u = std::get<0>(data); \ [[gnu::unused]] Matrix & sigma = std::get<1>(data); \ Matrix & tangent = std::get<2>(data); #define MATERIAL_TANGENT_QUADRATURE_POINT_LOOP_END } /* -------------------------------------------------------------------------- */ #define INSTANTIATE_MATERIAL_ONLY(mat_name) \ template class mat_name<1>; /* NOLINT */ \ template class mat_name<2>; /* NOLINT */ \ template class mat_name<3> /* NOLINT */ #define MATERIAL_DEFAULT_PER_DIM_ALLOCATOR(id, mat_name) \ [](UInt dim, const ID &, SolidMechanicsModel & model, \ const ID & id) /* NOLINT */ \ -> std::unique_ptr< \ Material> { /* NOLINT */ \ switch (dim) { \ case 1: \ return std::make_unique>(/* NOLINT */ \ model, id); \ case 2: \ return std::make_unique>(/* NOLINT */ \ model, id); \ case 3: \ return std::make_unique>(/* NOLINT */ \ 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/solid_mechanics_model_cohesive/materials/material_cohesive.cc b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc index e96efb926..1db0603cd 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.cc @@ -1,559 +1,579 @@ /** * @file material_cohesive.cc * * @author Mauro Corrado * @author Nicolas Richart * @author Seyedeh Mohadeseh Taheri Mousavi * @author Marco Vocialta * * @date creation: Wed Feb 22 2012 * @date last modification: Thu Jan 14 2021 * * @brief Specialization of the material class for cohesive elements * * * @section LICENSE * * Copyright (©) 2010-2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) * Laboratory (LSMS - Laboratoire de Simulation en Mécanique des Solides) * * Akantu is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * Akantu is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with Akantu. If not, see . * */ /* -------------------------------------------------------------------------- */ #include "material_cohesive.hh" #include "aka_random_generator.hh" #include "dof_synchronizer.hh" #include "fe_engine_template.hh" #include "integrator_gauss.hh" #include "shape_cohesive.hh" #include "solid_mechanics_model_cohesive.hh" #include "sparse_matrix.hh" /* -------------------------------------------------------------------------- */ namespace akantu { /* -------------------------------------------------------------------------- */ MaterialCohesive::MaterialCohesive(SolidMechanicsModel & model, const ID & id) : Material(model, id), facet_filter("facet_filter", id), fem_cohesive( model.getFEEngineClass("CohesiveFEEngine")), reversible_energy("reversible_energy", *this), total_energy("total_energy", *this), opening("opening", *this), tractions("tractions", *this), contact_tractions("contact_tractions", *this), - contact_opening("contact_opening", *this), delta_max("delta max", *this), + contact_opening("contact_opening", *this), delta_max("delta_max", *this), use_previous_delta_max(false), use_previous_opening(false), damage("damage", *this), sigma_c("sigma_c", *this), normal(0, spatial_dimension, "normal") { AKANTU_DEBUG_IN(); this->model = dynamic_cast(&model); this->registerParam("sigma_c", sigma_c, _pat_parsable | _pat_readable, "Critical stress"); this->registerParam("delta_c", delta_c, Real(0.), _pat_parsable | _pat_readable, "Critical displacement"); this->element_filter.initialize(this->model->getMesh(), _spatial_dimension = spatial_dimension, _element_kind = _ek_cohesive); // this->model->getMesh().initElementTypeMapArray( // this->element_filter, 1, spatial_dimension, false, _ek_cohesive); if (this->model->getIsExtrinsic()) { this->facet_filter.initialize(this->model->getMeshFacets(), _spatial_dimension = spatial_dimension - 1, _element_kind = _ek_regular); } // this->model->getMeshFacets().initElementTypeMapArray(facet_filter, 1, // spatial_dimension - // 1); this->reversible_energy.initialize(1); this->total_energy.initialize(1); this->tractions.initialize(spatial_dimension); this->tractions.initializeHistory(); this->contact_tractions.initialize(spatial_dimension); this->contact_opening.initialize(spatial_dimension); this->opening.initialize(spatial_dimension); this->opening.initializeHistory(); this->delta_max.initialize(1); this->damage.initialize(1); if (this->model->getIsExtrinsic()) { this->sigma_c.initialize(1); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ MaterialCohesive::~MaterialCohesive() = default; /* -------------------------------------------------------------------------- */ void MaterialCohesive::initMaterial() { AKANTU_DEBUG_IN(); Material::initMaterial(); if (this->use_previous_delta_max) { this->delta_max.initializeHistory(); } if (this->use_previous_opening) { this->opening.initializeHistory(); } AKANTU_DEBUG_OUT(); } - +/* -------------------------------------------------------------------------- */ +/// registering cohesive internal field +template +void registerCohesiveInternal(const std::string & name, UInt nb_component) { + AKANTU_TO_IMPLEMENT(); +}; + +template <> +void MaterialCohesive::registerCohesiveInternal(const std::string & name, + UInt nb_component) { + auto && internal = std::make_shared>(name, *this); + internal->initialize(nb_component); + this->internals[name] = internal; +} +template <> +void MaterialCohesive::registerCohesiveInternal(const std::string & name, + UInt nb_component) { + auto && internal = std::make_shared>(name, *this); + internal->initialize(nb_component); + this->internals[name] = internal; +} /* -------------------------------------------------------------------------- */ void MaterialCohesive::assembleInternalForces(GhostType ghost_type) { AKANTU_DEBUG_IN(); auto & internal_force = const_cast &>(model->getInternalForce()); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type, _ek_cohesive)) { auto & elem_filter = element_filter(type, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element == 0) { continue; } const auto & shapes = fem_cohesive.getShapes(type, ghost_type); auto & traction = tractions(type, ghost_type); auto & contact_traction = contact_tractions(type, ghost_type); UInt size_of_shapes = shapes.getNbComponent(); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); UInt nb_quadrature_points = fem_cohesive.getNbIntegrationPoints(type, ghost_type); /// compute @f$t_i N_a@f$ auto * traction_cpy = new Array(nb_element * nb_quadrature_points, spatial_dimension * size_of_shapes); auto traction_it = traction.begin(spatial_dimension, 1); auto contact_traction_it = contact_traction.begin(spatial_dimension, 1); auto shapes_filtered_begin = shapes.begin(1, size_of_shapes); auto traction_cpy_it = traction_cpy->begin(spatial_dimension, size_of_shapes); Matrix traction_tmp(spatial_dimension, 1); for (UInt el = 0; el < nb_element; ++el) { UInt current_quad = elem_filter(el) * nb_quadrature_points; for (UInt q = 0; q < nb_quadrature_points; ++q, ++traction_it, ++contact_traction_it, ++current_quad, ++traction_cpy_it) { const Matrix & shapes_filtered = shapes_filtered_begin[current_quad]; traction_tmp.copy(*traction_it); traction_tmp += *contact_traction_it; traction_cpy_it->mul(traction_tmp, shapes_filtered); } } /** * compute @f$\int t \cdot N\, dS@f$ by @f$ \sum_q \mathbf{N}^t * \mathbf{t}_q \overline w_q J_q@f$ */ auto * partial_int_t_N = new Array( nb_element, spatial_dimension * size_of_shapes, "int_t_N"); fem_cohesive.integrate(*traction_cpy, *partial_int_t_N, spatial_dimension * size_of_shapes, type, ghost_type, elem_filter); delete traction_cpy; auto * int_t_N = new Array( nb_element, 2 * spatial_dimension * size_of_shapes, "int_t_N"); Real * int_t_N_val = int_t_N->storage(); Real * partial_int_t_N_val = partial_int_t_N->storage(); for (UInt el = 0; el < nb_element; ++el) { std::copy_n(partial_int_t_N_val, size_of_shapes * spatial_dimension, int_t_N_val); std::copy_n(partial_int_t_N_val, size_of_shapes * spatial_dimension, int_t_N_val + size_of_shapes * spatial_dimension); for (UInt n = 0; n < size_of_shapes * spatial_dimension; ++n) { int_t_N_val[n] *= -1.; } int_t_N_val += nb_nodes_per_element * spatial_dimension; partial_int_t_N_val += size_of_shapes * spatial_dimension; } delete partial_int_t_N; /// assemble model->getDOFManager().assembleElementalArrayLocalArray( *int_t_N, internal_force, type, ghost_type, 1, elem_filter); delete int_t_N; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::assembleStiffnessMatrix(GhostType ghost_type) { AKANTU_DEBUG_IN(); for (auto type : element_filter.elementTypes(spatial_dimension, ghost_type, _ek_cohesive)) { UInt nb_quadrature_points = fem_cohesive.getNbIntegrationPoints(type, ghost_type); UInt nb_nodes_per_element = Mesh::getNbNodesPerElement(type); const Array & shapes = fem_cohesive.getShapes(type, ghost_type); Array & elem_filter = element_filter(type, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element == 0U) { continue; } UInt size_of_shapes = shapes.getNbComponent(); auto * shapes_filtered = new Array(nb_element * nb_quadrature_points, size_of_shapes, "filtered shapes"); Real * shapes_filtered_val = shapes_filtered->storage(); UInt * elem_filter_val = elem_filter.storage(); for (UInt el = 0; el < nb_element; ++el) { auto * shapes_val = shapes.storage() + elem_filter_val[el] * size_of_shapes * nb_quadrature_points; memcpy(shapes_filtered_val, shapes_val, size_of_shapes * nb_quadrature_points * sizeof(Real)); shapes_filtered_val += size_of_shapes * nb_quadrature_points; } Matrix A(spatial_dimension * size_of_shapes, spatial_dimension * nb_nodes_per_element); for (UInt i = 0; i < spatial_dimension * size_of_shapes; ++i) { A(i, i) = 1; A(i, i + spatial_dimension * size_of_shapes) = -1; } /// get the tangent matrix @f$\frac{\partial{(t/\delta)}}{\partial{\delta}} /// @f$ auto * tangent_stiffness_matrix = new Array( nb_element * nb_quadrature_points, spatial_dimension * spatial_dimension, "tangent_stiffness_matrix"); // Array * normal = new Array(nb_element * // nb_quadrature_points, spatial_dimension, "normal"); normal.resize(nb_quadrature_points); computeNormal(model->getCurrentPosition(), normal, type, ghost_type); /// compute openings @f$\mathbf{\delta}@f$ // computeOpening(model->getDisplacement(), opening(type, ghost_type), type, // ghost_type); tangent_stiffness_matrix->zero(); computeTangentTraction(type, *tangent_stiffness_matrix, normal, ghost_type); // delete normal; UInt size_at_nt_d_n_a = spatial_dimension * nb_nodes_per_element * spatial_dimension * nb_nodes_per_element; auto * at_nt_d_n_a = new Array(nb_element * nb_quadrature_points, size_at_nt_d_n_a, "A^t*N^t*D*N*A"); Array::iterator> shapes_filt_it = shapes_filtered->begin(size_of_shapes); Array::matrix_iterator D_it = tangent_stiffness_matrix->begin(spatial_dimension, spatial_dimension); Array::matrix_iterator At_Nt_D_N_A_it = at_nt_d_n_a->begin(spatial_dimension * nb_nodes_per_element, spatial_dimension * nb_nodes_per_element); Array::matrix_iterator At_Nt_D_N_A_end = at_nt_d_n_a->end(spatial_dimension * nb_nodes_per_element, spatial_dimension * nb_nodes_per_element); Matrix N(spatial_dimension, spatial_dimension * size_of_shapes); Matrix N_A(spatial_dimension, spatial_dimension * nb_nodes_per_element); Matrix D_N_A(spatial_dimension, spatial_dimension * nb_nodes_per_element); for (; At_Nt_D_N_A_it != At_Nt_D_N_A_end; ++At_Nt_D_N_A_it, ++D_it, ++shapes_filt_it) { N.zero(); /** * store the shapes in voigt notations matrix @f$\mathbf{N} = * \begin{array}{cccccc} N_0(\xi) & 0 & N_1(\xi) &0 & N_2(\xi) & 0 \\ * 0 & * N_0(\xi)& 0 &N_1(\xi)& 0 & N_2(\xi) \end{array} @f$ **/ for (UInt i = 0; i < spatial_dimension; ++i) { for (UInt n = 0; n < size_of_shapes; ++n) { N(i, i + spatial_dimension * n) = (*shapes_filt_it)(n); } } /** * compute stiffness matrix @f$ \mathbf{K} = \delta \mathbf{U}^T * \int_{\Gamma_c} {\mathbf{P}^t \frac{\partial{\mathbf{t}}} *{\partial{\delta}} * \mathbf{P} d\Gamma \Delta \mathbf{U}} @f$ **/ N_A.mul(N, A); D_N_A.mul(*D_it, N_A); (*At_Nt_D_N_A_it).mul(D_N_A, N_A); } delete tangent_stiffness_matrix; delete shapes_filtered; auto * K_e = new Array(nb_element, size_at_nt_d_n_a, "K_e"); fem_cohesive.integrate(*at_nt_d_n_a, *K_e, size_at_nt_d_n_a, type, ghost_type, elem_filter); delete at_nt_d_n_a; model->getDOFManager().assembleElementalMatricesToMatrix( "K", "displacement", *K_e, type, ghost_type, _unsymmetric, elem_filter); delete K_e; } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- * * Compute traction from displacements * * @param[in] ghost_type compute the residual for _ghost or _not_ghost element */ void MaterialCohesive::computeTraction(GhostType ghost_type) { AKANTU_DEBUG_IN(); for (const auto & type : element_filter.elementTypes( spatial_dimension, ghost_type, _ek_cohesive)) { Array & elem_filter = element_filter(type, ghost_type); UInt nb_element = elem_filter.size(); if (nb_element == 0) { continue; } UInt nb_quadrature_points = nb_element * fem_cohesive.getNbIntegrationPoints(type, ghost_type); normal.resize(nb_quadrature_points); /// compute normals @f$\mathbf{n}@f$ computeNormal(model->getCurrentPosition(), normal, type, ghost_type); /// compute openings @f$\mathbf{\delta}@f$ computeOpening(model->getDisplacement(), opening(type, ghost_type), type, ghost_type); /// compute traction @f$\mathbf{t}@f$ computeTraction(normal, type, ghost_type); } AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::computeNormal(const Array & position, Array & normal, ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); auto & fem_cohesive = this->model->getFEEngineClass("CohesiveFEEngine"); normal.zero(); #define COMPUTE_NORMAL(type) \ fem_cohesive.getShapeFunctions() \ .computeNormalsOnIntegrationPoints( \ position, normal, ghost_type, element_filter(type, ghost_type)); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(COMPUTE_NORMAL); #undef COMPUTE_NORMAL AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::computeOpening(const Array & displacement, Array & opening, ElementType type, GhostType ghost_type) { AKANTU_DEBUG_IN(); auto & fem_cohesive = this->model->getFEEngineClass("CohesiveFEEngine"); #define COMPUTE_OPENING(type) \ fem_cohesive.getShapeFunctions() \ .interpolateOnIntegrationPoints( \ displacement, opening, spatial_dimension, ghost_type, \ element_filter(type, ghost_type)); AKANTU_BOOST_COHESIVE_ELEMENT_SWITCH(COMPUTE_OPENING); #undef COMPUTE_OPENING AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ void MaterialCohesive::updateEnergies(ElementType type) { AKANTU_DEBUG_IN(); if (Mesh::getKind(type) != _ek_cohesive) { return; } Vector b(spatial_dimension); Vector h(spatial_dimension); auto erev = reversible_energy(type).begin(); auto etot = total_energy(type).begin(); auto traction_it = tractions(type).begin(spatial_dimension); auto traction_old_it = tractions.previous(type).begin(spatial_dimension); auto opening_it = opening(type).begin(spatial_dimension); auto opening_old_it = opening.previous(type).begin(spatial_dimension); auto traction_end = tractions(type).end(spatial_dimension); /// loop on each quadrature point for (; traction_it != traction_end; ++traction_it, ++traction_old_it, ++opening_it, ++opening_old_it, ++erev, ++etot) { /// trapezoidal integration b = *opening_it; b -= *opening_old_it; h = *traction_old_it; h += *traction_it; *etot += .5 * b.dot(h); *erev = .5 * traction_it->dot(*opening_it); } /// update old values AKANTU_DEBUG_OUT(); } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getReversibleEnergy() { AKANTU_DEBUG_IN(); Real erev = 0.; /// integrate reversible energy for each type of elements for (const auto & type : element_filter.elementTypes( spatial_dimension, _not_ghost, _ek_cohesive)) { erev += fem_cohesive.integrate(reversible_energy(type, _not_ghost), type, _not_ghost, element_filter(type, _not_ghost)); } AKANTU_DEBUG_OUT(); return erev; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getDissipatedEnergy() { AKANTU_DEBUG_IN(); Real edis = 0.; /// integrate dissipated energy for each type of elements for (const auto & type : element_filter.elementTypes( spatial_dimension, _not_ghost, _ek_cohesive)) { Array dissipated_energy(total_energy(type, _not_ghost)); dissipated_energy -= reversible_energy(type, _not_ghost); edis += fem_cohesive.integrate(dissipated_energy, type, _not_ghost, element_filter(type, _not_ghost)); } AKANTU_DEBUG_OUT(); return edis; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getContactEnergy() { AKANTU_DEBUG_IN(); Real econ = 0.; /// integrate contact energy for each type of elements for (const auto & type : element_filter.elementTypes( spatial_dimension, _not_ghost, _ek_cohesive)) { auto & el_filter = element_filter(type, _not_ghost); UInt nb_quad_per_el = fem_cohesive.getNbIntegrationPoints(type, _not_ghost); UInt nb_quad_points = el_filter.size() * nb_quad_per_el; Array contact_energy(nb_quad_points); auto contact_traction_it = contact_tractions(type, _not_ghost).begin(spatial_dimension); auto contact_opening_it = contact_opening(type, _not_ghost).begin(spatial_dimension); /// loop on each quadrature point for (UInt q = 0; q < nb_quad_points; ++contact_traction_it, ++contact_opening_it, ++q) { contact_energy(q) = .5 * contact_traction_it->dot(*contact_opening_it); } econ += fem_cohesive.integrate(contact_energy, type, _not_ghost, el_filter); } AKANTU_DEBUG_OUT(); return econ; } /* -------------------------------------------------------------------------- */ Real MaterialCohesive::getEnergy(const std::string & type) { if (type == "reversible") { return getReversibleEnergy(); } if (type == "dissipated") { return getDissipatedEnergy(); } if (type == "cohesive contact") { return getContactEnergy(); } return 0.; } /* -------------------------------------------------------------------------- */ } // namespace akantu diff --git a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh index c3155d2d4..f190016c9 100644 --- a/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh +++ b/src/model/solid_mechanics/solid_mechanics_model_cohesive/materials/material_cohesive.hh @@ -1,236 +1,241 @@ /** * @file material_cohesive.hh * * @author Nicolas Richart * @author Seyedeh Mohadeseh Taheri Mousavi * @author Marco Vocialta * * @date creation: Fri Jun 18 2010 * @date last modification: Thu Jan 14 2021 * * @brief Specialization of the material class for cohesive elements * * * @section LICENSE * * Copyright (©) 2010-2021 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 "cohesive_internal_field.hh" /* -------------------------------------------------------------------------- */ #ifndef AKANTU_MATERIAL_COHESIVE_HH_ #define AKANTU_MATERIAL_COHESIVE_HH_ /* -------------------------------------------------------------------------- */ namespace akantu { class SolidMechanicsModelCohesive; } namespace akantu { class MaterialCohesive : public Material { /* ------------------------------------------------------------------------ */ /* Constructors/Destructors */ /* ------------------------------------------------------------------------ */ public: using MyFEEngineCohesiveType = FEEngineTemplate; public: MaterialCohesive(SolidMechanicsModel & model, const ID & id = ""); ~MaterialCohesive() override; /* ------------------------------------------------------------------------ */ /* Methods */ /* ------------------------------------------------------------------------ */ public: /// initialize the material computed parameter void initMaterial() override; /// compute tractions (including normals and openings) void computeTraction(GhostType ghost_type = _not_ghost); /// assemble residual void assembleInternalForces(GhostType ghost_type = _not_ghost) override; /// check stress for cohesive elements' insertion, by default it /// also updates the cohesive elements' data virtual void checkInsertion(bool /*check_only*/ = false) { AKANTU_TO_IMPLEMENT(); } /// interpolate stress on given positions for each element (empty /// implemantation to avoid the generic call to be done on cohesive elements) virtual void interpolateStress(const ElementType /*type*/, Array & /*result*/) {} /// compute the stresses void computeAllStresses(GhostType /*ghost_type*/ = _not_ghost) final{}; // add the facet to be handled by the material UInt addFacet(const Element & element); + /// registering cohesive internal field + template + void registerCohesiveInternal(const std::string & name, UInt nb_component); + protected: virtual void computeTangentTraction(ElementType /*el_type*/, Array & /*tangent_matrix*/, const Array & /*normal*/, GhostType /*ghost_type*/ = _not_ghost) { AKANTU_TO_IMPLEMENT(); } /// compute the normal void computeNormal(const Array & position, Array & normal, ElementType type, GhostType ghost_type); /// compute the opening void computeOpening(const Array & displacement, Array & opening, ElementType type, GhostType ghost_type); template void computeNormal(const Array & position, Array & normal, GhostType ghost_type); /// assemble stiffness void assembleStiffnessMatrix(GhostType ghost_type) override; /// constitutive law virtual void computeTraction(const Array & normal, ElementType el_type, GhostType ghost_type = _not_ghost) = 0; /// parallelism functions inline UInt getNbData(const Array & elements, const SynchronizationTag & tag) const override; inline void packData(CommunicationBuffer & buffer, const Array & elements, const SynchronizationTag & tag) const override; inline void unpackData(CommunicationBuffer & buffer, const Array & elements, const SynchronizationTag & tag) override; protected: void updateEnergies(ElementType el_type) override; /* ------------------------------------------------------------------------ */ /* Accessors */ /* ------------------------------------------------------------------------ */ public: /// get the opening AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Opening, opening, Real); /// get the traction AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Traction, tractions, Real); /// get damage AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(Damage, damage, Real); /// get facet filter AKANTU_GET_MACRO_BY_ELEMENT_TYPE_CONST(FacetFilter, facet_filter, UInt); AKANTU_GET_MACRO_BY_ELEMENT_TYPE(FacetFilter, facet_filter, UInt); AKANTU_GET_MACRO(FacetFilter, facet_filter, const ElementTypeMapArray &); + AKANTU_GET_MACRO(NormalsAtQuads, normal, const Array &); // AKANTU_GET_MACRO(ElementFilter, element_filter, const // ElementTypeMapArray &); /// compute reversible energy Real getReversibleEnergy(); /// compute dissipated energy Real getDissipatedEnergy(); /// compute contact energy Real getContactEnergy(); /// get energy Real getEnergy(const std::string & type) override; /// return the energy (identified by id) for the provided element Real getEnergy(const std::string & energy_id, ElementType type, UInt index) override { return Material::getEnergy(energy_id, type, index); } /* ------------------------------------------------------------------------ */ /* Class Members */ /* ------------------------------------------------------------------------ */ protected: /// list of facets assigned to this material ElementTypeMapArray facet_filter; /// Link to the cohesive fem object in the model FEEngine & fem_cohesive; private: /// reversible energy by quadrature point CohesiveInternalField reversible_energy; /// total energy by quadrature point CohesiveInternalField total_energy; protected: /// opening in all elements and quadrature points CohesiveInternalField opening; /// traction in all elements and quadrature points CohesiveInternalField tractions; /// traction due to contact CohesiveInternalField contact_tractions; /// normal openings for contact tractions CohesiveInternalField contact_opening; /// maximum displacement CohesiveInternalField delta_max; /// tell if the previous delta_max state is needed (in iterative schemes) bool use_previous_delta_max; /// tell if the previous opening state is needed (in iterative schemes) bool use_previous_opening; /// damage CohesiveInternalField damage; /// pointer to the solid mechanics model for cohesive elements SolidMechanicsModelCohesive * model; /// critical stress RandomInternalField sigma_c; /// critical displacement Real delta_c; /// array to temporarily store the normals Array normal; }; } // namespace akantu /* -------------------------------------------------------------------------- */ /* inline functions */ /* -------------------------------------------------------------------------- */ #include "cohesive_internal_field_tmpl.hh" #include "material_cohesive_inline_impl.hh" #endif /* AKANTU_MATERIAL_COHESIVE_HH_ */